A pragmatic walkthrough of turning spare hardware into a stable, remotely-accessible home server — OS, networking, services, and the boring parts that keep it alive.
The first lie of homelabbing is that you need a rack. The second is that you need a static IP. You need neither. What you actually need is a machine that stays on, an OS you trust, a way in from outside, and the discipline to back it up before you start adding shiny things.
This is the playbook I wish someone had handed me when I plugged in my first home server.
Almost any 64-bit machine with 8 GB of RAM will host a useful stack — Git server, file storage, build runner, a couple of game-related side services. Three usable starting points:
logind.conf.Avoid running a server inside a desktop you also use. The first time you reboot to install a graphics driver and forget that your CI runner lives there, you will understand why.
Use Debian stable or Ubuntu Server LTS. The reason is not religious. It is that your Google searches at 1 AM, when something is broken, will return answers that match what you have. Arch is a fine OS; pick it for your laptop, not for the box you cannot easily plug a monitor into.
During install:
bedrock, kestrel, anything but server1).The first thing on a fresh box is SSH key auth and password lockout:
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server.local
sudo sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/^#*PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
sudo systemctl restart ssh
Add fail2ban if the server will ever be exposed directly. If it lives behind a VPN (preferred), you can skip it without losing sleep.
The boring, correct answer is Tailscale or WireGuard. Both put your server on a private mesh; nothing is open to the internet. Tailscale is faster to set up — install on the server and your phone, log in with the same account, done. You now have a stable hostname (bedrock.tail-scale.ts.net) reachable from anywhere.
If you need a service that the public internet must hit (a personal site, a webhook receiver), the right pattern is:
localhost:8080 on your box.*.yourdomain.com.Forwarding port 22 or 80 from your home router is doable but not worth the operational noise unless you have a real reason.
For a home server, Docker Compose is the right level of abstraction. One YAML file per stack, one docker compose up -d, restarts handled by the daemon. Kubernetes on a single node is a way to learn Kubernetes, not a way to run services.
A starting docker-compose.yml for a base stack:
services:
caddy:
image: caddy:2
restart: unless-stopped
ports: ["80:80", "443:443"]
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
gitea:
image: gitea/gitea:latest
restart: unless-stopped
volumes:
- ./gitea:/data
environment:
- USER_UID=1000
- USER_GID=1000
syncthing:
image: lscr.io/linuxserver/syncthing:latest
restart: unless-stopped
volumes:
- ./syncthing:/config
- /home/user/sync:/data
volumes:
caddy_data:
caddy_config:
Caddy in front gives you automatic HTTPS via Let's Encrypt with one line per service:
git.bedrock.example.com {
reverse_proxy gitea:3000
}
The list grows fast. A defensible starter set, in priority order:
Resist adding Plex, Home Assistant, an ad blocker, and a Minecraft server in week one. Each new service is a new thing that wakes you up.
This is where most home servers die. They do not crash. They drift.
sudo apt install unattended-upgrades. Security patches, no thinking required./ fills up with logs, the box stops responding to SSH. Mount a second disk and put /var/lib/docker and your data there.latest is a footgun. The day a base image changes its default port, your reverse proxy breaks at 3 AM.chrony or systemd-timesyncd. Half of the weird TLS errors that look like "the world is broken" are actually clock skew.A home server is finished when it survives a power cut, a router reboot, and your absence for two weeks without intervention. That is a much better goalpost than feature count. Once you hit it, then you are allowed to add the Minecraft server.