Homelab
I have a dedicated home server that I run a lot of services on. This repo has my monolithic docker-compose.yml
plus info about what I run.
CPU | Intel i3-7100 |
RAM | 32GB |
SSD | 512GB |
HDD | 3x10TB RAID-Z Array |
OS | Debian |
Services
These are all the services hosted here, what they are for, and any clients I use with them.
User-Facing
- Jellyfin - Media server for movies, TV shows, and music
- Miniflux - Minimalist RSS feed reader
- NetNewsWire - Wonderful all-purpose iOS RSS client
- vaultwarden - Password manager
- Gitea - Git server - in the process of replacing my GitHub account
- LinkStack - Self-hosted LinkTree alternative
- Homepage - My default new tab page; has info about all my services plus links
- Kiwix - Offline wiki hosting - I have Wikipedia, the Arch Linux wiki, and several others downloaded
- Actual Budget - Excellent budgeting app - it can be automatically synced with your bank, but I have found it to be unstable
- There used to be an official app but it has been discontinued - I added the website to my phone's home screen and it works quite well
- Paperless-ngx - Document management system for legal documents, IDs, bank statements, etc.
- Swift Paperless - iOS client
- Immich - Photo and video management
- Their official mobile apps are quite good
- Grocy - Household management (Am I out of milk? Do I have AAA batteries? What can I make for dinner?)
- Tandoor - Recipe management, so I always know which zucchine muffin recipe is the good one
- Untare - Mobile client (discontinued but it still works for now)
- AudioBookShelf - Audiobook server
- The official mobile client works great
- Calibre Web - Ebook management
- Yomu for iOS is nice and minimal and supports OPDS for use with Calibre Web
- Joplin - Notes (Obsidian alternative)
Monitoring
- Dozzle - Docker logs all in one place
- Scrutiny - HDD SMART monitoring, so I know when to prepare for a drive failure
- Speedtest Tracker - Runs scheduled internet speedtests and creates pretty graphs to keep my ISP honest
- Glances - System monitor - I mostly have this for dashboard widgets but it can be useful by itself
Networking
- cloudflared - CloudFlare tunnel client for easy and secure external service access
- gluetun - Docker VPN client and kill-switch. Very useful, allows for per-container VPN connectivity.
- AdGuard Home - DNS filtering - I use this with tailscale to block ads on my phone
Note that I run tailscale on bare metal so it is not listed here, but it is very useful for remote access to services I don't want visible on the open internet as well as SSH access.
Downloading
- qBittorrent - The only torrent client I'll ever use
- Radarr - Automated movie fetching
- Sonarr - Automated TV show fetching
- Prowlarr - Torrent indexer that interfaces with the other *arrs
- Bazarr - Automated subtitle fetching (I also use the OpenSubtitles plugin within Jellyfin when needed, but this works hands-off most of the time)
I use LunaSea as a mobile client for Radarr and Sonarr.
This configuration uses .env
files to separate secrets from public information and maintain brevity in the main docker-compose.yml
Environment
Below are the variables that need to be set in the .env
file for each service. Empty variables should be replaced with your values.
A Note on Email
Several of these env files include SMTP settings, which are completely optional. Automated email sending is very useful for user signups, 2FA, account recovery, and notifications, but email is notoriously difficult to self-host. The solution I've found works very well and generally gets past spam filters.
I use SendGrid with CloudFlare's email routing for email. I have a catch-all rule in CloudFlare that forwards all emails to a dedicated Gmail address, and that address uses a
Send Mail As
address set up with SendGrid's SMTP for sending emails by hand.By default, emails sent this way will show a little
via sendgrid.net
notice. To remove this, verify your domain with SendGrid.Also, link tracking is enabled by default and should be disabled in SendGrid's tracking settings.
SMTP Settings:
- Host:
smtp.sendgrid.net
- Port:
587
- Security:
tls
(or equivalent, e.g.starttls
for vaultwarden)- Username:
apikey
- Password: API Key generated in SendGrid
- From:
<mailer-name>@<your-domain>
- For each custom sender (mailer-name
), there needs to be a verified sender in SendGrid.
cloudflared
TUNNEL_TOKEN
: available in the cloudflare zero-trust tunnel dashboard, under install and run a connector
gluetun
The values below are specific to Mullvad VPN (docs). Other providers need different values, refer to the corresponding gluetun documentation.
VPN_SERVICE_PROVIDER=mullvad
VPN_TYPE=wireguard
WIREGUARD_PRIVATE_KEY=
WIREGUARD_ADDRESSESS=
SERVER_CITIES=
The values for WIREGUARD_PRIVATE_KEY
and WIREGUARD_ADDRESSES
should be available in the WireGuard configuration file generated by Mullvad. SERVER_CITIES
should be set to the city of your configuration's selected exit node.
Immich
My current Immich docker setup includes a lot of repetition - when I want to update, I have to change the version in 3 places. I have plans to improve this, but for now this is what works. Also note that the way I set the upload location is not recommended by the Immich docs.
For more information, see the Immich docker-compose setup instructions.
UPLOAD_LOCATION=/media/immich
IMMICH_VERSION="v1.123.0"
TYPESENSE_API_KEY=
DB_PASSWORD=
DB_HOSTNAME=immich_postgres
DB_USERNAME=postgres
DB_DATABASE_NAME=immich
DB_DATA_LOCATION=/docker/immich
REDIS_HOSTNAME=immich_redis
POSTGRES_PASSWORD= # this should be the same as DB_PASSWORD above
POSTGRES_USER=postgres
POSTGRES_DB=immich
Joplin
See the docker-joplin-server docs for more info.
APP_PORT=22300
APP_BASE_URL=
DB_CLIENT=pg
POSTGRES_PASSWORD=
POSTGRES_DATABASE=joplin
POSTGRES_USER=
POSTGRES_PORT=5432
POSTGRES_HOST=joplin-db
# Optional SMTP options
MAILER_ENABLED=1
MAILER_HOST=
MAILER_PORT=465
MAILER_SECURE=1
MAILER_AUTH_USER=
MAILER_AUTH_PASSWORD=
MAILER_NOREPLY_NAME=
MAILER_NOREPLY_EMAIL=
LinkStack
This one just needs the public hostname and admin email. Docs.
HTTPS_SERVER_NAME=
SERVER_ADMIN=
Miniflux
DATABASE_URL=postgres://miniflux:{...}@rss_db:5432/miniflux?sslmode=disable # replace {...} with your postgres password
RUN_MIGRATIONS=1
POSTGRES_USER=miniflux
POSTGRES_PASSWORD= # this is the password used above
POSTGRES_DB=miniflux
Paperless-ngx
USERMAP_UID=1000
USERMAP_GID=1000
PUID=1000
PGID=1000
PAPERLESS_URL=
# Random secret key, use for example `base64 /dev/urandom | head -c50` to generate one
PAPERLESS_SECRET_KEY=
PAPERLESS_TIME_ZONE=
PAPERLESS_OCR_LANGUAGE=eng
PAPERLESS_REDIS: redis://paperless_broker:6379
PAPERLESS_OCR_USER_ARGS: '{"invalidate_digital_signatures": true}'
# Optional SMTP email settings
PAPERLESS_EMAIL_HOST=
PAPERLESS_EMAIL_PORT=587
PAPERLESS_EMAIL_USE_TLS=true
PAPERLESS_EMAIL_HOST_USER=
PAPERLESS_EMAIL_HOST_PASSWORD=
PAPERLESS_EMAIL_FROM=
Speedtest Tracker
Docs. APP_URL
is the public address, APP_KEY
is generated with echo -n 'base64:'; openssl rand -base64 32;
PUID=1000
PGID=1000
APP_KEY=
APP_URL=
DB_CONNECTION=sqlite
APP_TIMEZONE=
DISPLAY_TIMEZONE=
SPEEDTEST_SCHEDULE=0,15,30,45 * * * * # run speedtest every 15 minutes
Tandoor
Docs.
# Random secret key, use for example `base64 /dev/urandom | head -c50` to generate one
SECRET_KEY=
# Allowed hosts (see documentation), should be set to your hostname(s) but might be * (default) for some proxies/providers
ALLOWED_HOSTS=
# Add only a database password if you want to run with the default postgres, otherwise change settings accordingly
DB_ENGINE=django.db.backends.postgresql
POSTGRES_HOST=tandoor-db
POSTGRES_DB=tandoor
POSTGRES_PORT=5432
POSTGRES_USER=tandoor
POSTGRES_PASSWORD=
vaultwarden
Docs. Note that the crypto API requires HTTPS, so local access is a bit of a challenge.
These values are only required if you need to use the vaultwarden admin page (for user management, SMTP, hardware 2FA, etc.). The ADMIN_TOKEN
value gave me trouble - to make it work, I used the 'Using argon2
' instructions from Enabling admin page in the docs. At your-ip-or-url.com/admin
, the password you used for the hash will unlock it (e.g. MySecretPassword
per their example).
Note: The ADMIN_TOKEN
value should be enclosed in single quotes. If it is not, all instances of $
in the value will need to be replaced with $$
to prevent the value from being split by the parser.
DOMAIN=
# Dollar signs must be replaced with two dollar signs to properly escape variables in this token
ADMIN_TOKEN=
# Optional SMTP email settings
SMTP_HOST=
SMTP_FROM=
SMTP_PORT=587
SMTP_SECURITY=starttls
SMTP_USERNAME=
SMTP_PASSWORD=