services: api: build: context: . dockerfile: server/Dockerfile restart: unless-stopped environment: - FESTIVAL_ID=${FESTIVAL_ID} - DB_PATH=/data/festival.sqlite volumes: - ./data:/data - ./tools:/app/tools:ro # Private, per-project network only. Keeping the API off the shared `traefik` # network prevents its `api` DNS alias from colliding with other stacks' # API containers (which caused requests to be served by the wrong backend). networks: - internal web: build: context: . dockerfile: nginx/Dockerfile restart: unless-stopped depends_on: - api volumes: - ./public:/usr/share/nginx/html:ro # `internal` to reach the API privately; `traefik` for public ingress only. networks: - internal - traefik labels: - traefik.enable=true # Pin the ingress IP to the traefik network (web is multi-homed). - traefik.docker.network=traefik - traefik.http.routers.affenschwenkonline.rule=Host(`affen.schwenk.online`) - traefik.http.routers.affenschwenkonline.entrypoints=websecure - traefik.http.routers.affenschwenkonline.tls.certresolver=myresolver - traefik.http.services.affenschwenkonline.loadbalancer.server.port=80 networks: # Private network created per compose project; isolates api<->web traffic. internal: traefik: external: true