2025-04-21 10:40:49 -05:00
2025-04-11 10:21:46 -05:00
2025-03-24 15:18:08 -05:00
2025-04-21 10:40:49 -05:00

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, what they are for, and any clients I use with them, in alphabetical order.

Media

  • AudioBookShelf - Audiobook and podcast server
    • The official mobile client works great
  • Calibre Web Automated - Ebook management
    • Yomu for iOS is nice and minimal and supports OPDS for use with Calibre Web
  • Immich - Photo and video management
    • Their official mobile apps are quite good
  • Jellyfin - Media server for movies, TV shows, and music
    • Feishin - Desktop music client (soon to be replaced by audioling)
    • Finamp - Mobile music client
    • For other devices (desktop, mobile, Roku/Android TV) I use either the web app or the official Jellyfin client

Utilities

  • Actual Budget - Excellent budgeting app. It can be automatically synced with your bank (SimpleFIN Bridge for US banks, $15/year), but I have found that 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
  • Baikal - Calendar/contacts
  • Backrest - UI to manage backups (sent to a Raspberry Pi 5 running restic)
  • ConvertX - File conversion utility
  • Gitea - Git server - in the process of replacing my GitHub account
  • Wallabag - Bookmark tool for links, pictures, notes, etc.
  • IT Tools - Collection of random useful development/IT utilities
  • Joplin - Notes (Obsidian alternative)
  • Kiwix - Offline wiki hosting - I have Wikipedia, the Arch Linux wiki, and several others downloaded
  • LinkStack - Self-hosted LinkTree alternative (azpsen.com) - more for content creators, definitely overkill for what I need. I'll probably replace it with a simple static site at some point
  • LubeLogger - Car mileage and service tracker
  • Maloja - Self-hosted music listen tracker (last.fm replacement) - with multi-scrobbler for Jellyfin support
  • Memos - Super simple note/list/todo/memo app
  • Miniflux - Minimalist RSS feed reader
  • Paperless-ngx - Document management system for legal documents, IDs, bank statements, etc.
  • PicoShare - Super simple file sharing tool
  • Seafile - Cloud drive
  • Stirling PDF - PDF tools for viewing, editing, converting, and everything else
  • 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)
  • Tinyhome - Static new tab page set up with links to all my server stuff
  • vaultwarden - Password manager
  • Wizarr - Jellyfin user invite manager

Monitoring

  • Dozzle - Docker logs all in one place
  • Glances - System monitor - I mostly have this for dashboard widgets but it can be useful by itself
  • Scrutiny - HDD SMART monitoring, so I know when to prepare for a drive failure
  • MySpeed - Runs scheduled internet speedtests and creates pretty graphs to keep my ISP honest

Networking

  • AdGuard Home - DNS filtering - I use this with tailscale to block ads on my phone
  • 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 routing.

Note that I run tailscale as a system service, not in a container, so it is not listed here, but it is very useful for secure remote access - both for SSH and for services that don't need to be publicly visible.

In docker-compose.yml, services that I access through tailscale need the dns: 100.111.0.126 section in order to access the internet (100.111.0.126 is the tailscale IP of the server).

Downloading

  • Bazarr - Automated subtitle fetching (I also use the OpenSubtitles plugin within Jellyfin when needed, but this works hands-off most of the time)
  • Calibre Web Book Downloader - Automated ebook search and downloading
  • openbooks - Automated IRC-based ebook search and downloading
  • Prowlarr - Torrent indexer that interfaces with the other *arrs
  • qBittorrent - The only torrent client I'll ever use
  • Radarr - Automated movie fetching
  • Sonarr - Automated TV show fetching

I use LunaSea as a mobile client for Radarr and Sonarr.

Environment

This configuration uses .env files to separate secrets from public information and keep the main docker-compose.yml a little shorter. It is set up to look for these files in /docker/env, with each service having its own <service>.env file.

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

Docs

# cloudflared.env

# Available in the cloudflare zero-trust tunnel dashboard, under `install and run a connector`
TUNNEL_TOKEN=

ConvertX

Docs

# convertx.env

JWT_SECRET=
HTTP_ALLOWED=true

gluetun

Docs

The values below are specific to Mullvad VPN (gluetun docs). Other providers need different values, refer to the corresponding gluetun documentation.

# gluetun.env

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

Docs

My current Immich docker setup has 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.

# immich.env

UPLOAD_LOCATION=/media/immich

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

Invidious

Docs

Note that the password under db in INVIDIOUS_CONFIG should be the same as the POSTGRES_PASSWORD. The hmac_key should be a different, randomly generated value

# invidious.env

# Invidious
INVIDIOUS_CONFIG='
    db:
        dbname: invidious
        user: invidious
        password:
        host: invidious-db
        port: 5432
    check_tables: true
    signature_server: invidious-sighelper:12999
    visitor_data:
    po_token:
    external_port: 9080
    https_only: false
    statistics_enabled: false
    registration_enabled: false
    popular_enabled: false
    hmac_key:
    admins: ["april"]
    default_user_preferences:
        quality: dash
        feed_menu: ["Trending", "Subscriptions", "Playlists"]
        default_home: Trending
'

# Database
POSTGRES_DB=invidious
POSTGRES_USER=invidious
POSTGRES_PASSWORD=

# to update the visitor_data and po_token:
# docker run quay.io/invidious/youtube-trusted-session-generator
# or, for use with gluetun:
# docker run --network=container:gluetun quay.io/invidious/youtube-trusted-session-generator

Joplin

Docs

# joplin.env

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 settings
MAILER_ENABLED=1
MAILER_HOST=
MAILER_PORT=465
MAILER_SECURE=1
MAILER_AUTH_USER=
MAILER_AUTH_PASSWORD=
MAILER_NOREPLY_NAME=
MAILER_NOREPLY_EMAIL=

LinkStack

Docs

This one just needs the public hostname and admin email.

# linkstack.env

HTTPS_SERVER_NAME=
SERVER_ADMIN=

LubeLogger

Docs

# lubelogger.env
LC_ALL=en_US
LANG=en_US
MailConfig__EmailServer=
MailConfig__EmailFrom=
MailConfig__Port=587
MailConfig__Username=
MailConfig__Password=

Miniflux

Docs

# miniflux.env

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

MultiScrobbler

Docs

# multi-scrobbler.env

TZ=America/Chicago
PUID=1000
PGID=1000
MALOJA_URL=http://maloja:42010
MALOJA_API_KEY=
JELLYFIN_URL=http://jellyfin:8096
JELLYFIN_USER=
JELLYFIN_APIKEY=
JELLYFIN_USERS_ALLOW=

Paperless-ngx

Docs

# paperless.env

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=

PicoShare

Docs

# picoshare.env

PORT=4001
PS_SHARED_SECRET=
PS_BEHIND_PROXY=true

Seafile

Docs

# seafile.env

DB_HOST=seafile_db
DB_ROOT_PASSWD=
SEAFILE_ADMIN_EMAIL=
SEAFILE_ADMIN_PASSWORD=
SEAFILE_SERVER_HOSTNAME=
FORCE_HTTPS_IN_CONF=true

MYSQL_ROOT_PASSWORD= # same as DB_ROOT_PASSWD above
MYSQL_LOG_CONSOLE=true
MARIADB_AUTO_UPGRADE=1

Speedtest Tracker

Docs

# speedtest.env

PUID=1000
PGID=1000

# Generate with `echo -n 'base64:'; openssl rand -base64 32;` or use the speedtest-tracker website
APP_KEY=

# Public address or IP
APP_URL=

DB_CONNECTION=sqlite
APP_TIMEZONE=
DISPLAY_TIMEZONE=
SPEEDTEST_SCHEDULE=0,15,30,45 * * * * # run speedtest every 15 minutes

Tandoor

Docs

# tandoor.env

# 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 cryptography API used by vaultwarden requires HTTPS, so local access can be 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.

# vaultwarden.env

# Public domain or IP
DOMAIN=

ADMIN_TOKEN=

# Optional SMTP email settings
SMTP_HOST=
SMTP_FROM=
SMTP_PORT=587
SMTP_SECURITY=starttls
SMTP_USERNAME=
SMTP_PASSWORD=

wallabag

Docs

The domain name should be set to your Wallabag instance's domain (e.g. links.mysite.com). Server name is just a pretty name for your instance. The DB password and secret can be set to randomly generated strings.

FOSUSER_REGISTRATION must be set to true for at least the first run so a user can be created.

Note: The username/password need to be included in the mailer DSN (e.g. smtp://apikey:mykey12345@smtp.sendgrid.net)

# wallabag.env

SYMFONY__ENV__DOMAIN_NAME=
SYMFONY__ENV__SERVER_NAME=
SYMFONY__ENV__DATABASE_PASSWORD=
SYMFONY__ENV__SECRET=
SYMFONY__ENV__FOSUSER_REGISTRATION=false
SYMFONY__ENV__MAILER_DSN=
SYMFONY__ENV__FROM_EMAIL=
Description
docker setup for self-hosted services
Readme 454 KiB