Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,14 @@ ACME_EMAIL=you@example.com # Let's Encrypt notification email
# TRAEFIK
# -----------------------------------------------------------------------------
TRAEFIK_DASHBOARD_USER=admin
# Generate password hash: echo $(htpasswd -nb admin yourpassword) | sed -e s/\$/\$\$/g
TRAEFIK_DASHBOARD_PASSWORD_HASH=
# Generate BasicAuth credentials:
# htpasswd -nbB admin 'your-password' | sed -e 's/\$/\$\$/g'
TRAEFIK_AUTH=
# letsencrypt = HTTP-01 challenge, letsencryptdns = DNS challenge
TRAEFIK_CERT_RESOLVER=letsencrypt
ACME_DNS_PROVIDER=cloudflare
CF_DNS_API_TOKEN=
DOCKER_API_VERSION=1.43

# -----------------------------------------------------------------------------
# PORTAINER
Expand Down Expand Up @@ -105,6 +111,16 @@ OLLAMA_GPU_ENABLED=false # Set to true if you have NVIDIA GPU
# -----------------------------------------------------------------------------
GOTIFY_PASSWORD= # REQUIRED
NTFY_AUTH_ENABLED=true
# Optional Watchtower integration with Gotify or ntfy via Shoutrrr.
# Examples:
# WATCHTOWER_NOTIFICATIONS=shoutrrr
# WATCHTOWER_NOTIFICATION_URL=gotify://gotify.example.com/token
# WATCHTOWER_NOTIFICATION_URL=ntfy://ntfy.example.com/homelab-updates
WATCHTOWER_NOTIFICATIONS=
WATCHTOWER_NOTIFICATION_URL=
WATCHTOWER_NOTIFICATIONS_LEVEL=info
WATCHTOWER_NOTIFICATION_REPORT=true
WATCHTOWER_NOTIFICATION_LOG_STDOUT=false

# -----------------------------------------------------------------------------
# NETWORK PROXY (optional — for CN users with local proxy)
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@
git clone https://github.com/YOUR_USERNAME/homelab-stack.git
cd homelab-stack

# 2. Check dependencies & setup environment
# 2. Check dependencies, configure the environment, and launch base infrastructure
./install.sh

# 3. Launch base infrastructure
docker compose -f docker-compose.base.yml up -d
# 3. Check base infrastructure
docker compose --env-file .env -f stacks/base/docker-compose.yml ps

# 4. Launch any stack
./scripts/stack-manager.sh start media
Expand All @@ -41,7 +41,7 @@ docker compose -f docker-compose.base.yml up -d

| Stack | Services | Bounty |
|-------|----------|--------|
| [Base Infrastructure](stacks/base/) | Traefik, Portainer, Watchtower | ✅ Core |
| [Base Infrastructure](stacks/base/) | Traefik, Portainer, Watchtower, Docker Socket Proxy | ✅ Core |
| [Media](stacks/media/) | Jellyfin, Sonarr, Radarr, Prowlarr, qBittorrent, Jellyseerr | [#2](../../issues/2) |
| [Storage](stacks/storage/) | Nextcloud, MinIO, FileBrowser, Syncthing | [#3](../../issues/3) |
| [Monitoring](stacks/monitoring/) | Grafana, Prometheus, Loki, Alertmanager, Uptime Kuma | [#4](../../issues/4) |
Expand Down Expand Up @@ -86,12 +86,12 @@ All stacks share:
```
homelab-stack/
├── install.sh # Entry point — env check + guided setup
├── docker-compose.base.yml # Core infrastructure
├── .env.example # All configurable variables
├── BOUNTY.md # Bounty task overview
├── stacks/ # One directory per service group
│ ├── media/
│ ├── base/ # Core infrastructure compose
│ ├── storage/
│ ├── monitoring/
│ ├── network/
Expand Down
40 changes: 4 additions & 36 deletions config/traefik/dynamic/middlewares.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,15 @@
# All middlewares defined here are available project-wide via @file provider.
#
# Usage in docker-compose labels:
# traefik.http.routers.<name>.middlewares=authentik@file,security-headers@file
# traefik.http.routers.<name>.middlewares=security-headers@file,rate-limit@file
# Dashboard BasicAuth is defined in stacks/base/docker-compose.yml so it can use
# TRAEFIK_AUTH from .env without writing generated secrets into this directory.
# Authentik ForwardAuth lives in config/traefik/dynamic/authentik.yml.
# =============================================================================

http:
middlewares:

# -------------------------------------------------------------------------
# BasicAuth — Traefik Dashboard protection
# Generate hash: echo $(htpasswd -nb admin PASSWORD) | sed -e s/\$/\$\$/g
# Then set TRAEFIK_DASHBOARD_PASSWORD_HASH in .env
# -------------------------------------------------------------------------
traefik-auth:
basicAuth:
usersFile: /dynamic/.htpasswd
removeHeader: true # Strip Authorization header from upstream request

# -------------------------------------------------------------------------
# Authentik ForwardAuth
# Protects any service — redirects unauthenticated requests to SSO login.
# Requires: SSO stack running (stacks/sso/docker-compose.yml)
#
# Usage: add to any router:
# traefik.http.routers.<name>.middlewares=authentik@file
# -------------------------------------------------------------------------
authentik:
forwardAuth:
address: "http://authentik-server:9000/outpost.goauthentik.io/auth/traefik"
trustForwardHeader: true
authResponseHeaders:
- X-authentik-username
- X-authentik-groups
- X-authentik-email
- X-authentik-name
- X-authentik-uid
- X-authentik-jwt
- X-authentik-meta-jwks
- X-authentik-meta-outpost
- X-authentik-meta-provider
- X-authentik-meta-app
- X-authentik-meta-version

# -------------------------------------------------------------------------
# Security Headers — applied to all public-facing services
# Reference: https://securityheaders.com
Expand Down
3 changes: 2 additions & 1 deletion config/traefik/traefik.local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ entryPoints:

providers:
docker:
endpoint: "unix:///var/run/docker.sock"
endpoint: "tcp://socket-proxy:2375"
exposedByDefault: false
network: proxy
constraints: "Label(`traefik.enable`, `true`)"
watch: true
file:
directory: /dynamic
Expand Down
16 changes: 8 additions & 8 deletions config/traefik/traefik.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
# Traefik — Static Configuration
# Docs: https://doc.traefik.io/traefik/reference/static-configuration/file/
#
# NOTE: Traefik static config does NOT support environment variable substitution.
# Edit this file directly or use envsubst in your deploy script.
# Values marked [EDIT] must be changed before first run.
# NOTE: Values in this static file can be overridden by TRAEFIK_* environment
# variables supplied by stacks/base/docker-compose.yml.
# =============================================================================

# -----------------------------------------------------------------------------
Expand Down Expand Up @@ -59,19 +58,19 @@ entryPoints:
certificatesResolvers:
letsencrypt:
acme:
email: "admin@yourdomain.com" # [EDIT] your email
email: "admin@example.com" # Overridden by ACME_EMAIL via compose env
storage: /acme.json
caServer: "https://acme-v02.api.letsencrypt.org/directory"
httpChallenge:
entryPoint: web

letsencrypt-dns:
letsencryptdns:
acme:
email: "admin@yourdomain.com" # [EDIT] same email
email: "admin@example.com" # Overridden by ACME_EMAIL via compose env
storage: /acme.json
caServer: "https://acme-v02.api.letsencrypt.org/directory"
dnsChallenge:
provider: cloudflare # [EDIT] your DNS provider
provider: cloudflare # Override with ACME_DNS_PROVIDER
resolvers:
- "1.1.1.1:53"
- "8.8.8.8:53"
Expand All @@ -81,9 +80,10 @@ certificatesResolvers:
# -----------------------------------------------------------------------------
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
endpoint: "tcp://socket-proxy:2375"
exposedByDefault: false # Containers must opt-in with traefik.enable=true
network: proxy # Default network for routing
constraints: "Label(`traefik.enable`, `true`)"
watch: true

file:
Expand Down
5 changes: 3 additions & 2 deletions homelab.md
Original file line number Diff line number Diff line change
Expand Up @@ -390,9 +390,10 @@ push notification"]
### base
| Service | Image | URL |
|---------|-------|-----|
| Traefik | traefik:v3.1.6 | traefik.DOMAIN |
| Portainer | portainer-ce:2.21.4 | portainer.DOMAIN |
| Traefik | traefik:v3.6.1 | traefik.DOMAIN |
| Portainer | portainer/portainer-ce:2.21.3 | portainer.DOMAIN |
| Watchtower | containrrr/watchtower:1.7.1 | -- |
| Docker Socket Proxy | tecnativa/docker-socket-proxy:0.2.0 | internal |

Config: config/traefik/traefik.yml (prod), traefik.local.yml (dev)

Expand Down
36 changes: 21 additions & 15 deletions install.sh
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
set -euo pipefail
IFS=$'\n\t'

ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
cd "$ROOT_DIR"

RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
BLUE='\033[0;34m'; BOLD='\033[1m'; NC='\033[0m'

Expand Down Expand Up @@ -34,32 +37,27 @@ echo -e "${BOLD} S T A C K v1.0.0${NC}"
echo -e ""

# ---------------------------------------------------------------------------
# Step 1: Check dependencies
# ---------------------------------------------------------------------------
log_step "Checking dependencies"
bash "$(dirname "$0")/scripts/check-deps.sh"

# ---------------------------------------------------------------------------
# Step 2: CN network detection
# Step 1: Check system dependencies
# ---------------------------------------------------------------------------
log_step "Network environment detection"
bash "$(dirname "$0")/scripts/check-deps.sh" --network-check
log_step "Checking system dependencies"
bash "$ROOT_DIR/scripts/check-deps.sh" --preflight

# ---------------------------------------------------------------------------
# Step 3: Setup environment
# Step 2: Setup environment
# ---------------------------------------------------------------------------
log_step "Environment configuration"
if [[ ! -f .env ]]; then
bash "$(dirname "$0")/scripts/setup-env.sh"
bash "$ROOT_DIR/scripts/setup-env.sh"
else
log_warn ".env already exists, skipping setup. Remove it to reconfigure."
fi

# ---------------------------------------------------------------------------
# Step 4: Create data directories
# Step 3: Create data directories and base prerequisites
# ---------------------------------------------------------------------------
log_step "Creating data directories"
log_step "Creating data directories and base prerequisites"
mkdir -p \
config/traefik \
data/traefik/certs \
data/portainer \
data/prometheus \
Expand All @@ -70,13 +68,21 @@ mkdir -p \
data/gitea \
data/vaultwarden

chmod 600 config/traefik/acme.json 2>/dev/null || touch config/traefik/acme.json && chmod 600 config/traefik/acme.json
touch config/traefik/acme.json
chmod 600 config/traefik/acme.json
docker network inspect proxy >/dev/null 2>&1 || docker network create proxy >/dev/null

# ---------------------------------------------------------------------------
# Step 4: Validate configured stack
# ---------------------------------------------------------------------------
log_step "Validating configured stack"
bash "$ROOT_DIR/scripts/check-deps.sh"

# ---------------------------------------------------------------------------
# Step 5: Launch base infrastructure
# ---------------------------------------------------------------------------
log_step "Launching base infrastructure"
docker compose -f docker-compose.base.yml up -d
docker compose --env-file .env -f stacks/base/docker-compose.yml up -d

log_info ""
log_info "${GREEN}${BOLD}✓ Base infrastructure is up!${NC}"
Expand Down
Empty file modified scripts/backup-databases.sh
100644 → 100755
Empty file.
Empty file modified scripts/backup.sh
100644 → 100755
Empty file.
Loading