this post was submitted on 02 Aug 2026
10 points (91.7% liked)

Selfhosted

61333 readers
479 users here now

A place to share alternatives to popular online services that can be self-hosted without giving up privacy or locking you into a service you don't control.

Rules:

Detailed Rules Post

  1. Be civil.

  2. No spam.

  3. Posts are to be related to self-hosting.

  4. Don't duplicate the full text of your blog or readme if you're providing a link.

  5. Submission headline should match the article title.

  6. No trolling.

  7. Promotion posts require active participation, with an account that is at least 30 days old. F/LOSS without a paywall has exceptions, with requirements. See the rules link for details. Tags [CBH] or [AIP] are required, see the links in Rule 8 for details.

  8. AI-related discussions and AI-involved promotional posts have additional requirements for tagging, as noted in Rule 7 and the AI & Promotional Post Expanded Rules post, and find example disclosures here.

Resources:

Any issues on the community? Report it using the report flag.

Questions? DM the mods!

founded 3 years ago
MODERATORS
 

Consider the following setup:

An NFS server exports the directory /srv/nfsv4 to one client. It is exported with the option "fsid=0" for use with NFSv4.

/srv/nfsv4              192.168.0.10/24(ro,sync,secure,root_squash,subtree_check,fsid=0)

The bind-mounted directory within it, foo, is exported as well. Client 192.168.0.10 can successfully mount and write to it.

/srv/nfsv4/foo          192.168.0.10/24(rw,sync,secure,root_squash,subtree_check)

"foo" has multiple subdirectories. While client 192.168.0.10 should have full read-write access to all of them, another client, 192.168.0.20, should only see a specific subset of these directories. Everything else should not only be read-only, but not mountable at all.

At first, I did it like this:

/srv/nfsv4              192.168.0.10/24(ro,sync,secure,root_squash,subtree_check,fsid=0) \
                        192.168.0.20/24(ro,sync,secure,root_squash,subtree_check,fsid=0)

/srv/nfsv4/foo          192.168.0.10/24(rw,sync,secure,root_squash,subtree_check) \
                        192.168.0.20/24(ro,sync,secure,root_squash,subtree_check)

/srv/nfsv4/foo/dir1     192.168.0.20/24(rw,sync,secure,root_squash,subtree_check)

/srv/nfsv4/foo/dir2     192.168.0.20/24(rw,sync,secure,root_squash,subtree_check)

With the effect that client 192.168.0.20 could still mount all other subdirectories of foo (even though read-only).

So, in an attempt to achieve the desired behavior, I created a second parent directory /srv/nfsv4/bar/ that has only the intended set of subdirectories bind-mounted to it:

srv/
└── nfsv4/
    ├── foo/
    │   ├── dir1
    │   ├── dir2
    │   ├── dir3
    │   └── dir4
    └── bar/
        ├── dir1
        └── dir2

And changed /etc/exports to look like this:

/srv/nfsv4              192.168.0.10/24(ro,sync,secure,root_squash,subtree_check,fsid=0) \
                        192.168.0.20/24(ro,sync,secure,root_squash,subtree_check,fsid=0)

/srv/nfsv4/foo          192.168.0.10/24(rw,sync,secure,root_squash,subtree_check)

/srv/nfsv4/bar          192.168.0.20/24(rw,sync,secure,root_squash,subtree_check)

Now, when I mount nfs-server:/bar on client 192.168.0.20, everything seems as expected. Except that I could still mount nfs-server:/ (the exported root) and have read access to foo. My understanding was that, unless I explicitly exported foo to 192.168.0.20, it should not be visible to it.

What did I do wrong?

top 9 comments
sorted by: hot top controversial new old
[–] CallMeAl@piefed.world 2 points 1 week ago* (last edited 1 week ago) (1 children)

When you add /24 you are exporting to the entire subnet. A single host export looks like this

/srv/nfsv4 192.168.0.10(ro,sync,secure,root_squash,subtree_check,fsid=0)

Just leave off the subnet mask.

[–] joulethief@discuss.tchncs.de 1 points 1 week ago* (last edited 1 week ago) (1 children)

Thank you. I'm closer to what I want now. Can you help me explain this behavior though:

For testing purposes, I commented out every line in /etc/exports but these:

/srv/nfsv4              192.168.0.10(ro,sync,secure,root_squash,subtree_check,fsid=0) \
                        192.168.0.20(ro,sync,secure,root_squash,subtree_check,fsid=0)

Client 192.168.0.20 can mount nfs-server:/ and listing the contents gives both directories foo and bar. It cannot see the contents of foo, as intended, but it can see what's inside bar (EDIT: it can see down one level, so the subdirectories of bar, but nothing further down). I cannot figure out why? I rebooted the machine in hopes it was just a caching thing, to no avail.

Apart from that, I was hoping 192.168.0.20 could not even mount foo, but as long as its contents are hidden, I can live with that for now.

[–] joulethief@discuss.tchncs.de 1 points 1 week ago* (last edited 1 week ago)

Even with bar exported to this client, it cannot see its subdirectories' contents. What the hell is going on? Just to be clear, I did run exportfs -arv after every change to /etc/exports.

[–] gooeyglob@lemmy.world 1 points 1 week ago* (last edited 1 week ago) (1 children)

The problem looks to be your subnet specification. /24 is 256 addresses. So for your 192.168.0.10/24 export, you're exposing it to 0.10 and the following 255 IPs.

The closest thing to what you want to achieve would be a /29, which would expose it to the given IP and the following 7 IPs.

[–] joulethief@discuss.tchncs.de 2 points 1 week ago (2 children)

That can't be right. For exposing it to a whole subnet, it would have to be 192.168.0.0/24, wouldn't it?

[–] curbstickle@anarchist.nexus 2 points 1 week ago* (last edited 1 week ago)

Edit: Completely misread things, I thought you had 192.168.10.0 and 192.168.20.0. Yes it would be the whole subnet for a /24, if you wanted less you'd go higher as mentioned.

192.168.0.0/29 would include 192.168.0.1-192.168.0.7.

/28 would get you up to 192.168.0.15.


No, /24 is just 256 IPs.

192.168.0.0/24 = 192.168.0.0 mask 255.255.255.0, or 192.168.0.1-192.168.0.254.

If you want 192.168.0.0 through, say, 192.168.7.254, you need to cover 2k ip's, which is a /21. The mask would be 255.255.248.0.

A /24 would only be the last octet.

[–] gooeyglob@lemmy.world 1 points 1 week ago* (last edited 1 week ago)

No, if you mean 192.168.0.0 - 192.168.255.255, that is a /16 192.168.0.0 - 192.168.0.255 is a /24 192.168.0.0 - 192.168.0.7 is a /29

I was a little glib in my initial response. You really don't want to start your definition in the middle of a subnet.

I would set it up so your first group of /29 would be 192.168.0.0 - 192.168.0.7

Second would be 192.168.0.8 - 192.168.0.15 (192.168.0.8/29)

Third would be 192.168.0.16 - 192.168.0.23 (192.168.0.16/29)

And so on.

[–] mhzawadi@lemmy.horwood.cloud 1 points 1 week ago (1 children)

Not read all the below posts, but yes a /25 is the 192.168.0.0 subnet.

A single IP is /32 so 192.168.0.10/32 would only allow that IP access.

Change the root exports to /32 from /24 and then only 192.168.0.10 can access everything

[–] joulethief@discuss.tchncs.de 1 points 1 week ago

Thanks, I misunderstood the usage of /24. I thought in order to export to a whole subnet, I had to put the subnet address 192.168.0.0/24 while 192.168.0.20/24 would imply a single client within that subnet. I removed the prefix length entirely as CallMeAl suggested, so that's sorted out.

There's another issue remaining, see my reply to Al's comment if you'd like.