## Please email lab@seedno.de with any questions about this file, or setting up any services therein ## The actual files are not a monolith like this one; this page is generated as a convenient reference ## The following variables should be set in a file named .env in the same directory as docker-compose.yml (alter as needed): # - CLOUDFLARE_API_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # - TIMEZONE=America/Chicago # - UID=1000 # - GID=1000 services: ### https://github.com/traefik/traefik ## Files for basicauth middleware should be generated with the following: # $ htpasswd -c "${filename}" "${username}" traefik: image: traefik:latest container_name: traefik restart: unless-stopped environment: - "CF_DNS_API_TOKEN=${CLOUDFLARE_API_TOKEN}" - "TZ=${TIMEZONE:?not set}" command: - "--accesslog=true" - "--accesslog.bufferingsize=100" - "--accesslog.fields.names.StartUTC=drop" - "--accesslog.filepath=/var/log/access.log" - "--api" - "--certificatesresolvers.letsencrypt.acme.dnschallenge=true" - "--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=cloudflare" - "--certificatesresolvers.letsencrypt.acme.dnschallenge.resolvers=1.1.1.1:53" - "--certificatesresolvers.letsencrypt.acme.storage=/certs/acme.json" - "--entrypoints.http-private.address=:1080" - "--entrypoints.http-private.http.redirections.entrypoint.scheme=https" - "--entrypoints.http-private.http.redirections.entryPoint.to=https-private" - "--entrypoints.https-private.address=:1443" - "--entrypoints.https-private.http3" - "--entrypoints.https-private.http3.advertisedport=443" - "--entrypoints.http-public.address=:2080" - "--entrypoints.http-public.http.redirections.entrypoint.scheme=https" - "--entrypoints.http-public.http.redirections.entryPoint.to=https-public" - "--entrypoints.https-public.address=:2443" - "--entrypoints.https-public.http3" - "--entrypoints.https-public.http3.advertisedport=443" - "--log.filePath=/var/log/traefik.log" - "--log.level=ERROR" - "--providers.docker=true" - "--providers.docker.exposedByDefault=false" - "--providers.file.directory=/conf" - "--providers.file.watch=true" - "--providers.providersThrottleDuration=1s" labels: - "traefik.enable=true" - "traefik.http.routers.traefik.rule=Host(`dashboard.seedno.de`)" - "traefik.http.routers.traefik.entrypoints=https-public" - "traefik.http.routers.traefik.service=api@internal" - "traefik.http.routers.traefik.tls=true" - "traefik.http.routers.traefik.tls.certresolver=letsencrypt" - "traefik.http.routers.traefik.middlewares=adminauth@file,compress@file,secure@file" ports: - "${PUBLIC_IP:?not set}:80:2080" - "${PUBLIC_IP:?not set}:443:2443" - "${PUBLIC_IP:?not set}:443:2443/udp" - "${TAILSCALE_IP:?not set}:80:1080" - "${TAILSCALE_IP:?not set}:443:1443" - "${TAILSCALE_IP:?not set}:443:1443/udp" networks: - traefik - asciinema - audio - code-server - cyberchef - naughty - nginx - query - random - registry - roulette - thelounge - trivia - vaultwarden - whoami volumes: - type: bind source: /docker/traefik/certs target: /certs - type: bind source: /docker/traefik/config target: /conf read_only: true - type: bind source: /docker/traefik/logs target: /var/log - type: bind source: /var/run/docker.sock target: /var/run/docker.sock read_only: true ### https://github.com/asciinema/asciinema-server asciinema: image: ghcr.io/asciinema/asciinema-server:latest container_name: asciinema restart: unless-stopped depends_on: - asciinema-db environment: - "CONTACT_EMAIL_ADDRESS=asciinema@seedno.de" - "DATABASE_URL=postgresql://${ASCIINEMA_DATABASE_USER:?not set}:${ASCIINEMA_DATABASE_PASS:?not set}@asciinema-db:5432/${ASCIINEMA_DATABASE_NAME:?not set}" - "SECRET_KEY_BASE=${ASCIINEMA_SECRET_KEY_BASE:?not set}" - "UNCLAIMED_RECORDING_TTL=7" - "UPLOAD_SIZE_LIMIT=16000000" - "URL_HOST=ascii.seedno.de" - "URL_SCHEME=https" labels: - "traefik.enable=true" - "traefik.http.middlewares.asciinema.headers.contentSecurityPolicy=default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'" - "traefik.http.routers.asciinema.rule=Host(`ascii.seedno.de`)" - "traefik.http.routers.asciinema.entrypoints=https-public" - "traefik.http.routers.asciinema.service=asciinema" - "traefik.http.routers.asciinema.tls=true" - "traefik.http.routers.asciinema.tls.certresolver=letsencrypt" - "traefik.http.routers.asciinema.middlewares=compress@file,asciinema,secure@file" - "traefik.http.services.asciinema.loadbalancer.server.port=4000" - "traefik.http.routers.asciinema-admin.rule=Host(`admin.ascii.seedno.de`)" - "traefik.http.routers.asciinema-admin.entrypoints=https-private" - "traefik.http.routers.asciinema-admin.service=asciinema-admin" - "traefik.http.routers.asciinema-admin.tls=true" - "traefik.http.routers.asciinema-admin.tls.certresolver=letsencrypt" - "traefik.http.routers.asciinema-admin.middlewares=allowlist@file,compress@file,asciinema,secure@file" - "traefik.http.services.asciinema-admin.loadbalancer.server.port=4002" networks: - asciinema - asciinema-db volumes: - type: bind source: /docker/asciinema/data target: /var/opt/asciinema asciinema-db: image: postgres:16-alpine container_name: asciinema-db restart: unless-stopped environment: - "POSTGRES_DB=${ASCIINEMA_DATABASE_NAME:?not set}" - "POSTGRES_USER=${ASCIINEMA_DATABASE_USER:?not set}" - "POSTGRES_PASSWORD=${ASCIINEMA_DATABASE_PASS:?not set}" networks: - asciinema-db volumes: - type: bind source: /docker/asciinema/database target: /var/lib/postgresql/data ### https://github.com/Seednode/roulette audio: image: oci.seedno.de/seednode/roulette:latest container_name: audio restart: unless-stopped environment: - "ROULETTE_AUDIO=true" - "ROULETTE_DEBUG=true" - "ROULETTE_PREFIX=/random/" - "ROULETTE_RECURSIVE=true" - "ROULETTE_VERBOSE=true" - "TZ=${TIMEZONE:?not set}" command: - "/data" labels: - "traefik.enable=true" - "traefik.http.middlewares.audio.headers.contentSecurityPolicy=default-src 'self'" - "traefik.http.routers.audio.rule=Host(`voice.seedno.de`) && PathPrefix(`/random`)" - "traefik.http.routers.audio.entrypoints=https-public" - "traefik.http.routers.audio.service=audio" - "traefik.http.routers.audio.tls=true" - "traefik.http.routers.audio.tls.certresolver=letsencrypt" - "traefik.http.routers.audio.middlewares=audio,compress@file,secure@file" - "traefik.http.services.audio.loadbalancer.server.port=8080" networks: - audio volumes: - type: bind source: /home/sinc/media/html/voice.seedno.de target: /data read_only: true ### https://github.com/coder/code-server code-server: image: lscr.io/linuxserver/code-server:latest container_name: code-server restart: unless-stopped privileged: true environment: PUID: ${UID:?not set} PGID: ${GID:?not set} SUDO_PASSWORD: ${CODE_SUDO_PASSWORD:?not set} TZ: ${TIMEZONE:?not set} INSTALL_PACKAGES: "fsharp rust-src" DOCKER_MODS: "linuxserver/mods:code-server-dotnet|\ linuxserver/mods:code-server-extension-arguments|\ linuxserver/mods:code-server-golang|\ linuxserver/mods:code-server-nodejs|\ linuxserver/mods:code-server-powershell|\ linuxserver/mods:code-server-python3|\ linuxserver/mods:code-server-rust|\ linuxserver/mods:code-server-shellcheck|\ linuxserver/mods:code-server-zsh|\ linuxserver/mods:universal-package-install" VSCODE_EXTENSION_IDS: "bungcip.better-toml|\ coolbear.systemd-unit-file|\ dbaeumer.vscode-eslint|\ esbenp.prettier-vscode|\ golang.go|\ Ionide.Ionide-fsharp|\ mads-hartmann.bash-ide-vscode|\ ms-azuretools.vscode-docker|\ ms-dotnettools.csdevkit|\ ms-python.python|\ ms-vscode.PowerShell|\ muhammad-sammy.csharp|\ rust-lang.rust-analyzer|\ timonwong.shellcheck" labels: - "traefik.enable=true" - "traefik.http.middlewares.code-server.headers.contentSecurityPolicy=default-src 'self'; style-src 'self' 'unsafe-inline' https://*.vscode-cdn.net; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://*.vscode-cdn.net; img-src 'self' data: https://*.vscode-cdn.net; connect-src 'self' https://open-vsx.org" - "traefik.http.routers.code-server.rule=Host(`code.seedno.de`)" - "traefik.http.routers.code-server.entrypoints=https-public" - "traefik.http.routers.code-server.service=code-server" - "traefik.http.routers.code-server.tls=true" - "traefik.http.routers.code-server.tls.certresolver=letsencrypt" - "traefik.http.routers.code-server.middlewares=adminauth@file,code-server,compress@file,secure@file" - "traefik.http.services.code-server.loadbalancer.server.port=8443" networks: - code-server volumes: - type: bind source: /docker/code-server/config target: /config - type: bind source: /home/sinc/code target: /config/workspace/code - type: bind source: /home/sinc/trivia target: /config/workspace/trivia ### https://github.com/gchq/CyberChef cyberchef: image: mpepping/cyberchef:latest container_name: cyberchef restart: unless-stopped labels: - "traefik.enable=true" - "traefik.http.middlewares.cyberchef.headers.contentSecurityPolicy=default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; object-src 'self' data:; frame-src 'self' data:; worker-src 'self' blob: data:" - "traefik.http.routers.cyberchef.rule=Host(`tools.seedno.de`)" - "traefik.http.routers.cyberchef.entrypoints=https-public" - "traefik.http.routers.cyberchef.service=cyberchef" - "traefik.http.routers.cyberchef.tls=true" - "traefik.http.routers.cyberchef.tls.certresolver=letsencrypt" - "traefik.http.routers.cyberchef.middlewares=compress@file,cyberchef,secure@file" - "traefik.http.services.cyberchef.loadbalancer.server.port=8000" networks: - cyberchef ### https://github.com/Seednode/docker-site-naughty naughty: image: oci.seedno.de/seednode/naughty:latest container_name: naughty restart: unless-stopped labels: - "traefik.enable=true" - "traefik.http.routers.naughty.rule=PathPrefix(`/{path:.*(\\.env|\\.aws|xmlrpc|wp-admin|wp-login).*}`)" - "traefik.http.routers.naughty.priority=254" - "traefik.http.routers.naughty.entrypoints=https-public" - "traefik.http.routers.naughty.service=naughty" - "traefik.http.routers.naughty.tls=true" - "traefik.http.routers.naughty.tls.certresolver=letsencrypt" - "traefik.http.routers.naughty.middlewares=compress@file,secure@file" - "traefik.http.services.naughty.loadbalancer.server.port=8080" networks: - naughty ### https://github.com/Seednode/docker-nginx ## All my sites are configured via the file provider ## An example is available here: ## https://cdn.seedno.de/txt/access.seedno.de.yaml nginx: image: oci.seedno.de/seednode/nginx:latest container_name: nginx restart: unless-stopped networks: - nginx volumes: - type: bind source: /docker/nginx/config target: /etc/nginx read_only: true - type: bind source: /docker/nginx/logs target: /var/log/nginx - type: bind source: /home/sinc/media/html target: /var/www/html read_only: true ### https://github.com/Seednode/query query: image: oci.seedno.de/seednode/query:latest container_name: query restart: unless-stopped environment: - "QUERY_ALL=true" - "QUERY_DNS_RESOLVER=1.1.1.1:53" - "QUERY_MAX_DICE_ROLLS=1024" - "QUERY_MAX_DICE_SIDES=1024" - "QUERY_QR_SIZE=512" - "QUERY_VERBOSE=true" - "TZ=${TIMEZONE:?not set}" labels: - "traefik.enable=true" - "traefik.http.middlewares.query.headers.contentSecurityPolicy=default-src 'self'" - "traefik.http.routers.query.rule=Host(`q.seedno.de`) || Host(`justinsinkula.com`)" - "traefik.http.routers.query.entrypoints=https-public" - "traefik.http.routers.query.service=query" - "traefik.http.routers.query.tls=true" - "traefik.http.routers.query.tls.certresolver=letsencrypt" - "traefik.http.routers.query.middlewares=compress@file,query,ratelimit@file,secure@file" - "traefik.http.services.query.loadbalancer.server.port=8080" networks: - query ### https://github.com/Seednode/roulette random: image: oci.seedno.de/seednode/roulette:latest container_name: random restart: unless-stopped environment: - "ROULETTE_ALL=true" - "ROULETTE_DEBUG=true" - "ROULETTE_PREFIX=/random/" - "ROULETTE_RECURSIVE=true" - "ROULETTE_VERBOSE=true" - "TZ=${TIMEZONE:?not set}" command: - "/data" labels: - "traefik.enable=true" - "traefik.http.middlewares.random.headers.contentSecurityPolicy=default-src 'self'" - "traefik.http.routers.random.rule=Host(`cdn.seedno.de`) && PathPrefix(`/random`)" - "traefik.http.routers.random.entrypoints=https-public" - "traefik.http.routers.random.service=random" - "traefik.http.routers.random.tls=true" - "traefik.http.routers.random.tls.certresolver=letsencrypt" - "traefik.http.routers.random.middlewares=compress@file,random,secure@file" - "traefik.http.services.random.loadbalancer.server.port=8080" networks: - random volumes: - type: bind source: /home/sinc/media/html/cdn.seedno.de target: /data read_only: true ### https://hub.docker.com/_/registry registry: image: registry:2 container_name: registry restart: unless-stopped environment: - "REGISTRY_HTTP_ADDR=0.0.0.0:5000" - "REGISTRY_HTTP_SECRET=${REGISTRY_SECRET:?not set}" labels: - "traefik.enable=true" - "traefik.http.routers.registry.rule=Host(`oci.seedno.de`)" - "traefik.http.routers.registry.entrypoints=https-private" - "traefik.http.routers.registry.service=registry" - "traefik.http.routers.registry.tls=true" - "traefik.http.routers.registry.tls.certresolver=letsencrypt" - "traefik.http.routers.registry.middlewares=allowlist@file,compress@file,secure@file" - "traefik.http.services.registry.loadbalancer.server.port=5000" networks: - registry volumes: - type: bind source: /docker/registry/config/config.yml target: /etc/docker/registry/config.yml read_only: true - type: bind source: /docker/registry/data target: /var/lib/registry ### https://github.com/Seednode/roulette roulette: image: oci.seedno.de/seednode/roulette:latest container_name: roulette restart: unless-stopped environment: - "ROULETTE_API=true" - "ROULETTE_DEBUG=true" - "ROULETTE_FILTER=true" - "ROULETTE_IGNORE=.roulette_ignore" - "ROULETTE_IMAGES=true" - "ROULETTE_INDEX=true" - "ROULETTE_INDEX_FILE=/index/index.zstd" - "ROULETTE_INDEX_INTERVAL=1h" - "ROULETTE_MAX_FILES=8" - "ROULETTE_OVERRIDE=.roulette_override" - "ROULETTE_PROFILE=true" - "ROULETTE_RECURSIVE=true" - "ROULETTE_REFRESH=true" - "ROULETTE_SORT=true" - "ROULETTE_VERBOSE=true" - "ROULETTE_VIDEO=true" - "TZ=${TIMEZONE:?not set}" command: - "/data" labels: - "traefik.enable=true" - "traefik.http.routers.roulette.rule=Host(`roulette.seedno.de`)" - "traefik.http.routers.roulette.entrypoints=https-private" - "traefik.http.routers.roulette.service=roulette" - "traefik.http.routers.roulette.tls=true" - "traefik.http.routers.roulette.tls.certresolver=letsencrypt" - "traefik.http.routers.roulette.middlewares=allowlist@file,compress@file,secure@file" - "traefik.http.services.roulette.loadbalancer.server.port=8080" networks: - roulette volumes: - type: bind source: /home/sinc/media/miscellaneous target: /data read_only: true - type: bind source: /docker/roulette/index target: /index ### https://github.com/thelounge/thelounge thelounge: image: lscr.io/linuxserver/thelounge:latest container_name: thelounge restart: unless-stopped environment: - "PUID=${UID:?not set}" - "PGID=${GID:?not set}" - "TZ=${TIMEZONE:?not set}" labels: - "traefik.enable=true" - "traefik.http.middlewares.thelounge.headers.contentSecurityPolicy=default-src 'self'; style-src 'self' 'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='" - "traefik.http.routers.thelounge.rule=Host(`chat.seedno.de`)" - "traefik.http.routers.thelounge.entrypoints=https-public" - "traefik.http.routers.thelounge.service=thelounge" - "traefik.http.routers.thelounge.tls=true" - "traefik.http.routers.thelounge.tls.certresolver=letsencrypt" - "traefik.http.routers.thelounge.middlewares=compress@file,secure@file,thelounge" - "traefik.http.services.thelounge.loadbalancer.server.port=9000" networks: - thelounge volumes: - type: bind source: /docker/thelounge/config target: /config ### https://github.com/Seednode/trivia trivia: image: oci.seedno.de/seednode/trivia:latest container_name: trivia restart: unless-stopped environment: - "TRIVIA_COLORS=/data/colors.txt" - "TRIVIA_HTML=true" - "TRIVIA_PROFILE=true" - "TRIVIA_RECURSIVE=true" - "TRIVIA_RELOAD=true" - "TRIVIA_RELOAD_INTERVAL=30m" - "TRIVIA_VERBOSE=true" - "TZ=${TIMEZONE:?not set}" command: - "/data/trivial-pursuit" labels: - "traefik.enable=true" - "traefik.http.routers.trivia.rule=Host(`trivia.seedno.de`)" - "traefik.http.routers.trivia.entrypoints=https-public" - "traefik.http.routers.trivia.service=trivia" - "traefik.http.routers.trivia.tls=true" - "traefik.http.routers.trivia.tls.certresolver=letsencrypt" - "traefik.http.routers.trivia.middlewares=compress@file,secure@file" - "traefik.http.services.trivia.loadbalancer.server.port=8080" networks: - trivia volumes: - type: bind source: /home/sinc/trivia target: /data read_only: true ### https://github.com/dani-garcia/vaultwarden vaultwarden: image: vaultwarden/server:alpine container_name: vaultwarden restart: unless-stopped depends_on: - vaultwarden-db environment: - "DATABASE_URL=postgresql://${VAULTWARDEN_DATABASE_USER:?not set}:${VAULTWARDEN_DATABASE_PASS:?not set}@vaultwarden-db:5432/${VAULTWARDEN_DATABASE_NAME:?not set}" - "DOMAIN=https://vault.seedno.de" - "WEBSOCKET_ENABLED=false" - "SIGNUPS_ALLOWED=true" - "INVITATIONS_ALLOWED=false" - "SHOW_PASSWORD_HINT=false" - "TRASH_AUTO_DELETE_DAYS=30" - "LOG_FILE=/data/vaultwarden.log" - "ROCKET_PORT=80" labels: - "traefik.enable=true" - "traefik.http.middlewares.vaultwarden.headers.contentSecurityPolicy=default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-eval'; img-src 'self' data:" - "traefik.http.routers.vaultwarden.rule=Host(`vault.seedno.de`)" - "traefik.http.routers.vaultwarden.entrypoints=https-private" - "traefik.http.routers.vaultwarden.service=vaultwarden" - "traefik.http.routers.vaultwarden.tls=true" - "traefik.http.routers.vaultwarden.tls.certresolver=letsencrypt" - "traefik.http.routers.vaultwarden.middlewares=compress@file,secure@file,vaultwarden" - "traefik.http.services.vaultwarden.loadbalancer.server.port=80" networks: - vaultwarden - vaultwarden-db volumes: - type: bind source: /docker/vaultwarden/data target: /data vaultwarden-db: image: postgres:16-alpine container_name: vaultwarden-db restart: unless-stopped environment: - "POSTGRES_DB=${VAULTWARDEN_DATABASE_NAME:?not set}" - "POSTGRES_USER=${VAULTWARDEN_DATABASE_USER:?not set}" - "POSTGRES_PASSWORD=${VAULTWARDEN_DATABASE_PASS:?not set}" networks: - vaultwarden-db volumes: - type: bind source: /docker/vaultwarden/database target: /var/lib/postgresql/data ### https://hub.docker.com/r/containous/whoami whoami: image: containous/whoami:latest container_name: whoami restart: unless-stopped labels: - "traefik.enable=true" - "traefik.http.middlewares.whoami.headers.contentSecurityPolicy=default-src 'self'" - "traefik.http.routers.whoami.rule=Host(`whoami.seedno.de`)" - "traefik.http.routers.whoami.entrypoints=https-public" - "traefik.http.routers.whoami.service=whoami" - "traefik.http.routers.whoami.tls=true" - "traefik.http.routers.whoami.tls.certresolver=letsencrypt" - "traefik.http.routers.whoami.middlewares=compress@file,ratelimit@file,secure@file,whoami" - "traefik.http.services.whoami.loadbalancer.server.port=80" networks: - whoami networks: traefik: name: traefik driver: bridge driver_opts: com.docker.network.bridge.name: traefik asciinema: name: asciinema driver: bridge driver_opts: com.docker.network.bridge.name: asciinema asciinema-db: name: asciinema-db driver: bridge driver_opts: com.docker.network.bridge.name: asciinema-db internal: true audio: name: audio driver: bridge driver_opts: com.docker.network.bridge.name: audio internal: true code-server: name: code-server driver: bridge driver_opts: com.docker.network.bridge.name: code-server cyberchef: name: cyberchef driver: bridge driver_opts: com.docker.network.bridge.name: cyberchef internal: true naughty: name: naughty driver: bridge driver_opts: com.docker.network.bridge.name: naughty internal: true nginx: name: nginx driver: bridge driver_opts: com.docker.network.bridge.name: nginx internal: true query: name: query driver: bridge driver_opts: com.docker.network.bridge.name: query random: name: random driver: bridge driver_opts: com.docker.network.bridge.name: random internal: true registry: name: registry driver: bridge driver_opts: com.docker.network.bridge.name: registry internal: true roulette: name: roulette driver: bridge driver_opts: com.docker.network.bridge.name: roulette internal: true thelounge: name: thelounge driver: bridge driver_opts: com.docker.network.bridge.name: thelounge trivia: name: trivia driver: bridge driver_opts: com.docker.network.bridge.name: trivia internal: true vaultwarden: name: vaultwarden driver: bridge driver_opts: com.docker.network.bridge.name: vaultwarden vaultwarden-db: name: vaultwarden-db driver: bridge driver_opts: com.docker.network.bridge.name: vaultwarden-db internal: true whoami: name: whoami driver: bridge driver_opts: com.docker.network.bridge.name: whoami internal: true