commit 4b7a8dce283945cd90f2eac45322a4b44a322e09 Author: ulfrxdev Date: Mon Feb 23 17:46:11 2026 +0100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c842e4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.env +.DS_Store \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/stacks/authentik/.env.example b/stacks/authentik/.env.example new file mode 100644 index 0000000..2646715 --- /dev/null +++ b/stacks/authentik/.env.example @@ -0,0 +1,3 @@ +AUTHENTIK_DOMAIN= +PG_DB= +PG_USER= \ No newline at end of file diff --git a/stacks/authentik/docker-compose.yml b/stacks/authentik/docker-compose.yml new file mode 100644 index 0000000..b2e3cbb --- /dev/null +++ b/stacks/authentik/docker-compose.yml @@ -0,0 +1,95 @@ +services: + db: + image: postgres@sha256:035b9ab53cfa147d7202b61f5f7782b939ae815b7d6bc81c96b7b42ff1fca950 + container_name: authentik-db + restart: unless-stopped + env_file: + - .env + environment: + POSTGRES_DB: ${PG_DB} + POSTGRES_USER: ${PG_USER} + POSTGRES_PASSWORD_FILE: /run/secrets/pg_pass + volumes: + - authentik_database:/var/lib/postgresql/data + networks: + - authentik_internal + secrets: + - pg_pass + healthcheck: + interval: 30s + retries: 5 + start_period: 20s + test: + - CMD-SHELL + - pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER} + timeout: 5s + server: + image: ghcr.io/goauthentik/server:2025.12.4@sha256:61eb50cfededf2ecc0ef483b497746db96d18934d440d7d55f6baa41977d8e85 + container_name: authentik-server + restart: unless-stopped + command: server + depends_on: + db: + condition: service_healthy + env_file: + - .env + environment: + AUTHENTIK_POSTGRESQL__HOST: db + AUTHENTIK_POSTGRESQL__NAME: ${PG_DB} + AUTHENTIK_POSTGRESQL__USER: ${PG_USER} + AUTHENTIK_POSTGRESQL__PASSWORD: file:///run/secrets/pg_pass + AUTHENTIK_SECRET_KEY: file:///run/secrets/authentik_secret_key + volumes: + - authentik_data:/data + networks: + - authentik_internal + - homelab_apps + secrets: + - pg_pass + - authentik_secret_key + labels: + - traefik.enable=true + - traefik.docker.network=homelab_apps + - traefik.http.routers.authentik.rule=Host(`${AUTHENTIK_DOMAIN}`) + - traefik.http.routers.authentik.entrypoints=websecure + - traefik.http.routers.authentik.tls=true + - traefik.http.routers.authentik.tls.certresolver=le + - traefik.http.services.authentik.loadbalancer.server.port=9000 + worker: + image: ghcr.io/goauthentik/server:2025.12.4@sha256:61eb50cfededf2ecc0ef483b497746db96d18934d440d7d55f6baa41977d8e85 + container_name: authentik-worker + restart: unless-stopped + command: worker + depends_on: + db: + condition: service_healthy + env_file: + - .env + environment: + AUTHENTIK_POSTGRESQL__HOST: db + AUTHENTIK_POSTGRESQL__NAME: ${PG_DB} + AUTHENTIK_POSTGRESQL__USER: ${PG_USER} + AUTHENTIK_POSTGRESQL__PASSWORD: file:///run/secrets/pg_pass + AUTHENTIK_SECRET_KEY: file:///run/secrets/authentik_secret_key + volumes: + - authentik_data:/data + networks: + - authentik_internal + secrets: + - pg_pass + - authentik_secret_key +volumes: + authentik_database: + driver: local + authentik_data: + driver: local +networks: + authentik_internal: + internal: true + homelab_apps: + external: true +secrets: + pg_pass: + file: ./secrets/pg_pass.txt + authentik_secret_key: + file: ./secrets/authentik_secret_key.txt \ No newline at end of file diff --git a/stacks/dockhand/.env.example b/stacks/dockhand/.env.example new file mode 100644 index 0000000..71dfe32 --- /dev/null +++ b/stacks/dockhand/.env.example @@ -0,0 +1 @@ +DOCKHAND_DOMAIN= \ No newline at end of file diff --git a/stacks/dockhand/docker-compose.yaml b/stacks/dockhand/docker-compose.yaml new file mode 100644 index 0000000..07b3f69 --- /dev/null +++ b/stacks/dockhand/docker-compose.yaml @@ -0,0 +1,37 @@ +services: + dockhand: + image: fnsys/dockhand@sha256:546e7ab26146a64fe93f5f421d3f73914f495a84bfdb87bc3ff3a199388f44a2 + container_name: dockhand + restart: unless-stopped + env_file: + - .env + environment: + - ENCRYPTION_KEY_PATH=/run/secrets/encryption_key + - DISABLE_LOCAL_LOGIN=true + networks: + - homelab_apps + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - dockhand_data:/app/data + secrets: + - encryption_key + labels: + - "traefik.enable=true" + - "traefik.docker.network=homelab_apps" + - "traefik.http.routers.dockhand.rule=Host(`${DOCKHAND_DOMAIN}`)" + - "traefik.http.routers.dockhand.entrypoints=websecure" + - "traefik.http.routers.dockhand.tls=true" + - "traefik.http.routers.dockhand.tls.certresolver=le" + - "traefik.http.services.dockhand.loadbalancer.server.port=3000" + +volumes: + dockhand_data: + driver: local + +networks: + homelab_apps: + external: true + +secrets: + encryption_key: + file: ./secrets/dockhand_encryption_key.txt \ No newline at end of file diff --git a/stacks/gitea/.env.example b/stacks/gitea/.env.example new file mode 100644 index 0000000..ef11cc6 --- /dev/null +++ b/stacks/gitea/.env.example @@ -0,0 +1 @@ +GITEA_DOMAIN= \ No newline at end of file diff --git a/stacks/gitea/docker-compose.yaml b/stacks/gitea/docker-compose.yaml new file mode 100644 index 0000000..62543b8 --- /dev/null +++ b/stacks/gitea/docker-compose.yaml @@ -0,0 +1,89 @@ +services: + server: + image: gitea/gitea@sha256:1926e89ad28358ef2146bb8a1b9c3ba24bae681cb02b72d2df11125fdc675abe + container_name: gitea + restart: unless-stopped + depends_on: + db: + condition: service_healthy + env_file: + - .env + environment: + - GITEA__database__DB_TYPE=postgres + - GITEA__database__HOST=db:5432 + - GITEA__database__NAME=gitea + - GITEA__database__USER=gitea + - GITEA__database__PASSWD_FILE=/run/secrets/gitea_db_password + + - GITEA__server__DOMAIN=${GITEA_DOMAIN} + - GITEA__server__ROOT_URL=https://${GITEA_DOMAIN} + - GITEA__server__SSH_PORT=2222 + - GITEA__server__SSH_LISTEN_PORT=2222 + + - GITEA__service__DISABLE_REGISTRATION=true + - GITEA__service__ENABLE_BASIC_AUTHENTICATION=false + - GITEA__service__ENABLE_PASSWORD_SIGNIN_FORM=false + - GITEA__service__ENABLE_PASSKEY_AUTHENTICATION=false + - GITEA__openid__ENABLE_OPENID_SIGNIN=false + - GITEA__openid__ENABLE_OPENID_SIGNUP=false + networks: + - homelab_apps + - gitea_db_net + ports: + - "2222:2222" + volumes: + - gitea_data:/var/lib/gitea + - gitea_config:/etc/gitea + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + secrets: + - gitea_db_password + labels: + - traefik.enable=true + - traefik.docker.network=homelab_apps + - traefik.http.routers.gitea.rule=Host(`${GITEA_DOMAIN}`) + - traefik.http.routers.gitea.entrypoints=websecure + - traefik.http.routers.gitea.tls=true + - traefik.http.routers.gitea.tls.certresolver=le + - traefik.http.services.gitea.loadbalancer.server.port=3000 + + db: + image: postgres@sha256:035b9ab53cfa147d7202b61f5f7782b939ae815b7d6bc81c96b7b42ff1fca950 + container_name: gitea_db + restart: unless-stopped + environment: + - POSTGRES_DB=gitea + - POSTGRES_USER=gitea + - POSTGRES_PASSWORD_FILE=/run/secrets/gitea_db_password + networks: + - gitea_db_net + volumes: + - gitea_db_data:/var/lib/postgresql + secrets: + - gitea_db_password + healthcheck: + interval: 30s + retries: 5 + start_period: 20s + test: + - CMD-SHELL + - pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER} + timeout: 5s + +volumes: + gitea_data: + driver: local + gitea_config: + driver: local + gitea_db_data: + driver: local + +networks: + homelab_apps: + external: true + gitea_db_net: + internal: true + +secrets: + gitea_db_password: + file: ./secrets/gitea_db_password.txt \ No newline at end of file diff --git a/stacks/homepage/.env.example b/stacks/homepage/.env.example new file mode 100644 index 0000000..abe2277 --- /dev/null +++ b/stacks/homepage/.env.example @@ -0,0 +1 @@ +HOMEPAGE_DOMAIN= \ No newline at end of file diff --git a/stacks/homepage/docker-compose.yaml b/stacks/homepage/docker-compose.yaml new file mode 100644 index 0000000..f7b666c --- /dev/null +++ b/stacks/homepage/docker-compose.yaml @@ -0,0 +1,30 @@ +services: + homepage: + image: ghcr.io/gethomepage/homepage:v1.10.1@sha256:4815be05c8abf3503272b7ff1ac40c5f7364602a1ed807b0fc5a4cf69df0b15b + container_name: homepage + restart: unless-stopped + env_file: + - .env + environment: + - HOMEPAGE_ALLOWED_HOSTS=${HOMEPAGE_DOMAIN} + networks: + - homelab_apps + volumes: + - ./config:/app/config + labels: + - "traefik.enable=true" + - "traefik.docker.network=homelab_apps" + - "traefik.http.routers.homepage.rule=Host(`${HOMEPAGE_DOMAIN}`)" + - "traefik.http.routers.homepage.entrypoints=websecure" + - "traefik.http.routers.homepage.tls=true" + - "traefik.http.routers.homepage.tls.certresolver=le" + - "traefik.http.services.homepage.loadbalancer.server.port=3000" + + - "traefik.http.middlewares.authentik.forwardauth.address=http://authentik-server-1:9000/outpost.goauthentik.io/auth/traefik" + - "traefik.http.middlewares.authentik.forwardauth.trustForwardHeader=true" + - "traefik.http.middlewares.authentik.forwardauth.authResponseHeaders=X-authentik-username,X-authentik-groups,X-authentik-entitlements,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" + - "traefik.http.routers.homepage.middlewares=authentik" + +networks: + homelab_apps: + external: true \ No newline at end of file diff --git a/stacks/proxy/.env.example b/stacks/proxy/.env.example new file mode 100644 index 0000000..6b968d0 --- /dev/null +++ b/stacks/proxy/.env.example @@ -0,0 +1 @@ +ACME_EMAIL= \ No newline at end of file diff --git a/stacks/proxy/docker-compose.yaml b/stacks/proxy/docker-compose.yaml new file mode 100644 index 0000000..c16f3f8 --- /dev/null +++ b/stacks/proxy/docker-compose.yaml @@ -0,0 +1,53 @@ +services: + tunnel: + image: cloudflare/cloudflared:2026.2.0@sha256:09b8ae19c02e44c075361a64094e6216421672705647b0e8d4ce8d1d8feea7ac + restart: unless-stopped + command: tunnel --no-autoupdate run + environment: + - TUNNEL_TOKEN_FILE=/run/secrets/tunnel_token + networks: + - homelab_proxy + secrets: + - tunnel_token + + traefik: + image: traefik:v3.6.8@sha256:daf5df7f7b96cd34a1a499a275cb93c8dbc4ce58d49f98911e0583ba41cc4351 + restart: unless-stopped + command: + - --providers.docker=true + - --providers.docker.exposedbydefault=false + - --entrypoints.websecure.address=:443 + - --entrypoints.websecure.http.tls=true + + - --certificatesresolvers.le.acme.email=${ACME_EMAIL} + - --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json + - --certificatesresolvers.le.acme.dnschallenge=true + - --certificatesresolvers.le.acme.dnschallenge.provider=cloudflare + env_file: + - .env + environment: + - CF_DNS_API_TOKEN_FILE=/run/secrets/cf_api_token + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + - letsencrypt:/letsencrypt + networks: + - homelab_proxy + - homelab_apps + secrets: + - cf_api_token + +volumes: + letsencrypt: + driver: local + +networks: + homelab_proxy: + external: true + homelab_apps: + external: true + +secrets: + tunnel_token: + file: ./secrets/tunnel_token.txt + cf_api_token: + file: ./secrets/cf_api_token.txt \ No newline at end of file