Initial stack: Caddy, Forgejo, Outline, Vaultwarden, Uptime Kuma, n8n
This commit is contained in:
commit
06f8e8812e
6 changed files with 401 additions and 0 deletions
165
compose.yml
Normal file
165
compose.yml
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
# ~$ selfhostedops — The €15/Month Self-Hosted Company Stack
|
||||
# Series A · Episode 1 — https://youtube.com/@selfhostedops
|
||||
#
|
||||
# One server. One file. Your whole company stack:
|
||||
# caddy reverse proxy + automatic HTTPS
|
||||
# forgejo git hosting + CI (also acts as SSO/OIDC provider)
|
||||
# outline team wiki (logs in via Forgejo SSO)
|
||||
# vaultwarden password manager (Bitwarden-compatible)
|
||||
# uptime-kuma monitoring + alerts
|
||||
# n8n automation hub
|
||||
# wg-easy WireGuard VPN (optional — start with: --profile vpn)
|
||||
# (full Netbird mesh gets its own episode)
|
||||
#
|
||||
# Quickstart:
|
||||
# 1. cp .env.example .env && edit it (domain, email, secrets)
|
||||
# 2. Point *.${DOMAIN} (wildcard A/AAAA record) at this server
|
||||
# 3. docker compose up -d
|
||||
#
|
||||
# Every image below is multi-arch (amd64 + arm64) — runs on a €14 ARM box.
|
||||
|
||||
name: selfhostedops-stack
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
internal:
|
||||
|
||||
volumes:
|
||||
caddy_data:
|
||||
caddy_config:
|
||||
forgejo_data:
|
||||
outline_data:
|
||||
outline_pg:
|
||||
vaultwarden_data:
|
||||
kuma_data:
|
||||
n8n_data:
|
||||
wg_data:
|
||||
|
||||
services:
|
||||
caddy:
|
||||
image: caddy:2-alpine
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "443:443/udp" # HTTP/3
|
||||
environment:
|
||||
DOMAIN: ${DOMAIN}
|
||||
ACME_EMAIL: ${ACME_EMAIL}
|
||||
volumes:
|
||||
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
||||
- caddy_data:/data
|
||||
- caddy_config:/config
|
||||
networks: [proxy]
|
||||
|
||||
forgejo:
|
||||
image: codeberg.org/forgejo/forgejo:11
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
USER_UID: "1000"
|
||||
USER_GID: "1000"
|
||||
FORGEJO__server__DOMAIN: git.${DOMAIN}
|
||||
FORGEJO__server__ROOT_URL: https://git.${DOMAIN}/
|
||||
FORGEJO__server__SSH_PORT: "2222"
|
||||
FORGEJO__service__DISABLE_REGISTRATION: "true"
|
||||
FORGEJO__openid__ENABLE_OPENID_SIGNIN: "false"
|
||||
ports:
|
||||
- "2222:22" # git over SSH
|
||||
volumes:
|
||||
- forgejo_data:/data
|
||||
networks: [proxy]
|
||||
|
||||
outline-postgres:
|
||||
image: postgres:16-alpine
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_USER: outline
|
||||
POSTGRES_PASSWORD: ${OUTLINE_PG_PASSWORD}
|
||||
POSTGRES_DB: outline
|
||||
volumes:
|
||||
- outline_pg:/var/lib/postgresql/data
|
||||
networks: [internal]
|
||||
|
||||
outline-redis:
|
||||
image: redis:7-alpine
|
||||
restart: unless-stopped
|
||||
networks: [internal]
|
||||
|
||||
outline:
|
||||
image: outlinewiki/outline:latest
|
||||
restart: unless-stopped
|
||||
depends_on: [outline-postgres, outline-redis]
|
||||
environment:
|
||||
URL: https://wiki.${DOMAIN}
|
||||
PORT: "3000"
|
||||
SECRET_KEY: ${OUTLINE_SECRET_KEY}
|
||||
UTILS_SECRET: ${OUTLINE_UTILS_SECRET}
|
||||
DATABASE_URL: postgres://outline:${OUTLINE_PG_PASSWORD}@outline-postgres:5432/outline
|
||||
PGSSLMODE: disable
|
||||
REDIS_URL: redis://outline-redis:6379
|
||||
FILE_STORAGE: local
|
||||
FILE_STORAGE_LOCAL_ROOT_DIR: /var/lib/outline/data
|
||||
FORCE_HTTPS: "false" # TLS terminates at caddy
|
||||
# --- SSO via your own Forgejo (set up the OAuth2 app first, see README) ---
|
||||
OIDC_CLIENT_ID: ${OUTLINE_OIDC_CLIENT_ID}
|
||||
OIDC_CLIENT_SECRET: ${OUTLINE_OIDC_CLIENT_SECRET}
|
||||
OIDC_AUTH_URI: https://git.${DOMAIN}/login/oauth/authorize
|
||||
OIDC_TOKEN_URI: https://git.${DOMAIN}/login/oauth/access_token
|
||||
OIDC_USERINFO_URI: https://git.${DOMAIN}/login/oauth/userinfo
|
||||
OIDC_LOGOUT_URI: https://git.${DOMAIN}/logout
|
||||
OIDC_DISPLAY_NAME: Forgejo
|
||||
OIDC_SCOPES: openid profile email
|
||||
volumes:
|
||||
- outline_data:/var/lib/outline/data
|
||||
networks: [proxy, internal]
|
||||
|
||||
vaultwarden:
|
||||
image: vaultwarden/server:latest
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
DOMAIN: https://vault.${DOMAIN}
|
||||
ADMIN_TOKEN: ${VAULTWARDEN_ADMIN_TOKEN}
|
||||
SIGNUPS_ALLOWED: "${VAULTWARDEN_SIGNUPS_ALLOWED:-true}" # set to false after your team joined!
|
||||
volumes:
|
||||
- vaultwarden_data:/data
|
||||
networks: [proxy]
|
||||
|
||||
uptime-kuma:
|
||||
image: louislam/uptime-kuma:1
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- kuma_data:/app/data
|
||||
networks: [proxy]
|
||||
|
||||
n8n:
|
||||
image: docker.n8n.io/n8nio/n8n:latest
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
N8N_HOST: n8n.${DOMAIN}
|
||||
N8N_PORT: "5678"
|
||||
N8N_PROTOCOL: https
|
||||
WEBHOOK_URL: https://n8n.${DOMAIN}/
|
||||
GENERIC_TIMEZONE: ${TZ:-Europe/Berlin}
|
||||
TZ: ${TZ:-Europe/Berlin}
|
||||
volumes:
|
||||
- n8n_data:/home/node/.n8n
|
||||
networks: [proxy]
|
||||
|
||||
# Optional starter VPN — enable with: docker compose --profile vpn up -d
|
||||
# (The proper Netbird mesh deployment is Episode 5.)
|
||||
wg-easy:
|
||||
image: ghcr.io/wg-easy/wg-easy:14
|
||||
profiles: [vpn]
|
||||
restart: unless-stopped
|
||||
cap_add: [NET_ADMIN, SYS_MODULE]
|
||||
sysctls:
|
||||
net.ipv4.ip_forward: 1
|
||||
net.ipv4.conf.all.src_valid_mark: 1
|
||||
environment:
|
||||
WG_HOST: vpn.${DOMAIN}
|
||||
PASSWORD_HASH: ${WGEASY_PASSWORD_HASH}
|
||||
ports:
|
||||
- "51820:51820/udp"
|
||||
volumes:
|
||||
- wg_data:/etc/wireguard
|
||||
networks: [proxy]
|
||||
Loading…
Add table
Add a link
Reference in a new issue