These are basic instructions for how I have configured the OS and auxiliary packages for my home server. This sets up:
- Sane security defaults
- At-rest encryption for all important data
- Remote and local backups
For information on how to setup the various Docker containers for services, visit each of the subdirectories here:
I use NixOS btw, so I have a NixOS setup for servers. All I need are my dotfiles (GitLab, GitHub) with profile
set to “homelab” inside my flake.nix
. What this essentially does is:
- Activate a firewall that doesn’t let anything through by default (except SSH)
- Activates ssh with my public ssh key authorized
- Disallows root login via ssh
- Disallows password-based login via ssh
- Replaces
sudo
withdoas
, since sudo is overkill for a system managed by one person - Installs necessary packages for server management:
docker
, along with docker utilitiesdocker-compose
andlazydocker
gocryptfs
for easy at-rest encryption of all important datardiff-backup
for quick reverse-incremental backupsrclone
for connecting to cloud storage for off-site backups
Again, since I use NixOS, my configuration does all of this for me, since I told it to. All of these can be done on other Linux distros (i.e. Ubuntu, Debian, Arch), but require you to remember a set of steps. A quick look through the Arch wiki should tell you how to set any of these up yourself on a different system if you would like.
Most of the time, when you encrypt a Linux desktop or laptop, you use block encryption
, which encrypts literally everything (except the bootloader). What this means is, if the computer shuts down unexpectedly, when turning it back on, you must either:
- Input the keyphrase manually
- Store a keyfile on the disk to decrypt it
In the first case, you can set it up to allow you to input the keyphrase remotely, but that’s a bit annoying to setup, which means you can only input the keyphrase when you have physical access to the server.
In the second case, any moderately skilled hacker who steals your hard drive can decrypt the entire thing, which means the encryption isn’t doing its job.
In any case, while more secure, this block encryption is inconvenient for homelab usage.
The other solution is stacked filesystem encryption
, in which you encrypt only a single directory (we’ll call it crypt
), and then virtually mount it for usage inside a decrypted directory (I usually call this directory plain
).
Benefits to this for are:
- You can decrypt it remotely a lot easier (as long as the server is physically on), since you will still always have access to ssh in the case of an interruption
- It’s really easy to backup everything to the cloud encrypted, since all you need to do is sync the
crypt
folder instead of theplain
folder
With respect to block-level encryption:
- It may be easier for an attacker with physical access to tamper with your system-level files to install a rootkit or other nasty hack, since those files remain unencrypted on the system
- With most stacked encryption solutions, attackers can still see the directory structure and relative file sizes of encrypted files, which can allow them to guess what kind of files you have (even if the file names and contents are encrypted)
For my use I’m going with stacked filesystem encryption
using a package called gocryptfs
First create two directories: crypt
and plain
. crypt
is the encrypted directory, while plain
is where it will be mounted in the clear.
mkdir crypt plain
Then, you must initialize the encrypted directory, providing it with a passphrase:
gocryptfs -init crypt
It will give you a master key, which gives you complete access to the encrypted directory. As they explain, save it in a secure place and only use it in emergencies!
Finally, to mount it, you merely run:
gocryptfs crypt plain
The only problem with this setup, is that only the user that called the command can view the unencrypted contents. If you call this as your normal user not even root can see inside the decrypted mount. This is a feature, not a bug. However, since many docker containers rely on multiple users, this means that running most docker containers inside a gocryptfs mount won’t work by default. Fortunately, we can allow other users into the mount with the -allow_others
flag:
gocryptfs -allow_others crypt plain
which allows normal filesystem access inside the gocryptfs mount based on *nix permissions.
With gocryptfs setup and mounted, the docker-compose
examples from this repo can be copied into the plain
directory and setup. Most examples require you to change defaults, such as database passwords, domain name(s), email, time zones, etc.. More info can be found in each subdirectory (i.e. homelab, network, gameservers, etc…)
Once such defaults are properly configured, you can cd
into each directory and run:
sudo docker-compose up -d
to start the containers.
If data does not exist in at least 3 physical drives, and at least 2 geographically separated locations, it does not exist. It is a good idea to set up:
- A local backup on a separate SSD or flash drive
- This protects against your main hard drive failing
- Additionally, if it is disconnected, this protects against ransomware and/or other hacks where access to data is compromised by an attacker
- A remote backup in the cloud (or someone else’s computer)
- This protects you against a home disaster such as fire, flooding, theft
More information can be found in maintenance.org within the homelab directory.