{"id":51371330,"url":"https://github.com/shuntps/homelab-stack","last_synced_at":"2026-07-03T07:03:24.405Z","repository":{"id":367794706,"uuid":"1282142235","full_name":"shuntps/homelab-stack","owner":"shuntps","description":"Production-oriented Docker Compose homelab stack for Unraid, Traefik, Authelia, Cloudflare Tunnel, DDNS, and future self-hosted apps.","archived":false,"fork":false,"pushed_at":"2026-06-27T16:47:01.000Z","size":10,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-27T18:18:50.634Z","etag":null,"topics":["2fa","authelia","cloudflare-ddns","cloudflare-tunnel","docker","docker-compose","homelab","infrastructure","infrastructure-as-code","reverse-proxy","self-hosted","sso","traefik","unraid","valkey"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shuntps.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-27T11:30:12.000Z","updated_at":"2026-06-27T16:47:05.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/shuntps/homelab-stack","commit_stats":null,"previous_names":["shuntps/homelab-stack"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/shuntps/homelab-stack","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shuntps%2Fhomelab-stack","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shuntps%2Fhomelab-stack/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shuntps%2Fhomelab-stack/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shuntps%2Fhomelab-stack/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shuntps","download_url":"https://codeload.github.com/shuntps/homelab-stack/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shuntps%2Fhomelab-stack/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35075805,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-03T02:00:05.635Z","response_time":110,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["2fa","authelia","cloudflare-ddns","cloudflare-tunnel","docker","docker-compose","homelab","infrastructure","infrastructure-as-code","reverse-proxy","self-hosted","sso","traefik","unraid","valkey"],"created_at":"2026-07-03T07:03:23.540Z","updated_at":"2026-07-03T07:03:24.391Z","avatar_url":"https://github.com/shuntps.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Homelab Config\n\nProduction-oriented Docker Compose configuration for a private homelab stack.\n\n## Repository\n\n```bash\ngit clone https://github.com/shuntps/homelab-stack.git\n```\n\n## Overview\n\nThis repository contains public-safe configuration templates for a homelab stack:\n\n- Cloudflare Tunnel for inbound HTTP routing.\n- Cloudflare DDNS for direct DNS records.\n- Traefik as the internal reverse proxy.\n- AdGuard DNS Proxy for DNS-over-HTTPS (DoH).\n- Authelia for authentication.\n- Valkey as Redis-compatible session storage.\n- Docker Socket Proxy for constrained Docker API access.\n- Vaultwarden for password management.\n- Pi-hole for LAN DNS filtering (using AdGuard DNS Proxy as upstream).\n- Servarr media automation with qBittorrent, Plex, xTeVe, Prowlarr, Radarr, Sonarr, Overseerr, and Profilarr.\n\nThe real local configuration is intentionally kept out of Git. Public files use safe examples, while private files are ignored by `.gitignore`.\n\nInfrastructure services live in `core/compose.yml`; application services that depend on the shared edge network live in `apps/compose.yml`; media automation services live in `servarr/compose.yml`. Shared values live in `env/common.env`.\n\n## Layout\n\n```text\nenv/\n  common.env.example\ncore/\n  compose.yml\n  .env.example\n  config/\n    authelia/\n      configuration.yml\n      users_database.example.yml\n    cloudflared/\n      config.example.yml\n      credentials.example.json\n    traefik/\n      traefik.yml\n      config/\napps/\n  compose.yml\n  .env.example\nservarr/\n  compose.yml\n  .env.example\n```\n\n## Private Files\n\nCreate these files locally from their examples before starting the stack:\n\n```bash\ncp env/common.env.example env/common.env\ncp core/.env.example core/.env\ncp apps/.env.example apps/.env\ncp servarr/.env.example servarr/.env\ncp core/config/cloudflared/config.example.yml core/config/cloudflared/config.yml\ncp core/config/cloudflared/credentials.example.json core/config/cloudflared/credentials.json\ncp core/config/authelia/users_database.example.yml core/config/authelia/users_database.yml\n```\n\nThen replace all example values with real local values.\n\nCreate `authelia/data/` in your configured appdata path and make it writable by `UID:GID` from `env/common.env`.\n\nPublic hostnames are configured with `*_SUBDOMAIN` variables plus `DOMAIN`.\n\nSet `PIHOLE_DNS_BIND_IP` to the LAN address of the host that should answer DNS queries.\n\nNever commit:\n\n- `env/common.env`\n- `core/.env`\n- `apps/.env`\n- `servarr/.env`\n- `core/config/cloudflared/config.yml`\n- `core/config/cloudflared/credentials.json`\n- `core/config/authelia/users_database.yml`\n- Authelia database, notification, secret, and runtime data files\n\nAuthelia runtime data is expected under `authelia/data/` in your configured appdata path. Vaultwarden and Pi-hole persistent data are also expected under the configured appdata path and should stay out of Git.\n\nAll internal services (except those that circumvent Docker networks, like Plex in host mode) are now configured to use Pi-hole as their primary DNS via `PIHOLE_DNS_BIND_IP`, ensuring internal telemetry filtering and upstream privacy via DoH.\n\nPi-hole Docker settings are managed through `FTLCONF_` environment variables in `apps/compose.yml`. Generated Pi-hole files such as `pihole.toml`, `dnsmasq.conf`, local hosts, and real list exports should stay private.\n\nServarr downloads and media paths should stay on the same storage pool when possible. This keeps Radarr and Sonarr imports fast and allows hardlinks instead of copy-heavy moves.\n\nBefore the first Servarr start, create the Servarr config, downloads, and media directories and make them writable by `UID:GID`.\n\nxTeVe keeps its own container user and group through `XTEVE_UID` and `XTEVE_GID`. Keep its config directories writable by those numeric IDs rather than the shared LinuxServer `PUID` and `PGID`.\n\nPlex is not routed through Traefik. It uses host networking so LAN discovery, companion, and DLNA behavior match a native Plex install.\n\nClaim Plex with a fresh `PLEX_CLAIM` token only during first setup, then remove it from `servarr/.env`. Access the server locally with `http://\u003chost-lan-ip\u003e:32400/web`. For direct remote access, forward TCP `32400` on the edge router to the Docker host and configure Plex Remote Access from the Plex admin UI.\n\n## Usage\n\nStart the core stack from the repository root first, then start the app stack:\n\n```bash\ndocker compose --env-file env/common.env --env-file core/.env -f core/compose.yml up -d\ndocker compose --env-file env/common.env --env-file apps/.env -f apps/compose.yml up -d\ndocker compose --env-file env/common.env --env-file servarr/.env -f servarr/compose.yml up -d\n```\n\nValidate the rendered Compose configuration:\n\n```bash\ndocker compose --env-file env/common.env.example --env-file core/.env.example -f core/compose.yml config --quiet\ndocker compose --env-file env/common.env.example --env-file apps/.env.example -f apps/compose.yml config --quiet\ndocker compose --env-file env/common.env.example --env-file servarr/.env.example -f servarr/compose.yml config --quiet\ndocker compose --env-file env/common.env.example --env-file core/.env.example --env-file apps/.env.example --env-file servarr/.env.example -f core/compose.yml -f apps/compose.yml -f servarr/compose.yml config --quiet\n```\n\n## Validation\n\nAuthelia configuration:\n\n```bash\ndocker run --rm --entrypoint authelia \\\n  --env-file env/common.env.example \\\n  --env-file core/.env.example \\\n  -v \"$PWD/core/config/authelia/configuration.yml:/config/configuration.yml:ro\" \\\n  -v \"$PWD/core/config/authelia/users_database.example.yml:/config/users_database.yml:ro\" \\\n  --tmpfs /data \\\n  -e AUTHELIA_SESSION_REDIS_HOST=redis_valkey \\\n  -e AUTHELIA_SESSION_REDIS_PORT=6379 \\\n  -e AUTHELIA_SESSION_REDIS_PASSWORD=replace_with_strong_redis_password \\\n  authelia/authelia:4.39.15 \\\n  --config /config/configuration.yml \\\n  --config.experimental.filters template \\\n  config validate\n```\n\nCloudflared example configuration:\n\n```bash\ndocker run --rm \\\n  -v \"$PWD/core/config/cloudflared/config.example.yml:/etc/cloudflared/config.yml:ro\" \\\n  -v \"$PWD/core/config/cloudflared/credentials.example.json:/etc/cloudflared/credentials.json:ro\" \\\n  cloudflare/cloudflared:2026.6.1 \\\n  tunnel --config /etc/cloudflared/config.yml ingress validate\n```\n\n## Security Notes\n\n- Do not expose Traefik, Authelia, Redis, or Docker Socket Proxy directly on host ports.\n- Keep Docker socket access behind Docker Socket Proxy.\n- Bind Pi-hole DNS only to the intended LAN host address.\n- Run qBittorrent behind a VPN or firewall policy before using it for untrusted peer traffic.\n- Do not expose Plex through Traefik unless you intentionally design that route.\n- Keep Cloudflare tunnel credentials private.\n- Replace all example passwords, secrets, users, tunnel IDs, and DNS values before production use.\n- Rotate any secret that was ever committed or shared.\n\n## License\n\nThis project is licensed under the MIT License. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshuntps%2Fhomelab-stack","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshuntps%2Fhomelab-stack","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshuntps%2Fhomelab-stack/lists"}