Ctrl K
ComunidadGuías…

docker-compose.yml

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

Archivo original ↗Preguntar a KiBot
services:
  app:
    # Image publiée, épinglée par DIGEST sur la version de ce dépôt : un
    # `docker compose pull` tire exactement l'image de la release, jamais une
    # image poussée depuis. Pour mettre à jour, récupère la nouvelle version du
    # dépôt (`git pull`) : ce fichier y porte le digest suivant.
    #
    # Installation depuis les sources : `build:` vit dans docker-compose.build.yml.
    # Docker refuse de taguer un build local avec une référence qui contient un
    # digest (« build tag cannot contain a digest ») — les deux ne peuvent pas
    # cohabiter dans ce fichier.
    image: ghcr.io/physalis-cloud/physalis:1.7.1@sha256:2af2222d45560a6ba7034db97e007ee8e96ab4248a170533ab109f7d0eebce72
    container_name: physalis
    restart: unless-stopped
    env_file: .env
    environment:
      DATABASE_URL: postgresql://physalis:${DB_PASSWORD}@db:5432/physalis
      PORT: "3000"
    ports:
      # ⚠️ Défaut volontairement FERMÉ. Sans adresse, Docker publie sur 0.0.0.0
      # ET contourne le pare-feu de l'hôte (la chaîne DOCKER-USER est vide par
      # défaut) : un gestionnaire de secrets devient joignable depuis l'Internet
      # public dès que l'IP du serveur est connue — et une IP se découvre
      # (historique DNS, journaux de transparence des certificats).
      #
      # Sur ta machine, 127.0.0.1 suffit : http://localhost:3000 fonctionne.
      # Sur un serveur distant, mets Physalis derrière un reverse proxy (nginx,
      # Caddy, Traefik) qui termine le TLS et parle au conteneur en local.
      # Si tu dois vraiment publier le port, pose `BIND_IP` dans `.env` :
      # l'adresse d'une interface privée (VPN, réseau interne) de préférence,
      # `0.0.0.0` en dernier recours et seulement derrière un pare-feu.
      - "${BIND_IP:-127.0.0.1}:${PORT:-3000}:3000"
    security_opt:
      - no-new-privileges:true
    read_only: true
    # Aucune capability n'est nécessaire : le process écoute sur 3000 (> 1024,
    # donc pas de NET_BIND_SERVICE) et tourne en `nextjs` uid 1001, pas en root.
    # À NE PAS reporter sur `db` : l'entrypoint postgres démarre en root et a
    # besoin de SETUID/SETGID/CHOWN pour redescendre sur l'utilisateur postgres.
    cap_drop:
      - ALL
    tmpfs:
      - /tmp
    volumes:
      # Next.js écrit le cache d'images optimisées ici, et le rootfs est en
      # lecture seule → un tmpfs est obligatoire. Syntaxe LONGUE avec
      # `mode: 01777` (world-writable + sticky) : la syntaxe courte laisse le
      # montage non inscriptible par l'utilisateur non-root `nextjs`, d'où un
      # "EACCES: mkdir '/app/.next/cache/images'" au démarrage.
      - type: tmpfs
        target: /app/.next/cache
        tmpfs:
          mode: 01777
    # Limites de ressources — décommente et ajuste à ta machine. Volontairement
    # absentes par défaut : une limite mémoire trop basse fait tuer le conteneur
    # par l'OOM killer sur une grosse instance, et l'inverse d'un durcissement,
    # c'est une indisponibilité. Ces valeurs conviennent à un usage courant.
    # deploy:
    #   resources:
    #     limits:
    #       cpus: '1.0'
    #       memory: 512M
    #       pids: 100
    depends_on:
      db:
        condition: service_healthy
    networks:
      - internal

  db:
    # Version précise de postgres. Une montée arrive avec une nouvelle version
    # de Physalis ; ne change jamais la majeure (16) à la main, c'est une
    # migration de données, pas un changement de tag.
    image: postgres:16.15-alpine
    container_name: physalis-db
    restart: always
    environment:
      POSTGRES_USER: physalis
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: physalis
    volumes:
      - pg_data:/var/lib/postgresql/data
    networks:
      - internal
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U physalis"]
      interval: 5s
      retries: 10

volumes:
  pg_data:

networks:
  internal: