Ctrl K
ComunidadGuías…

sftp-traefik-letsencrypt-docker-compose.yml

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Image pins live HERE, as interpolation defaults, so `git pull` (or
# re-downloading this file) delivers the exact version combination this
# repository has tested — no .env editing required. Setting the matching
# variable in .env overrides the default for anyone who wants to pin
# differently; .env itself carries only secrets and deliberate overrides.
# CI (Trivy scans, check-pin-freshness, the ephemeral test .env) reads
# the pins from these lines — this block is the single source of truth.
x-images:
  traefik: &traefik-image ${TRAEFIK_IMAGE_TAG:-traefik:${TRAEFIK_IMAGE_VERSION:-3.7@sha256:f4bb143d1135a579b630ed491e17ec50f6f7c9c6a30585ff3d385471d2a86f5a}}
  sftp: &sftp-image ${SFTP_IMAGE_TAG:-atmoz/sftp:${SFTP_IMAGE_VERSION:-debian@sha256:54efe2a6cda236d713042e17a836d970342eea5a7568e4f60800432cec4da205}}

networks:
  sftp-network:
    external: true
  traefik-network:
    external: true

volumes:
  traefik-certificates:

services:
  sftp:
    image: *sftp-image
    # Hardening: no privilege escalation via setuid binaries
    security_opt:
      - no-new-privileges:true
    # Resource limits as .env-overridable defaults (e.g. SFTP_MEMORY_LIMIT=2g);
    # the override survives every git pull.
    deploy:
      resources:
        limits:
          memory: ${SFTP_MEMORY_LIMIT:-512m}
          cpus: "${SFTP_CPU_LIMIT:-1.0}"
        reservations:
          memory: ${SFTP_MEMORY_RESERVATION:-64m}
          cpus: "${SFTP_CPU_RESERVATION:-0.25}"
    # THE USERS GO IN THE ENVIRONMENT, NOT ON THE COMMAND LINE. As command
    # arguments, user:password:uid sat in the entrypoint's arguments while it
    # created the users and generated the host keys, where every user on the
    # host reads them with ps, and in the container's recorded command. The
    # image reads the same list, space-separated, from SFTP_USERS.
    environment:
      SFTP_USERS: >-
        ${SFTP_USER_1:-user1}:${SFTP_USER_1_PASSWORD:?set in .env - see .env.example for generation command}:${SFTP_USER_1_UID:-1001}::
        ${SFTP_USER_2:-user2}:${SFTP_USER_2_PASSWORD:?set in .env - see .env.example for generation command}:${SFTP_USER_2_UID:-1002}::
    volumes:
      - /srv/sftpusers/${SFTP_USER_1:-user1}:/home/${SFTP_USER_1:-user1}/data
      - /srv/sftpusers/${SFTP_USER_2:-user2}:/home/${SFTP_USER_2:-user2}/data
    networks:
      - sftp-network
      - traefik-network
    labels:
      # Enable Traefik for this container
      - "traefik.enable=true"
      # Define TCP router rules for SFTP to match all incoming requests (HostSNI)
      - "traefik.tcp.routers.sftp.rule=HostSNI(`*`)"
      # Assign the SFTP router to a named Traefik service
      - "traefik.tcp.routers.sftp.service=sftp"
      # Use the 'SFTP' (custom) entry point
      - "traefik.tcp.routers.sftp.entrypoints=ssh"
      # Define the internal container port for routing to the SFTP service
      - "traefik.tcp.services.sftp.loadbalancer.server.port=22"
      # Specify which Docker network Traefik should use for routing
      - "traefik.docker.network=traefik-network"
    restart: unless-stopped

  traefik:
    image: *traefik-image
    # Hardening: no privilege escalation via setuid binaries
    security_opt:
      - no-new-privileges:true
    # Drop every Linux capability; add back only what this image's
    # entrypoint needs (bind :80/:443, chown its data directory, drop to
    # its service user).
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE
    # Resource limits as .env-overridable defaults (e.g. TRAEFIK_MEMORY_LIMIT=2g);
    # the override survives every git pull.
    deploy:
      resources:
        limits:
          memory: ${TRAEFIK_MEMORY_LIMIT:-256m}
          cpus: "${TRAEFIK_CPU_LIMIT:-0.5}"
        reservations:
          memory: ${TRAEFIK_MEMORY_RESERVATION:-64m}
          cpus: "${TRAEFIK_CPU_RESERVATION:-0.1}"
    command:
      # Set the log level (DEBUG, INFO, WARN, ERROR)
      - "--log.level=${TRAEFIK_LOG_LEVEL:-WARN}"
      # Enable the built-in API and web-based dashboard
      - "--api.dashboard=true"
      # Enable the /ping endpoint so we can health-check Traefik
      - "--ping=true"
      # Assign the /ping endpoint to a dedicated entry point on port 8082
      - "--ping.entrypoint=ping"
      - "--entrypoints.ping.address=:8082"
      # Define the primary HTTP entry point on port 80
      - "--entrypoints.web.address=:80"
      # Define the secure (HTTPS) entry point on port 443
      - "--entrypoints.websecure.address=:443"
      # Timeouts on the HTTPS entry point. Unset, they are Traefik's own
      # defaults; set them in .env to tune (see .env.example).
      - "--entrypoints.websecure.transport.respondingTimeouts.readTimeout=${TRAEFIK_READ_TIMEOUT:-60s}"
      - "--entrypoints.websecure.transport.respondingTimeouts.writeTimeout=${TRAEFIK_WRITE_TIMEOUT:-0s}"
      - "--entrypoints.websecure.transport.respondingTimeouts.idleTimeout=${TRAEFIK_IDLE_TIMEOUT:-180s}"
      # HTTP -> HTTPS redirect at entrypoint level
      - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
      - "--entrypoints.web.http.redirections.entrypoint.scheme=https"
      # Define the SFTP entry point using an environment variable for the port
      - "--entryPoints.ssh.address=:${SFTP_PORT:-2222}"
      # Enable the Docker provider to detect containers and their labels
      - "--providers.docker=true"
      # Point Traefik to the Docker socket
      - "--providers.docker.endpoint=unix:///var/run/docker.sock"
      # Prevent automatic exposure of all containers; only expose containers
      # with "traefik.enable=true"
      - "--providers.docker.exposedbydefault=false"
      # Use ACME (Let's Encrypt) to generate/renew certificates via TLS challenge
      - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
      # The email address used by Let's Encrypt for renewal notices
      - "--certificatesresolvers.letsencrypt.acme.email=${TRAEFIK_ACME_EMAIL:?set in .env - see .env.example}"
      # The file where ACME certificates are stored inside the container
      - "--certificatesresolvers.letsencrypt.acme.storage=/etc/traefik/acme/acme.json"
      # Enable Prometheus metrics
      - "--metrics.prometheus=true"
      # Configure Prometheus histogram buckets
      - "--metrics.prometheus.buckets=0.1,0.3,1.2,5.0"
      # Check for newer Traefik versions and optionally log that info
      - "--global.checknewversion=true"
      # Disable sending anonymous usage data to the Traefik maintainers
      - "--global.sendanonymoususage=false"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - traefik-certificates:/etc/traefik/acme
    networks:
      - traefik-network
    ports:
      - "${SFTP_PORT:-2222}:${SFTP_PORT:-2222}"
      - "80:80"
      - "443:443"
    healthcheck:
      test: ["CMD", "wget", "http://localhost:8082/ping","--spider"]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 5s
    labels:
      # Enable Traefik for this container
      - "traefik.enable=true"
      # A router to expose the Traefik dashboard
      - "traefik.http.routers.dashboard.rule=Host(`${TRAEFIK_HOSTNAME:?set in .env - see .env.example}`)"
      - "traefik.http.routers.dashboard.entrypoints=websecure"
      - "traefik.http.routers.dashboard.tls=true"
      - "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
      - "traefik.http.routers.dashboard.service=api@internal"
      # Basic Authentication for the Traefik dashboard
      - "traefik.http.routers.dashboard.middlewares=authtraefik"
      - "traefik.http.middlewares.authtraefik.basicauth.users=${TRAEFIK_BASIC_AUTH:?set in .env - see .env.example for htpasswd generation}"
      # Specify the internal server port to the dashboard service
      - "traefik.http.services.dashboard.loadbalancer.server.port=8080"
      # Pass the original Host header to the backend
      - "traefik.http.services.dashboard.loadbalancer.passhostheader=true"
    restart: unless-stopped