self hosting 101
My Setup
My homeserver is my old laptop running Arch Linux. All the services are categorized in groups and managed one docker-compose.yml file for each group, along with one .env file for all the groups. my setup works for me and I don’t require anything more complicated than this.
Apps
- Administration
- Caddy
- Adguard Home
- Beszel (Monitoring Dashboard)
- Dozzle (Logs)
- Scrutiny (Hard Drive Health Check)
- Personal
- Immich (Google Photos alternative)
- SyncThing
- Samba (SMB share for windows/mac/android)
- Media
- Jellyfin
- *Arr Stack
Wiki
My wiki lives as a folder of markdown files, which I edit using Obsidian, Sync to between my PC and homeserver using Syncthing, and have a CRON job which deploys it every hour to Cloudflare Pages.
Resume CI/CD
I Write my Resume as a TOML file, in my Github Repo. I have a Github Action which runs on any push with tags like “v3.1” and compiles a PDF from the TOML file using Typst, uploads it as a Github Release.
So when you visit resume.advik.one, you make a request to a Cloudflare Worker, which pulls the PDF from the latest Github Release and serves it to you.
Is it Overcomplicated? yes. Did I have fun making it? also yes.
Domain
If you don’t have a public IP address, then you would need cloudflare tunnel. If you have a public IPv6, then you would need Dynamic DNS with cloudflare proxy. If you have a public IPv4, then you don’t need anything else.
Cloudflare API Token
Head over to API Tokens and create a new token. Grant the following permissions:
- Zone > Zone > Read
- Zone > DNS > Edit Copy & Paste the token in your env file
Security
Right now our home server is accessible from anywhere in the world, thanks to IPv6. But do we really want that? Let’s demonstrate why this is a bad idea by grabbing the public IP address of our machine and looking for open ports.
Exposing any service to the public web has inherent risks no matter how secure the service itself is, so it is wise to block all incoming requests except for the ones from Cloudflare.
# Allow localhostsudo iptables -A INPUT -i lo -j ACCEPTsudo ip6tables -A INPUT -i lo -j ACCEPT
# Allow local networksudo iptables -A INPUT -s 192.168.0.0/16 -j ACCEPTsudo ip6tables -A INPUT -s fe80::/64 -j ACCEPT # Link-local IPv6 addresses
# Allow connections established from hostsudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPTsudo ip6tables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Allow ICMPsudo iptables -A INPUT -p icmp -j ACCEPTsudo ip6tables -A INPUT -p icmpv6 -j ACCEPT
# Allow Cloudflare IP rangessudo iptables -A INPUT -s 173.245.48.0/20 -j ACCEPTsudo iptables -A INPUT -s 103.21.244.0/22 -j ACCEPTsudo iptables -A INPUT -s 103.22.200.0/22 -j ACCEPTsudo iptables -A INPUT -s 103.31.4.0/22 -j ACCEPTsudo iptables -A INPUT -s 141.101.64.0/18 -j ACCEPTsudo iptables -A INPUT -s 108.162.192.0/18 -j ACCEPTsudo iptables -A INPUT -s 190.93.240.0/20 -j ACCEPTsudo iptables -A INPUT -s 188.114.96.0/20 -j ACCEPTsudo iptables -A INPUT -s 197.234.240.0/22 -j ACCEPTsudo iptables -A INPUT -s 198.41.128.0/17 -j ACCEPTsudo iptables -A INPUT -s 162.158.0.0/15 -j ACCEPTsudo iptables -A INPUT -s 104.16.0.0/13 -j ACCEPTsudo iptables -A INPUT -s 104.24.0.0/14 -j ACCEPTsudo iptables -A INPUT -s 172.64.0.0/13 -j ACCEPTsudo iptables -A INPUT -s 131.0.72.0/22 -j ACCEPTsudo ip6tables -A INPUT -s 2400:cb00::/32 -j ACCEPTsudo ip6tables -A INPUT -s 2606:4700::/32 -j ACCEPTsudo ip6tables -A INPUT -s 2803:f800::/32 -j ACCEPTsudo ip6tables -A INPUT -s 2405:b500::/32 -j ACCEPTsudo ip6tables -A INPUT -s 2405:8100::/32 -j ACCEPTsudo ip6tables -A INPUT -s 2a06:98c0::/29 -j ACCEPTsudo ip6tables -A INPUT -s 2c0f:f248::/32 -j ACCEPT
# Drop everything elsesudo iptables -P INPUT DROPsudo iptables -P FORWARD DROPsudo ip6tables -P INPUT DROPsudo ip6tables -P FORWARD DROPFuture Improvements
Fail2Ban
I should probably have it but I’m lazy to set it up, and v6 address space is big enough that I never get any bots (I have checked the access logs).
Random Issues
WiFi auto reconnect after a disconnect
[Match]Name=wl*
[Network]# IPv4 ConfigurationAddress=192.168.1.100/24Gateway=192.168.1.1DNS=127.0.0.1
# IPv6 ConfigurationAddress=fe80::100/64Gateway=fe80::1DNS=::1Chrome android ignoring local DNS
https://bugdrivendevelopment.net/browser-ignore-internal-dns/ similar issue on android, fixed by manually setting the dns server in the wifi settings. works on android 13 custom rom.