Skip to content

Instantly share code, notes, and snippets.

@brettinternet
Last active December 31, 2023 15:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save brettinternet/5c9ac8e235cf2860bb34e0427760af7f to your computer and use it in GitHub Desktop.
Save brettinternet/5c9ac8e235cf2860bb34e0427760af7f to your computer and use it in GitHub Desktop.
docker-compose example with SOPS secrets, multi-domain Traefik, Cloudflare DNS and Cloudflare tunnel
---
x-service: &service
networks: [default]
environment: &environment
TZ: "${TIMEZONE}"
deploy:
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 45s
networks:
default:
ipam:
driver: default
config:
- subnet: 192.168.0.0/24
services:
diun:
<<: *service
image: crazymax/diun:latest
depends_on: [socket-proxy]
command: serve
environment:
<<: *environment
LOG_LEVEL: info
LOG_JSON: "false"
DIUN_WATCH_WORKERS: 20
DIUN_WATCH_SCHEDULE: 0 */6 * * *
DIUN_WATCH_JITTER: 30s
DIUN_PROVIDERS_DOCKER: "true"
DIUN_PROVIDERS_DOCKER_WATCHBYDEFAULT: "true"
DIUN_PROVIDERS_DOCKER_ENDPOINT: tcp://socket-proxy:2375
DIUN_NOTIF_NTFY_ENDPOINT: http://ntfy
DIUN_NOTIF_NTFY_TOKEN: "${NTFY_DIUN_TOKEN}"
DIUN_NOTIF_NTFY_TOPIC: homelab
socket-proxy:
<<: *service
image: tecnativa/docker-socket-proxy:latest
environment:
<<: *environment
CONTAINERS: 1
IMAGES: 1
NETWORKS: 1
CONTAINERS_CREATE: 1
CONTAINERS_START: 1
CONTAINERS_UPDATE: 1
CONTAINERS_DELETE: 1
IMAGES_DELETE: 1
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
cloudflared-tunnel:
<<: *service
image: cloudflare/cloudflared:2023.10.0
environment:
<<: *environment
NO_AUTOUPDATE: "true"
NO_TLS_VERIFY: "true"
TUNNEL_TOKEN: "${CLOUDFLARE_TUNNEL_TOKEN:?err}"
TUNNEL_URL: https://traefik
TUNNEL_ID: "${CLOUDFLARE_TUNNEL_ID}"
command: [tunnel, run]
traefik:
<<: *service
image: traefik:v2.10
depends_on: [socket-proxy]
environment:
<<: *environment
CF_DNS_API_TOKEN: "${CLOUDFLARE_API_TOKEN:?err}"
CLOUDFLARE_POLLING_INTERVAL: 10
CLOUDFLARE_PROPAGATION_TIMEOUT: 300
ports:
- 80:80
- 443:443
volumes:
- "${CONFIG_DIR}/traefik:/etc/traefik"
command:
- --log.level=DEBUG
- --api=true
- --providers.docker=true
- --providers.docker.endpoint=tcp://socket-proxy:2375
- --providers.docker.exposedbydefault=false
- --entrypoints.web.address=:80
- --entrypoints.web.http.redirections.entrypoint.to=websecure
- --entrypoints.web.http.redirections.entrypoint.scheme=https
- --entrypoints.websecure.address=:443
- --entrypoints.websecure.http.tls.certResolver=leresolver
- --entrypoints.websecure.http.tls.domains[0].main=${PUBLIC_DOMAIN}
- --entrypoints.websecure.http.tls.domains[0].sans=*.${PUBLIC_DOMAIN}
- --entrypoints.websecure.http.tls.domains[1].main=${PRIVATE_DOMAIN}
- --entrypoints.websecure.http.tls.domains[1].sans=*.${PRIVATE_DOMAIN}
- --certificatesresolvers.leresolver.acme.dnschallenge=true
- --certificatesresolvers.leresolver.acme.dnschallenge.disablepropagationcheck=true # for internal domain
- --certificatesresolvers.leresolver.acme.dnschallenge.provider=cloudflare
- --certificatesresolvers.leresolver.acme.dnschallenge.resolvers=1.1.1.1:53
- --certificatesresolvers.leresolver.acme.storage=/etc/traefik/acme.json
- --certificatesresolvers.leresolver.acme.email=${ACME_EMAIL}
# - --certificatesresolvers.leresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
labels:
traefik.enable: "true"
traefik.http.routers.traefik.rule: Host(`traefik.${PRIVATE_DOMAIN}`)
traefik.http.routers.traefik.service: api@internal
traefik.http.routers.traefik.entrypoints: websecure
traefik.http.routers.traefik.middlewares: hsts-header, ipallowlist
traefik.http.middlewares.ipallowlist.ipwhitelist.sourcerange: "${IPALLOWLIST:-0.0.0.0/0,::/0}"
traefik.http.middlewares.hsts-header.headers.customResponseHeaders.Strict-Transport-Security: max-age=63072000
cloudflare-companion:
<<: *service
image: tiredofit/traefik-cloudflare-companion:latest
depends_on: [socket-proxy]
environment:
<<: *environment
DOCKER_HOST: tcp://socket-proxy:2375
TIMEZONE: "${TIMEZONE}"
TRAEFIK_VERSION: 2
CF_TOKEN: "${CLOUDFLARE_API_TOKEN:?err}"
TARGET_DOMAIN: "tunnel.${PUBLIC_DOMAIN}"
DOMAIN1: "${PUBLIC_DOMAIN}"
DOMAIN1_ZONE_ID: "${CLOUDFLARE_PUBLIC_DOMAIN_ZONE_ID}"
DOMAIN1_PROXIED: "true"
# public services
ntfy:
<<: *service
image: binwiederhier/ntfy:latest
environment:
<<: *environment
NTFY_UPSTREAM_BASE_URL: https://ntfy.sh
NTFY_BEHIND_PROXY: "true"
NTFY_AUTH_FILE: /var/lib/ntfy/auth.db
NTFY_CACHE_FILE: /var/lib/ntfy/cache.db
NTFY_AUTH_DEFAULT_ACCESS: deny-all
NTFY_BASE_URL: "https://ntfy.${PUBLIC_DOMAIN}"
NTFY_ENABLE_LOGIN: "true"
command: [serve]
volumes:
- "${CONFIG_DIR}/ntfy:/var/lib/ntfy"
labels:
traefik.enable: "true"
traefik.http.routers.ntfy.rule: Host(`ntfy.${PUBLIC_DOMAIN}`)
traefik.http.routers.ntfy.entrypoints: websecure
traefik.http.services.ntfy.loadbalancer.server.port: 80
cgit:
<<: *service
image: ghcr.io/brettinternet/cgit:latest
environment:
<<: *environment
ROOT_TITLE: "git.${PUBLIC_DOMAIN}"
ROOT_DESC: Source code of various projects
ROOT_README: /srv/git/README.md
SECTION_FROM_STARTPATH: 1
NOPLAINEMAIL: 1
volumes:
- "${CONFIG_DIR}/git:/srv/git"
labels:
traefik.enable: "true"
traefik.http.routers.cgit.middlewares: hsts-header
traefik.http.routers.cgit.rule: Host(`git.${PUBLIC_DOMAIN}`)
traefik.http.routers.cgit.entrypoints: websecure
traefik.http.services.cgit.loadbalancer.server.port: 80
# encrypt with sops --encrypt --in-place sops.env
TIMEZONE=America/New_York
NTFY_DIUN_TOKEN=
CONFIG_DIR=/mnt/tank
PRIVATE_DOMAIN=myinternaldomain.net
PUBLIC_DOMAIN=mypublicsite.com
CLOUDFLARE_TUNNEL_ID=
CLOUDFLARE_API_TOKEN=
CLOUDFLARE_PUBLIC_DOMAIN_ZONE_ID=
ACME_EMAIL=hello@mypublicsite.com
IPALLOWLIST=192.168.0.0/24
# install go-task
---
version: "3"
vars:
PROJECT: myproject
SECRETS_FILE: sops.env
COMPOSE_FILES:
sh: find . -type f -iname "compose*.yaml" -exec basename {} ';' | sort -r
COMPOSE_FILES_ARGS: -f {{ .COMPOSE_FILES | splitLines | join " -f " }}
COMPOSE_COMMAND: docker-compose -p {{ .PROJECT }} {{ .COMPOSE_FILES_ARGS }}
env:
COMPOSE_PROJECT: \{{ .PROJECT }}
COMPOSE_PROFILES: myprofile,anotherprofile
DOCKER_HOST: ssh://myremotehost
tasks:
up:
desc: Deploy compose files; This targets a single node 'DOCKER_HOST' or locahost.
cmds:
- sops exec-env {{ .SECRETS_FILE }} '{{ .COMPOSE_COMMAND }} up -d --remove-orphans'
requires:
vars: [SECRETS_FILE]
stop:
desc: Stop compose containers on host
cmds:
- sops exec-env {{ .SECRETS_FILE }} '{{ .COMPOSE_COMMAND }} down --remove-orphans'
requires:
vars: [SECRETS_FILE]
down:
desc: Stop and clean up containers on host
cmds:
- sops exec-env {{ .SECRETS_FILE }} '{{ .COMPOSE_COMMAND }} down --remove-orphans --rmi all'
requires:
vars: [SECRETS_FILE]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment