A home server is one of the few projects where the interesting parts are not the software. Installing a media server takes ten minutes. Laying out the storage so it can grow, and getting permissions right so two people and three devices can all write to the same directory, is the actual work — and it is where almost every home setup goes wrong.
An afternoon, on any machine with a spare disk.
What this guide does not do. Everything here stays on your own network. Nothing is exposed to the internet, because a file server full of family photos is the last thing that should be — if you want access from outside, put a VPN in front rather than forwarding a port. It also does not make your data safe: mirrored disks protect against a disk dying and nothing else. Backups are step 7, and they are not optional.
1. Separate the system from the data
The operating system goes on its own disk — ideally a small SSD — and your data goes on separate disks that are never touched by a reinstall. This one decision is what makes the machine disposable: when something goes badly wrong, you reinstall in twenty minutes and remount the data.
lsblk -f # what you have, and what is on it
sudo mkfs.ext4 -L data /dev/sdb1 # a label makes fstab readable
sudo blkid /dev/sdb1 # the UUID, which is what fstab should use
sudo mkdir -p /srv/data# /etc/fstab
UUID=<the-uuid> /srv/data ext4 defaults,nofail 0 2nofail matters more here than on a normal machine: a home server that will not boot because a disk was not detected is a home server nobody can fix remotely. See Disks and Mounting for the rest of the fstab fields, and never reference a disk as /dev/sdb1 — that name can change between boots.
On filesystem choice: ext4 is the boring correct answer. Choose btrfs or ZFS if you specifically want snapshots and checksums that detect silent corruption — both genuinely valuable for a photo archive — and read Filesystems first, because both ask more of you.
Verify: reboot. findmnt /srv/data shows it mounted, with no intervention.
2. Get the permissions right, once
This is the step people skip and then fight for months. The problem: two people write files to a shared directory, each file is owned by whoever created it with default permissions, and eventually one of them cannot modify the other’s files. The fix is a shared group plus the setgid bit on the directories.
sudo groupadd -r media
sudo usermod -aG media alice # note -aG, never -G
sudo usermod -aG media bob
sudo mkdir -p /srv/data/{photos,music,video,documents}
sudo chown -R root:media /srv/data
sudo chmod -R 2775 /srv/data # the leading 2 is setgidSetgid on a directory means every file created inside it inherits the directory’s group rather than the creator’s. With 2775, anyone in media can read and write everything, new subdirectories inherit the same behaviour, and nobody has to remember to run chgrp.
The remaining gap is the file mode: a default umask of 022 creates files that group members can read but not write. Samba can be told to fix this per share, which step 4 does; for local users, set umask 002 in their shell configuration.
Verify: as Alice, create a file in /srv/data/photos. As Bob, edit it. If that fails, the umask is the reason — see File Permissions.
3. Choose Samba, NFS, or both
| Samba (SMB) | NFS | |
|---|---|---|
| Clients | Everything — Windows, macOS, Linux, phones, TVs | Linux and Unix |
| Authentication | Its own users and passwords | Trusts the client’s UID numbers |
| Speed on a LAN | Good | Slightly better |
| Good for | Anything with a screen | Linux machines you control |
Most households want Samba, because a phone or a television will speak it and will not speak NFS. Run both if you have Linux machines that would benefit — they can share the same directories.
4. Samba
sudo apt install samba
sudo smbpasswd -a alice # a SEPARATE password from her Linux login# /etc/samba/smb.conf
[global]
workgroup = WORKGROUP
server min protocol = SMB3
map to guest = never
[data]
path = /srv/data
valid users = @media
writable = yes
browseable = yes
create mask = 0664
directory mask = 2775
force group = mediaSamba users are not Linux users. The account must exist on the system, but the password is separate and set with smbpasswd. Forgetting this produces an authentication failure that looks inexplicable, since the password you are typing is definitely correct — for something else.
server min protocol = SMB3 refuses the ancient versions of the protocol, which is worth doing deliberately. The three mask lines are what stop new files arriving with unhelpful permissions despite step 2.
testparm # check the config before restarting
sudo systemctl restart smbd
smbclient -L localhost -U alice
sudo ufw allow from 192.168.1.0/24 to any app SambaNote the firewall rule is restricted to the local network. Samba should never be reachable from the internet.
Verify: mount the share from another machine, write a file, and check on the server that it is owned by the media group with mode 664.
5. NFS, if you want it
sudo apt install nfs-kernel-server
# /etc/exports
/srv/data 192.168.1.0/24(rw,sync,no_subtree_check)
sudo exportfs -ra
sudo exportfs -v # what is actually exported
showmount -e localhostBe clear about what NFS’s security model is: it trusts the client to tell the truth about who is asking. A machine on the allowed network can claim to be UID 1000 and will be believed. That is fine for machines you control on a home network and completely unacceptable anywhere else. Restrict the export to specific addresses, never to a whole subnet you do not own.
The corollary is that UIDs must match between server and clients, or files will appear to belong to the wrong person. Creating your users in the same order on each machine is the low-effort fix; specifying -u explicitly with useradd is the reliable one.
Verify: mount it from a client, create a file, and confirm ls -l shows the same owner on both machines.
6. Media, in a container
# /srv/jellyfin/compose.yaml
services:
jellyfin:
image: jellyfin/jellyfin:10.10.3
restart: unless-stopped
user: "1000:<media-gid>"
ports:
- "127.0.0.1:8096:8096"
volumes:
- ./config:/config
- ./cache:/cache
- /srv/data/video:/media/video:ro
- /srv/data/music:/media/music:ro
devices:
- /dev/dri:/dev/dri # hardware transcoding, if the CPU has itThree deliberate choices. The media directories are mounted read-only, because a media server has no business deleting your files. The user: line sets the UID and GID it runs as, which is what avoids the permission mismatch described in Containers — use the numeric group ID from getent group media. And the port is bound to localhost, so it is reachable through a reverse proxy on the LAN rather than published directly.
Hardware transcoding is worth setting up if your processor supports it: without it, one person watching a file their device cannot play natively will occupy the entire CPU. Check what actually happens during playback — the dashboard tells you whether a stream is being transcoded or passed through.
Verify: play something from another device, and watch htop. If one core is at 100% for a single stream, transcoding is not being accelerated.
7. RAID is not a backup
Mirrored disks protect against exactly one failure: a disk dying. They do nothing about deleting a folder by accident, a corrupted file being faithfully mirrored to both disks, ransomware, a power supply failure that takes the whole machine, theft, or a flood. Neither do snapshots, which live on the same disks. The rule is three copies, on two kinds of media, one of them somewhere else — and the offsite copy is the one that saves you.
restic -r b2:mybucket:home backup /srv/data --exclude-caches
restic -r b2:mybucket:home snapshots
restic -r b2:mybucket:home restore latest --target /tmp/check --include /srv/data/documentsrestic to cheap object storage costs a few pounds a month for a family’s documents and photos, and encrypts before upload. Video is usually replaceable and can be excluded; the photos are not. Put it on a timer that alerts you when it fails.
Verify: restore a directory to /tmp and open a file from it. Repeat every few months.
8. Notice a disk dying before it does
sudo apt install smartmontools
sudo smartctl -a /dev/sda | grep -Ei 'reallocated|pending|health'
sudo smartctl -t long /dev/sda # a thorough self-test, takes hours
sudo systemctl enable --now smartd # and set it to email you
cat /proc/mdstat # if using mdadm RAID
sudo btrfs scrub start /srv/data # if using btrfsThe two numbers worth watching are reallocated sectors and pending sectors. Either climbing from zero means the disk is failing, and you have time to replace it calmly rather than during a rebuild. Schedule a scrub or a long self-test monthly.
Verify: trigger a test alert and confirm it reaches you — the same principle as everything in Monitoring a Server.
Before you call it done
- The data disks are separate from the system disk, and mounted by UUID with
nofail - Shared directories are setgid, and two different people can edit each other’s files
- Samba passwords are set, and the share is firewalled to the local network only
- Nothing is reachable from the internet — check from outside, do not assume
- The media server runs as a real UID and has read-only access to your files
- An encrypted offsite backup runs on a schedule and alerts on failure
- You have restored from that backup at least once
- SMART monitoring is on, and you have seen an alert arrive
Related
- Disks and Mounting — lsblk, UUIDs and the fstab options used above
- File Permissions — setgid, umask and why group writing fails
- restic — the offsite copy that makes the rest of it safe
- A WireGuard VPN — how to reach all of this from outside without exposing it
