This place is not a place of honor... no highly esteemed deed is commemorated here... nothing valued is here.
What is here was dangerous and repulsive to us. This message is a warning about danger.
The danger is still present, in your time, as it was in ours.
The danger is unleashed only if you substantially disturb this place. This place is best shunned and left uninhabited.

## 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

## The firewall is configured as follows:

# Allow traffic from traefik to other containers
# $ sudo iptables -A DOCKER-USER -s 10.160.3.254/32 -d 10.160.0.0/22 -i br_traefik -o br_traefik -j ACCEPT

# Allow other containers to reply to traefik
# $ sudo iptables -A DOCKER-USER -s 10.160.0.0/22 -d 10.160.3.254/32 -i br_traefik -o br_traefik -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

# Block all other traffic between containers not sharing an internal network
# $ sudo iptables -A DOCKER-USER -i br_traefik -o br_traefik -j REJECT

version: "3.9"

services:

  ### https://github.com/traefik/traefik
  ## Files for basicauth middleware should be generated with the following:
  # $ htpasswd -c "${filename}" "${username}"
  traefik:
    image: traefik:v3.0
    container_name: traefik
    restart: unless-stopped
    environment:
      - "CF_DNS_API_TOKEN=${CLOUDFLARE_API_TOKEN:?not set}"
      - "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.address=:80"
      - "--entrypoints.http.http.redirections.entrypoint.to=https"
      - "--entrypoints.http.http.redirections.entrypoint.scheme=https"
      - "--entrypoints.https.address=:443"
      - "--entrypoints.https.http3"
      - "--entrypoints.metrics.address=:8082"
      - "--log.filePath=/var/log/traefik.log"
      - "--log.level=ERROR"
      - "--metrics.prometheus=true"
      - "--metrics.prometheus.addentrypointslabels=true"
      - "--metrics.prometheus.addserviceslabels=true"
      - "--metrics.prometheus.entrypoint=metrics"
      - "--providers.docker=true"
      - "--providers.docker.exposedByDefault=false"
      - "--providers.docker.network=traefik"
      - "--providers.file.directory=/conf"
      - "--providers.file.watch=true"
      - "--serverstransport.insecureskipverify=true"
    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.compress.compress=true"
      - "traefik.http.middlewares.contenttype.contenttype=true"
      - "traefik.http.middlewares.errors.errors.status=404,502,504"
      - "traefik.http.middlewares.errors.errors.service=errors"
      - "traefik.http.middlewares.errors.errors.query=/{status}.html"
      - "traefik.http.middlewares.adminauth.basicauth.usersfile=/conf/auth/admin"
      - "traefik.http.middlewares.familyauth.basicauth.usersfile=/conf/auth/family"
      - "traefik.http.middlewares.friendsauth.basicauth.usersfile=/conf/auth/friends"
      - "traefik.http.middlewares.ratelimit.ratelimit.average=3"
      - "traefik.http.middlewares.ratelimit.ratelimit.burst=1"
      - "traefik.http.middlewares.ratelimit.ratelimit.period=1"
      - "traefik.http.middlewares.ratelimit.ratelimit.sourcecriterion.requestheadername=X-Forwarded-For"
      - "traefik.http.middlewares.secure.headers.browserxssfilter=true"
      - "traefik.http.middlewares.secure.headers.contenttypenosniff=true"
      - "traefik.http.middlewares.secure.headers.customframeoptionsvalue=SAMEORIGIN"
      - "traefik.http.middlewares.secure.headers.customresponseheaders.Permissions-Policy=geolocation=(), midi=(), sync-xhr=(), microphone=(), camera=(), magnetometer=(), gyroscope=(), fullscreen=(), payment=()"
      - "traefik.http.middlewares.secure.headers.customresponseheaders.Server=GNU-Netcat/0.7.1"
      - "traefik.http.middlewares.secure.headers.customresponseheaders.X-Clacks-Overhead=GNU Terry Pratchett"
      - "traefik.http.middlewares.secure.headers.customrequestheaders.X-Forwarded-Proto=https"
      - "traefik.http.middlewares.secure.headers.forcestsheader=true"
      - "traefik.http.middlewares.secure.headers.framedeny=true"
      - "traefik.http.middlewares.secure.headers.referrerpolicy=strict-origin-when-cross-origin"
      - "traefik.http.middlewares.secure.headers.stsincludesubdomains=true"
      - "traefik.http.middlewares.secure.headers.stspreload=true"
      - "traefik.http.middlewares.secure.headers.stsseconds=63072000"
      - "traefik.http.routers.traefik.rule=Host(`dashboard.crimson.seedno.de`)"
      - "traefik.http.routers.traefik.entrypoints=https"
      - "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=contenttype,errors,whitelist-vpn@file"
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    networks:
      traefik:
        ipv4_address: 10.160.3.254
    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/cockroachdb/cockroach
  cockroach-db:
    image: cockroachdb/cockroach:latest-v22.2
    container_name: cockroach-db
    hostname: cockroach.crimson.seedno.de
    restart: unless-stopped
    command:
      - "start"
      - "--cache=.25"
      - "--max-sql-memory=.25"
      - "--join=cockroach.atom.seedno.de,cockroach.crimson.seedno.de,cockroach.nuc.seedno.de"
      - "--advertise-addr=cockroach.crimson.seedno.de:26357"
      - "--advertise-sql-addr=cockroach.crimson.seedno.de:26257"
      - "--cluster-name=logging"
      - "--certs-dir=/certs"
      - "--http-addr=0.0.0.0:8080"
      - "--listen-addr=0.0.0.0:26357"
      - "--sql-addr=0.0.0.0:26257"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.cockroachdb.rule=Host(`cockroach.crimson.seedno.de`)"
      - "traefik.http.routers.cockroachdb.entrypoints=https"
      - "traefik.http.routers.cockroachdb.service=cockroachdb"
      - "traefik.http.routers.cockroachdb.tls=true"
      - "traefik.http.routers.cockroachdb.tls.certresolver=letsencrypt"
      - "traefik.http.routers.cockroachdb.middlewares=compress,contenttype,errors,secure,whitelist-vpn@file"
      - "traefik.http.services.cockroachdb.loadbalancer.server.port=8080"
      - "traefik.http.services.cockroachdb.loadbalancer.server.scheme=https"
    ports:
      - "26257:26257"
      - "26357:26357"
    networks:
      - traefik
    volumes:
      - type: bind
        source: /docker/cockroachdb/certs
        target: /certs
        read_only: true
      - type: bind
        source: /docker/cockroachdb/data
        target: /cockroach/cockroach-data

  ### 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}
      DOCKER_MODS: "linuxserver/mods:code-server-dotnet|\
                    linuxserver/mods:code-server-extension-arguments|\
                    linuxserver/mods:code-server-golang|\
                    linuxserver/mods:code-server-java11|\
                    linuxserver/mods:code-server-nodejs|\
                    linuxserver/mods:code-server-php8|\
                    linuxserver/mods:code-server-powershell|\
                    linuxserver/mods:code-server-python3|\
                    linuxserver/mods:code-server-shellcheck|\
                    linuxserver/mods:code-server-terraform|\
                    linuxserver/mods:universal-docker-in-docker"
      VSCODE_EXTENSION_IDS: "coolbear.systemd-unit-file|\
                             dbaeumer.vscode-eslint|\
                             golang.go|\
                             mads-hartmann.bash-ide-vscode|\
                             ms-azuretools.vscode-docker|\
                             ms-python.python|\
                             ms-vscode.PowerShell|\
                             muhammad-sammy.csharp|\
                             esbenp.prettier-vscode|\
                             redhat.java|\
                             timonwong.shellcheck|\
                             bungcip.better-toml"
    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"
      - "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,compress,contenttype,secure,code-server"
      - "traefik.http.services.code-server.loadbalancer.server.port=8443"
    networks:
      - traefik
    volumes:
      - type: bind
        source: /docker/code-server/config
        target: /config
      - type: bind
        source: /home/sinc/code
        target: /config/workspace/code

  ### https://git.seedno.de/seednode/commands
  commands:
    image: oci.seedno.de/seednode/commands:latest
    container_name: commands
    restart: unless-stopped
    environment:
      - "TZ=${TIMEZONE:?not set}"
    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.commands.headers.contentSecurityPolicy=default-src 'self'; style-src 'self' 'unsafe-inline'"
      - "traefik.http.routers.commands.rule=Host(`commands.seedno.de`)"
      - "traefik.http.routers.commands.entrypoints=https"
      - "traefik.http.routers.commands.service=commands"
      - "traefik.http.routers.commands.tls=true"
      - "traefik.http.routers.commands.tls.certresolver=letsencrypt"
      - "traefik.http.routers.commands.middlewares=compress,errors,secure,commands,contenttype,whitelist-vpn@file"
      - "traefik.http.services.commands.loadbalancer.server.port=8080"
    networks:
      - traefik
    volumes:
      - type: bind
        source: /docker/commands/config
        target: /home/nonroot/.config/commands

  ### 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"
      - "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,contenttype,errors,secure,cyberchef"
      - "traefik.http.services.cyberchef.loadbalancer.server.port=8000"
    networks:
      - traefik

  ### https://github.com/dokuwiki/dokuwiki
  dokuwiki:
    image: lscr.io/linuxserver/dokuwiki:latest
    container_name: dokuwiki
    restart: always
    environment:
      - "PUID=${UID:?not set}"
      - "PGID=${GID:?not set}"
      - "TZ=${TIMEZONE:?not set}"
    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.dokuwiki.headers.contentSecurityPolicy=default-src 'self'"
      - "traefik.http.routers.dokuwiki.rule=Host(`wiki.seedno.de`)"
      - "traefik.http.routers.dokuwiki.entrypoints=https"
      - "traefik.http.routers.dokuwiki.service=dokuwiki"
      - "traefik.http.routers.dokuwiki.tls=true"
      - "traefik.http.routers.dokuwiki.tls.certresolver=letsencrypt"
      - "traefik.http.routers.dokuwiki.middlewares=compress,contenttype,errors,secure,dokuwiki"
      - "traefik.http.services.dokuwiki.loadbalancer.server.port=80"
    networks:
      - traefik
    volumes:
      - type: bind
        source: /docker/dokuwiki/config
        target: /config

  ### https://github.com/jgraph/drawio
  drawio:
    image: jgraph/drawio:latest
    container_name: drawio
    restart: always
    environment:
      - "KEYSTORE_PASS=${DRAWIO_KEYSTORE_PASS}"
      - "KEY_PASS=${DRAWIO_KEY_PASS}"
    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.drawio.headers.contentSecurityPolicy=default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self' https://www.draw.io/notifications"
      - "traefik.http.routers.drawio.rule=Host(`draw.seedno.de`)"
      - "traefik.http.routers.drawio.entrypoints=https"
      - "traefik.http.routers.drawio.service=drawio"
      - "traefik.http.routers.drawio.tls=true"
      - "traefik.http.routers.drawio.tls.certresolver=letsencrypt"
      - "traefik.http.routers.drawio.middlewares=compress,secure,drawio"
      - "traefik.http.services.drawio.loadbalancer.server.port=8080"
    networks:
      - traefik

  ### https://github.com/elastic/elasticsearch
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.3.3
    container_name: elasticsearch
    restart: unless-stopped
    environment:
      - "discovery.type=single-node"
      - "ES_JAVA_OPTS=-Xms1G -Xmx4G"
      - "xpack.security.enabled=false"
    networks:
      - elasticsearch
    volumes:
      - type: bind
        source: /docker/elasticsearch/data
        target: /usr/share/elasticsearch/data

  ### https://git.seedno.de/seednode/docker-site-errors
  errors:
    image: oci.seedno.de/seednode/errors:latest
    container_name: errors
    restart: unless-stopped
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.errors.entrypoints=http"
      - "traefik.http.services.errors.loadbalancer.server.port=8080"
    networks:
      - traefik

  ### https://github.com/go-gitea/gitea
  gitea:
    image: gitea/gitea:latest
    container_name: gitea
    restart: unless-stopped
    depends_on:
      - gitea-db
    environment:
      - "TMPDIR=/data/backups"
      - "USER_UID=${UID:?not set}"
      - "USER_GID=${GID:?not set}"
    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.gitea.headers.contentSecurityPolicy=default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; font-src 'self' data:; img-src 'self' https: data:; manifest-src 'self' data:"
      - "traefik.http.routers.gitea.rule=Host(`git.seedno.de`)"
      - "traefik.http.routers.gitea.entrypoints=https"
      - "traefik.http.routers.gitea.service=gitea"
      - "traefik.http.routers.gitea.tls=true"
      - "traefik.http.routers.gitea.tls.certresolver=letsencrypt"
      - "traefik.http.routers.gitea.middlewares=compress,contenttype,errors,secure,gitea"
      - "traefik.http.services.gitea.loadbalancer.server.port=3000"
    ports:
      - "9023:22"
    networks:
      - traefik
      - gitea
    volumes:
      - type: bind
        source: /docker/gitea/data
        target: /data
      - type: bind
        source: /etc/localtime
        target: /etc/localtime
        read_only: true
      - type: bind
        source: /docker/gitea/conf/sshd_config
        target: /etc/ssh/sshd_config
        read_only: true

  gitea-db:
    image: postgres:13-alpine
    container_name: gitea-db
    restart: unless-stopped
    environment:
      - "POSTGRES_DB=${GITEA_DATABASE_NAME:?not set}"
      - "POSTGRES_USER=${GITEA_DATABASE_USER:?not set}"
      - "POSTGRES_PASSWORD=${GITEA_DATABASE_PASS:?not set}"
    networks:
      - gitea
    volumes:
      - type: bind
        source: /docker/gitea/database
        target: /var/lib/postgresql/data

  ### https://github.com/grafana/grafana
  ## Set data source to "http://prometheus:9090"
  ## Run `chown -R 472:472 /docker/grafana` to fix permissions
  grafana-renderer:
    image: grafana/grafana-image-renderer:latest
    container_name: grafana-renderer
    restart: unless-stopped
    depends_on:
      - grafana
    environment:
      - "BROWSER_TZ=${TIMEZONE}"
      - "HTTP_HOST=0.0.0.0"
      - "HTTP_PORT=8081"
    networks:
      - grafana

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    restart: unless-stopped
    depends_on:
      - prometheus
    environment:
      - "GF_ALERTING_ENABLED=false"
      - "GF_AUTH_ANONYMOUS_ENABLED=false"
      - "GF_DEFAULT_INSTANCE_NAME=grafana.seedno.de"
      - "GF_INSTALL_PLUGINS=grafana-piechart-panel,grafana-clock-panel"
      - "GF_LOG_FILTERS=rendering:debug"
      - "GF_METRICS_ENABLED=true"
      - "GF_PATHS_TEMP_DATA_LIFETIME=0"
      - "GF_RENDERING_SERVER_URL=http://grafana-renderer:8081/render"
      - "GF_RENDERING_CALLBACK_URL=http://grafana:3000/"
      - "GF_SECURITY_COOKIE_SECURE=true"
      - "GF_SECURITY_DISABLE_GRAVATAR=true"
      - "GF_SECURITY_ALLOW_EMBEDDING=false"
      - "GF_SERVER_DOMAIN=grafana.seedno.de"
      - "GF_SERVER_ENFORCE_DOMAIN=true"
      - "GF_SERVER_HTTP_PORT=3000"
      - "GF_SERVER_HTTP_PROTOCOL=https"
      - "GF_SERVER_ROOT_URL=https://grafana.seedno.de/"
      - "GF_SERVER_SERVE_FROM_SUB_PATH=false"
      - "GF_SNAPSHOTS_EXTERNAL_ENABLED=false"
      - "GF_USERS_ALLOW_SIGN_UP=false"
      - "GF_USERS_VIEWERS_CAN_EDIT=false"
    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.grafana.headers.contentSecurityPolicy=default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src 'self' data:"
      - "traefik.http.routers.grafana.rule=Host(`grafana.seedno.de`)"
      - "traefik.http.routers.grafana.entrypoints=https"
      - "traefik.http.routers.grafana.service=grafana"
      - "traefik.http.routers.grafana.tls=true"
      - "traefik.http.routers.grafana.tls.certresolver=letsencrypt"
      - "traefik.http.routers.grafana.middlewares=compress,contenttype,errors,secure,grafana,whitelist-vpn@file"
      - "traefik.http.services.grafana.loadbalancer.server.port=3000"
    networks:
      - traefik
      - prometheus
      - grafana
    volumes:
      - type: bind
        source: /docker/grafana/data
        target: /var/lib/grafana

  ### https://github.com/toptal/haste-server
  hastebin:
    image: angristan/hastebin:latest
    container_name: hastebin
    restart: unless-stopped
    environment:
      - "UID=${UID:?not set}"
      - "GID=${GID:?not set}"
    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.hastebin.headers.contentSecurityPolicy=default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' ajax.googleapis.com"
      - "traefik.http.routers.hastebin.rule=Host(`paste.seedno.de`)"
      - "traefik.http.routers.hastebin.entrypoints=https"
      - "traefik.http.routers.hastebin.service=hastebin"
      - "traefik.http.routers.hastebin.tls=true"
      - "traefik.http.routers.hastebin.tls.certresolver=letsencrypt"
      - "traefik.http.routers.hastebin.middlewares=compress,contenttype,errors,secure,hastebin"
      - "traefik.http.services.hastebin.loadbalancer.server.port=7777"
    networks:
      - traefik
    volumes:
      - type: bind
        source: /docker/hastebin/data
        target: /app/data

  ### https://github.com/imgproxy/imgproxy
  imgproxy:
    image: darthsim/imgproxy:latest
    container_name: imgproxy
    restart: unless-stopped
    environment:
      - "IMGPROXY_KEY=${IMGPROXY_KEY:?not set}"
      - "IMGPROXY_SALT=${IMGPROXY_SALT:?not set}"
    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.imgproxy.headers.contentSecurityPolicy=default-src 'self'"
      - "traefik.http.routers.imgproxy.rule=Host(`imgproxy.seedno.de`)"
      - "traefik.http.routers.imgproxy.entrypoints=https"
      - "traefik.http.routers.imgproxy.service=imgproxy"
      - "traefik.http.routers.imgproxy.tls=true"
      - "traefik.http.routers.imgproxy.tls.certresolver=letsencrypt"
      - "traefik.http.routers.imgproxy.middlewares=compress,contenttype,errors,secure,imgproxy"
      - "traefik.http.services.imgproxy.loadbalancer.server.port=8080"
    networks:
      - traefik

  ## https://github.com/danmanners/memegen
  memegen:
    image: oci.seedno.de/seednode/memegen:latest
    container_name: memegen
    restart: unless-stopped
    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.memegen.headers.contentSecurityPolicy=default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'; img-src 'self' data: https://validator.swagger.io"
      - "traefik.http.routers.memegen.rule=Host(`memes.seedno.de`)"
      - "traefik.http.routers.memegen.entrypoints=https"
      - "traefik.http.routers.memegen.service=memegen"
      - "traefik.http.routers.memegen.tls=true"
      - "traefik.http.routers.memegen.tls.certresolver=letsencrypt"
      - "traefik.http.routers.memegen.middlewares=compress,contenttype,errors,secure,memegen"
      - "traefik.http.services.memegen.loadbalancer.server.port=5000"
    networks:
      - traefik

  ### https://github.com/minio/minio
  ## Set up minio-client alias
  # $ mc alias set minio https://minio.seedno.de  
  ## Generate JWT bearer token
  # $ mc admin prometheus generate minio
  minio:
    image: minio/minio:latest
    container_name: minio
    restart: unless-stopped
    command:
      - "server"
      - "/data"
      - "--console-address"
      - ":9001"
    environment:
      - "MINIO_BROWSER_REDIRECT_URL=https://console.minio.seedno.de"
      - "MINIO_PROMETHEUS_AUTH_TYPE=jwt"
      - "MINIO_PROMETHEUS_JOB_ID=minio-job"
      - "MINIO_PROMETHEUS_URL=http://prometheus:9090"
      - "MINIO_ROOT_USER=${MINIO_ROOT_USER:?not set}"
      - "MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASS:?not set}"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.minio-server.rule=Host(`s3.seedno.de`)"
      - "traefik.http.routers.minio-server.entrypoints=https"
      - "traefik.http.routers.minio-server.service=minio-server"
      - "traefik.http.routers.minio-server.tls=true"
      - "traefik.http.routers.minio-server.tls.certresolver=letsencrypt"
      - "traefik.http.routers.minio-server.middlewares=compress,contenttype,errors,secure"
      - "traefik.http.services.minio-server.loadbalancer.server.port=9000"
      - "traefik.http.routers.minio-console.rule=Host(`console.minio.seedno.de`)"
      - "traefik.http.routers.minio-console.entrypoints=https"
      - "traefik.http.routers.minio-console.service=minio-console"
      - "traefik.http.routers.minio-console.tls=true"
      - "traefik.http.routers.minio-console.tls.certresolver=letsencrypt"
      - "traefik.http.routers.minio-console.middlewares=compress,contenttype,errors,secure,whitelist-vpn@file"
      - "traefik.http.services.minio-console.loadbalancer.server.port=9001"
    networks:
      - traefik
      - prometheus
    volumes:
      - type: bind
        source: /docker/minio/data
        target: /data

  ### https://git.seedno.de/seednode/docker-roulette
  nature:
    image: oci.seedno.de/seednode/roulette:latest
    container_name: nature
    restart: unless-stopped
    environment:
      - "TZ=${TIMEZONE:?not set}"
    command:
      - "--bind=0.0.0.0"
      - "--cache"
      - "--cache-file=/cache/index.file"
      - "--debug"
      - "--filter"
      - "--port=8080"
      - "--recursive"
      - "--sort"
      - "--stats"
      - "--stats-file=/cache/stats.file"
      - "--verbose"
      - "/data"
    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.nature.headers.contentSecurityPolicy=default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'"
      - "traefik.http.routers.nature.rule=Host(`nature.seedno.de`)"
      - "traefik.http.routers.nature.entrypoints=https"
      - "traefik.http.routers.nature.service=nature"
      - "traefik.http.routers.nature.tls=true"
      - "traefik.http.routers.nature.tls.certresolver=letsencrypt"
      - "traefik.http.routers.nature.middlewares=compress,contenttype,secure,nature"
      - "traefik.http.services.nature.loadbalancer.server.port=8080"
    networks:
      - traefik
    volumes:
      - type: bind
        source: /docker/nature/cache
        target: /cache
      - type: bind
        source: /media/nature
        target: /data
        read_only: true

  ### https://git.seedno.de/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=255"
      - "traefik.http.routers.naughty.entrypoints=https"
      - "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,contenttype,errors,secure"
      - "traefik.http.services.naughty.loadbalancer.server.port=8080"
    networks:
      - traefik

  ### https://github.com/netdata/netdata
  netdata:
    image: netdata/netdata:latest
    container_name: netdata
    hostname: netdata.crimson.seedno.de
    restart: unless-stopped
    cap_add:
      - "SYS_PTRACE"
    security_opt:
      - "apparmor:unconfined"
    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.netdata.headers.contentSecurityPolicy=default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' https://www.googletagmanager.com; img-src 'self' data:; connect-src 'self' https://registry.my-netdata.io https://www.googleapis.com; frame-src 'self' https://app.netdata.cloud"
      - "traefik.http.routers.netdata.rule=Host(`netdata.crimson.seedno.de`)"
      - "traefik.http.routers.netdata.entrypoints=https"
      - "traefik.http.routers.netdata.service=netdata"
      - "traefik.http.routers.netdata.tls=true"
      - "traefik.http.routers.netdata.tls.certresolver=letsencrypt"
      - "traefik.http.routers.netdata.middlewares=compress,contenttype,errors,secure,netdata,whitelist-vpn@file"
      - "traefik.http.services.netdata.loadbalancer.server.port=19999"
    networks:
      - traefik
    volumes:
      - type: bind
        source: /proc
        target: /host/proc
        read_only: true
      - type: bind
        source: /sys
        target: /host/sys
        read_only: true

  ### https://github.com/nextcloud
  # The config file is located inside the container at /config/www/nextcloud/config/config.php
  nextcloud:
    image: lscr.io/linuxserver/nextcloud
    container_name: nextcloud
    restart: unless-stopped
    depends_on:
      - nextcloud-db
    environment:
      - "PUID=${UID:?not set}"
      - "PGID=${GID:?not set}"
      - "TZ=${TIMEZONE:?not set}"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.nextcloud.rule=Host(`cloud.seedno.de`)"
      - "traefik.http.routers.nextcloud.entrypoints=https"
      - "traefik.http.routers.nextcloud.service=nextcloud"
      - "traefik.http.routers.nextcloud.tls=true"
      - "traefik.http.routers.nextcloud.tls.certresolver=letsencrypt"
      - "traefik.http.routers.nextcloud.middlewares=compress,contenttype,errors,secure,nextcloud@file"
      - "traefik.http.services.nextcloud.loadbalancer.server.port=443"
      - "traefik.http.services.nextcloud.loadbalancer.server.scheme=https"
    networks:
      - traefik
      - nextcloud
    volumes:
      - type: bind
        source: /docker/nextcloud/config
        target: /config
      - type: bind
        source: /docker/nextcloud/data
        target: /data

  nextcloud-db:
    image: postgres:15-alpine
    container_name: nextcloud-db
    restart: unless-stopped
    environment:
      - "POSTGRES_DB=${NEXTCLOUD_DATABASE_NAME}"
      - "POSTGRES_USER=${NEXTCLOUD_DATABASE_USER}"
      - "POSTGRES_PASSWORD=${NEXTCLOUD_DATABASE_PASS}"
    networks:
      - nextcloud
    volumes:
      - type: bind
        source: /docker/nextcloud/database
        target: /var/lib/postgresql/data

  ### https://git.seedno.de/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
    depends_on:
      - nginx-php-fpm
    networks:
      - traefik
      - php
    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: /storage
        target: /storage
        read_only: true
      - type: bind
        source: /var/www/html
        target: /var/www/html
        read_only: true

  nginx-php-fpm:
    image: php:8-fpm-alpine
    container_name: nginx-php-fpm
    restart: unless-stopped
    networks:
      - php
    volumes:
      - type: bind
        source: /storage
        target: /storage
        read_only: true
      - type: bind
        source: /var/www/html
        target: /var/www/html
        read_only: true

  ### https://github.com/Luzifer/ots
  ots:
    image: oci.seedno.de/seednode/ots:latest
    container_name: ots
    restart: unless-stopped
    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.ots.headers.contentSecurityPolicy=default-src 'self'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; script-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' https://fonts.gstatic.com"
      - "traefik.http.routers.ots.rule=Host(`secrets.seedno.de`)"
      - "traefik.http.routers.ots.entrypoints=https"
      - "traefik.http.routers.ots.service=ots"
      - "traefik.http.routers.ots.tls=true"
      - "traefik.http.routers.ots.tls.certresolver=letsencrypt"
      - "traefik.http.routers.ots.middlewares=compress,contenttype,errors,secure,ots"
      - "traefik.http.services.ots.loadbalancer.server.port=3000"
    networks:
      - traefik

  ### https://git.seedno.de/seednode/oui-web
  oui:
    image: oci.seedno.de/seednode/oui-web:latest
    container_name: oui
    restart: unless-stopped
    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.oui.headers.contentSecurityPolicy=default-src 'self'"
      - "traefik.http.routers.oui.rule=Host(`oui.seedno.de`)"
      - "traefik.http.routers.oui.entrypoints=https"
      - "traefik.http.routers.oui.service=oui"
      - "traefik.http.routers.oui.tls=true"
      - "traefik.http.routers.oui.tls.certresolver=letsencrypt"
      - "traefik.http.routers.oui.middlewares=compress,contenttype,errors,secure,ratelimit,oui"
      - "traefik.http.services.oui.loadbalancer.server.port=8080"
    networks:
      - traefik

  ### https://github.com/owncast/owncast
  owncast:
    image: gabekangas/owncast:latest
    container_name: owncast
    restart: unless-stopped
    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.owncast.headers.contentSecurityPolicy=default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' blob:; img-src 'self' data:; font-src 'self' data:; media-src 'self' blob:"
      - "traefik.http.routers.owncast.rule=Host(`stream.seedno.de`)"
      - "traefik.http.routers.owncast.entrypoints=https"
      - "traefik.http.routers.owncast.service=owncast"
      - "traefik.http.routers.owncast.tls=true"
      - "traefik.http.routers.owncast.tls.certresolver=letsencrypt"
      - "traefik.http.routers.owncast.middlewares=compress,contenttype,errors,secure,owncast"
      - "traefik.http.services.owncast.loadbalancer.server.port=8080"
    ports:
      - "1935:1935"
    networks:
      - traefik
    volumes:
      - type: bind
        source: /docker/owncast/data
        target: /app/data


  ## https://github.com/prometheus/prometheus
  ## Run `chown -R 65534:65534 /docker/prometheus` to fix permissions
  ## See https://cdn.seedno.de/txt/prometheus.yml for example config file
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    restart: unless-stopped
    command:
      - "--storage.tsdb.path=/prometheus"
      - "--storage.tsdb.retention.time=30d"
      - "--web.console.libraries=/usr/share/prometheus/console_libraries"
      - "--web.console.templates=/usr/share/prometheus/consoles"
    networks:
      - prometheus
    volumes:
      - type: bind
        source: /docker/prometheus/config/prometheus.yml
        target: /prometheus/prometheus.yml
        read_only: true
      - type: bind
        source: /docker/prometheus/data
        target: /prometheus

  ### https://github.com/qbittorrent/qBittorrent
  qbittorrent:
    image: lscr.io/linuxserver/qbittorrent:latest
    container_name: qbittorrent
    restart: unless-stopped
    environment:
      - "PUID=${UID:?not set}"
      - "PGID=${GID:?not set}"
      - "TZ=${TIMEZONE:?not set}"
      - "UMASK_SET=022"
      - "WEBUI_PORT=8080"
    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.qbittorrent.headers.contentSecurityPolicy=default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'"
      - "traefik.http.routers.qbittorrent.rule=Host(`torrent.seedno.de`)"
      - "traefik.http.routers.qbittorrent.entrypoints=https"
      - "traefik.http.routers.qbittorrent.service=qbittorrent"
      - "traefik.http.routers.qbittorrent.tls=true"
      - "traefik.http.routers.qbittorrent.tls.certresolver=letsencrypt"
      - "traefik.http.routers.qbittorrent.middlewares=compress,contenttype,errors,secure,qbittorrent,whitelist-vpn@file"
      - "traefik.http.services.qbittorrent.loadbalancer.server.port=8080"
    ports:
      - "6881:6881"
      - "6881:6881/udp"
    networks:
      - traefik
    volumes:
      - type: bind
        source: /docker/qbittorrent/config
        target: /config
      - type: bind
        source: /storage/media/torrents
        target: /downloads

  ### https://git.seedno.de/seednode/docker-roulette
  roulette:
    image: oci.seedno.de/seednode/roulette:latest
    container_name: roulette
    restart: unless-stopped
    environment:
      - "TZ=${TIMEZONE:?not set}"
    command:
      - "--bind=0.0.0.0"
      - "--cache"
      - "--cache-file=/cache/index.file"
      - "--debug"
      - "--filter"
      - "--port=8080"
      - "--recursive"
      - "--sort"
      - "--stats"
      - "--stats-file=/cache/stats.file"
      - "--verbose"
      - "/data"
    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.roulette.headers.contentSecurityPolicy=default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'"
      - "traefik.http.routers.roulette.rule=Host(`roulette.seedno.de`)"
      - "traefik.http.routers.roulette.entrypoints=https"
      - "traefik.http.routers.roulette.service=roulette"
      - "traefik.http.routers.roulette.tls=true"
      - "traefik.http.routers.roulette.tls.certresolver=letsencrypt"
      - "traefik.http.routers.roulette.middlewares=compress,contenttype,secure,roulette,whitelist-vpn@file"
      - "traefik.http.services.roulette.loadbalancer.server.port=8080"
    networks:
      - traefik
    volumes:
      - type: bind
        source: /docker/roulette/cache
        target: /cache
      - type: bind
        source: /media/private
        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(`docker.seedno.de`)"
      - "traefik.http.routers.registry.entrypoints=https"
      - "traefik.http.routers.registry.service=registry"
      - "traefik.http.routers.registry.tls=true"
      - "traefik.http.routers.registry.tls.certresolver=letsencrypt"
      - "traefik.http.routers.registry.middlewares=compress,contenttype,errors,secure"
      - "traefik.http.services.registry.loadbalancer.server.port=5000"
    networks:
      - traefik
    volumes:
      - type: bind
        source: /docker/registry/config/config_private.yml
        target: /etc/docker/registry/config.yml
        read_only: true
      - type: bind
        source: /docker/registry/data
        target: /var/lib/registry

  ### Some people follow the actual guide for running a public registry,
  ### and some people just run a second copy of the service in maintenance
  ### mode and then disable write access to the volume
  registry-public:
    image: registry:2
    container_name: registry-public
    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-protected.rule=Host(`oci.seedno.de`) && PathPrefix(`/v2/_catalog`)"
      - "traefik.http.routers.registry-protected.entrypoints=https"
      - "traefik.http.routers.registry-protected.service=registry"
      - "traefik.http.routers.registry-protected.tls=true"
      - "traefik.http.routers.registry-protected.tls.certresolver=letsencrypt"
      - "traefik.http.routers.registry-protected.middlewares=adminauth,compress,contenttype,errors,secure"
      - "traefik.http.services.registry-protected.loadbalancer.server.port=5000"
      - "traefik.http.routers.registry-public.rule=Host(`oci.seedno.de`)"
      - "traefik.http.routers.registry-public.entrypoints=https"
      - "traefik.http.routers.registry-public.service=registry-public"
      - "traefik.http.routers.registry-public.tls=true"
      - "traefik.http.routers.registry-public.tls.certresolver=letsencrypt"
      - "traefik.http.routers.registry-public.middlewares=compress,contenttype,errors,secure"
      - "traefik.http.services.registry-public.loadbalancer.server.port=5000"
    networks:
      - traefik
    volumes:
      - type: bind
        source: /docker/registry/config/config_public.yml
        target: /etc/docker/registry/config.yml
        read_only: true
      - type: bind
        source: /docker/registry/data
        target: /var/lib/registry
        read_only: true

  ### https://github.com/ekzhang/rustpad
  rustpad:
    image: ekzhang/rustpad:latest
    container_name: rustpad
    restart: unless-stopped
    environment:
      - "EXPIRY_DAYS=1"
      - "SQLITE_URI=file:/app/db.sqlite;Version=3;"
    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.rustpad.headers.contentSecurityPolicy=default-src 'self'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdn.jsdelivr.net; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net; font-src 'self' https://fonts.gstatic.com https://cdn.jsdelivr.net; worker-src 'self' blob:"
      - "traefik.http.routers.rustpad.rule=Host(`notes.seedno.de`)"
      - "traefik.http.routers.rustpad.entrypoints=https"
      - "traefik.http.routers.rustpad.service=rustpad"
      - "traefik.http.routers.rustpad.tls=true"
      - "traefik.http.routers.rustpad.tls.certresolver=letsencrypt"
      - "traefik.http.routers.rustpad.middlewares=compress,contenttype,errors,secure,rustpad"
      - "traefik.http.services.rustpad.loadbalancer.server.port=3030"
    networks:
      - traefik
    volumes:
      - type: bind
        source: /docker/rustpad/data
        target: /app

  ### https://hub.docker.com/r/sflow/prometheus
  sflow-collector:
    image: sflow/prometheus:latest
    container_name: sflow-collector
    restart: unless-stopped
    environment:
      - "RTMEM=2G"
    command:
      - "-Dsnmp.ifname=yes"
      - "-Dgeo.country=resources/config/GeoLite2-Country.mmdb"
    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.sflow.headers.contentSecurityPolicy=default-src 'self'"
      - "traefik.http.routers.sflow.rule=Host(`flows.seedno.de`)"
      - "traefik.http.routers.sflow.entrypoints=https"
      - "traefik.http.routers.sflow.service=sflow"
      - "traefik.http.routers.sflow.tls=true"
      - "traefik.http.routers.sflow.tls.certresolver=letsencrypt"
      - "traefik.http.routers.sflow.middlewares=compress,contenttype,errors,secure,sflow,whitelist-vpn@file"
      - "traefik.http.services.sflow.loadbalancer.server.port=8008"
    ports:
      - "10.25.0.1:6343:6343/udp"
    networks:
      - traefik
      - prometheus

  ### https://github.com/sflow/host-sflow
  sflow-exporter:
    image: sflow/host-sflow:latest
    container_name: sflow-exporter
    restart: unless-stopped
    environment:
      - "COLLECTOR=flows.seedno.de"
      - "DROPMON=enable"
      - "NET=wan"
      - "POLLING=20"
      - "PORT=6343"
      - "SAMPLING=1000"
    network_mode: host

  ### https://github.com/oetiker/SmokePing
  smokeping:
    image: lscr.io/linuxserver/smokeping:latest
    container_name: smokeping
    restart: unless-stopped
    environment:
      - "PUID=${UID:?not set}"
      - "PGID=${GID:?not set}"
      - "TZ=${TIMEZONE:?not set}"
    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.smokeping.headers.contentSecurityPolicy=default-src 'self'; img-src 'self' data:"
      - "traefik.http.routers.smokeping.rule=Host(`ping.seedno.de`)"
      - "traefik.http.routers.smokeping.entrypoints=https"
      - "traefik.http.routers.smokeping.service=smokeping"
      - "traefik.http.routers.smokeping.tls=true"
      - "traefik.http.routers.smokeping.tls.certresolver=letsencrypt"
      - "traefik.http.routers.smokeping.middlewares=compress,contenttype,errors,secure,smokeping,whitelist-vpn@file"
      - "traefik.http.services.smokeping.loadbalancer.server.port=80"
    networks:
      - traefik
    volumes:
      - type: bind
        source: /docker/smokeping/config
        target: /config
        read_only: true
      - type: bind
        source: /docker/smokeping/data
        target: /data

  ### https://github.com/RobinLinus/snapdrop
  ## Note: "proxy_set_header X-Forwarded-for $remote_addr;" must be commented out in /config/nginx/site-confs/default, due to how traefik handles the header value
  snapdrop:
    image: lscr.io/linuxserver/snapdrop:latest
    container_name: snapdrop
    restart: unless-stopped
    environment:
      - "PUID=${UID:?not set}"
      - "PGID=${GID:?not set}"
      - "TZ=${TIMEZONE:?not set}"
    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.snapdrop.headers.contentSecurityPolicy=default-src 'self'; style-src 'self' 'sha256-biLFinpqYMtWHmXfkA1BPeCY0/fNt46SAZ+BBk5YUog='; style-src-attr 'self' 'unsafe-inline'"
      - "traefik.http.routers.snapdrop.rule=Host(`drop.seedno.de`)"
      - "traefik.http.routers.snapdrop.entrypoints=https"
      - "traefik.http.routers.snapdrop.service=snapdrop"
      - "traefik.http.routers.snapdrop.tls=true"
      - "traefik.http.routers.snapdrop.tls.certresolver=letsencrypt"
      - "traefik.http.routers.snapdrop.middlewares=compress,contenttype,errors,secure,snapdrop"
      - "traefik.http.services.snapdrop.loadbalancer.server.port=80"
    networks:
      - traefik
    volumes:
      - type: bind
        source: /docker/snapdrop/config
        target: /config

  ### https://github.com/syncthing/syncthing
  syncthing:
    image: lscr.io/linuxserver/syncthing:amd64-latest
    container_name: syncthing
    restart: unless-stopped
    environment:
      - "PUID=${UID:?not set}"
      - "PGID=${GID:?not set}"
      - "TZ=${TIMEZONE:?not set}"
      - "UMASK_SET=022"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.syncthing.rule=Host(`sync.crimson.seedno.de`)"
      - "traefik.http.routers.syncthing.entrypoints=https"
      - "traefik.http.routers.syncthing.service=syncthing"
      - "traefik.http.routers.syncthing.tls=true"
      - "traefik.http.routers.syncthing.tls.certresolver=letsencrypt"
      - "traefik.http.routers.syncthing.middlewares=compress,contenttype,errors,secure,whitelist-vpn@file"
      - "traefik.http.services.syncthing.loadbalancer.server.port=8384"
    ports:
      - "22000:22000"
      - "22000:22000/udp"
    networks:
      - traefik
    volumes:
      - type: bind
        source: /docker/syncthing/config
        target: /config
      - type: bind
        source: /ai
        target: /ai
      - type: bind
        source: /home/sinc/Dropbox
        target: /home/sinc/Dropbox
      - type: bind
        source: /storage
        target: /storage
      - type: bind
        source: /var/www/html
        target: /var/www/html

  ### https://github.com/thelounge/thelounge		
  thelounge:
    image: lscr.io/linuxserver/thelounge:latest
    container_name: thelounge
    restart: unless-stopped
    environment:
      - "PUID=${UID}"
      - "PGID=${GID}"
      - "TZ=${TIMEZONE}"
    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.irc.headers.contentSecurityPolicy=default-src 'self'; style-src 'self' 'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='"
      - "traefik.http.routers.irc.rule=Host(`chat.seedno.de`)"
      - "traefik.http.routers.irc.entrypoints=https"
      - "traefik.http.routers.irc.service=irc"
      - "traefik.http.routers.irc.tls=true"
      - "traefik.http.routers.irc.tls.certresolver=letsencrypt"
      - "traefik.http.routers.irc.middlewares=compress,contenttype,secure,irc"
      - "traefik.http.services.irc.loadbalancer.server.port=9000"
    networks:
      - traefik
    volumes:
      - type: bind
        source: /docker/thelounge/config
        target: /config

  ### https://github.com/linuxserver/docker-unifi-controller
  unifi:
    image: jacobalberty/unifi:latest
    container_name: unifi
    restart: unless-stopped
    environment:
    - "BIND_PRIV=false"
    - "RUNAS_UID0=false"
    - "UNIFI_UID=${UID:?not set}"
    - "UNIFI_GID=${GID:?not set}"
    - "TZ=${TIMEZONE:?not set}"
    networks:
      - traefik
    ports:
      - "3478:3478/udp"
      - "8080:8080"
    volumes:
      - type: bind
        source: /docker/unifi/data
        target: /unifi

  ### 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=false"
      - "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"
      - "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,contenttype,errors,secure,vaultwarden"
      - "traefik.http.services.vaultwarden.loadbalancer.server.port=80"
    networks:
      - traefik
      - vaultwarden
    volumes:
      - type: bind
        source: /docker/vaultwarden/data
        target: /data

  vaultwarden-db:
    image: postgres:13-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
    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"
      - "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,contenttype,errors,secure,ratelimit,whoami"
      - "traefik.http.services.whoami.loadbalancer.server.port=80"
    networks:
      - traefik

  ### https://github.com/chkpwd/winxuu
  winxuu:
    image: chkpwd/winxuu
    container_name: winxuu
    restart: unless-stopped
    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.winxuu.headers.contentSecurityPolicy=default-src 'self'; style-src 'self' https://cdnjs.cloudflare.com; font-src 'self' https://cdnjs.cloudflare.com"
      - "traefik.http.routers.winxuu.rule=Host(`winxuu.seedno.de`)"
      - "traefik.http.routers.winxuu.entrypoints=https"
      - "traefik.http.routers.winxuu.service=winxuu"
      - "traefik.http.routers.winxuu.tls=true"
      - "traefik.http.routers.winxuu.tls.certresolver=letsencrypt"
      - "traefik.http.routers.winxuu.middlewares=compress,contenttype,errors,secure,winxuu"
      - "traefik.http.services.winxuu.loadbalancer.server.port=8080"
    networks:
      - traefik

  ### https://www.xbrowsersync.org/
  xbrowsersync:
    image: xbrowsersync/api:latest
    container_name: xbrowsersync
    restart: unless-stopped
    depends_on:
      - xbrowsersync-db
    environment:
      - "XBROWSERSYNC_DB_PWD=${XBROWSERSYNC_DATABASE_PASS:?not set}"
      - "XBROWSERSYNC_DB_USER=${XBROWSERSYNC_DATABASE_USER:?not set}"
    healthcheck:
      test: [ "CMD", "node", "/usr/src/api/healthcheck.js" ]
      interval: "1m"
      timeout: "10s"
      retries: 5
      start_period: "30s"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.xbrowsersync.rule=Host(`browser-sync.seedno.de`)"
      - "traefik.http.routers.xbrowsersync.entrypoints=https"
      - "traefik.http.routers.xbrowsersync.service=xbrowsersync"
      - "traefik.http.routers.xbrowsersync.tls=true"
      - "traefik.http.routers.xbrowsersync.tls.certresolver=letsencrypt"
      - "traefik.http.routers.xbrowsersync.middlewares=compress,contenttype,errors,secure"
      - "traefik.http.services.xbrowsersync.loadbalancer.server.port=8080"
    networks:
      - traefik
      - xbrowsersync
    volumes:
      - type: bind
        source: /docker/xbrowsersync/config/settings.json
        target: /usr/src/api/config/settings.json
      - type: bind
        source: /docker/xbrowsersync/config/healthcheck.js
        target: /usr/src/api/healthcheck.js

  xbrowsersync-db:
    image: mongo:latest
    container_name: xbrowsersync-db
    restart: unless-stopped
    environment:
      - "MONGO_INITDB_DATABASE=${XBROWSERSYNC_DATABASE_NAME:?not set}"
      - "MONGO_INITDB_ROOT_PASSWORD=${XBROWSERSYNC_DATABASE_PASS:?not set}"
      - "MONGO_INITDB_ROOT_USERNAME=${XBROWSERSYNC_DATABASE_USER:?not set}"
      - "XBS_DB_NAME=${XBROWSERSYNC_DATABASE_NAME:?not set}"
      - "XBS_DB_PASSWORD=${XBROWSERSYNC_DATABASE_PASS:?not set}"
      - "XBS_DB_USERNAME=${XBROWSERSYNC_DATABASE_USER:?not set}"
    networks:
      - xbrowsersync
    volumes:
      - type: bind
        source: /docker/xbrowsersync/database
        target: /data/db
      - type: bind
        source: /docker/xbrowsersync/backups
        target: /data/backups
      - type: bind
        source: /docker/xbrowsersync/config/mongoconfig.js
        target: /docker-entrypoint-initdb.d/mongoconfig.js

networks:
  traefik:
    name: traefik
    driver: bridge
    driver_opts:
      com.docker.network.bridge.name: br_traefik
    ipam:
      driver: default
      config:
        - subnet: 10.160.0.0/22
  elasticsearch:
    name: elasticsearch
    internal: true
  gitea:
    name: gitea
    internal: true
  grafana:
    name: grafana
    internal: true
  nextcloud:
    name: nextcloud
    internal: true
  php:
    name: php
    internal: true
  prometheus:
    name: prometheus
    internal: true
  vaultwarden:
    name: vaultwarden
    internal: true
  xbrowsersync:
    name: xbrowsersync
    internal: true