name: softvowels # ---------------------------------------------------------------- # SoftVowels — production docker-compose # # This stack publishes a static site (Astro) and a PayloadCMS # admin panel. Both attach to the homeserver's existing # `nginx_proxy_manager` network so Nginx Proxy Manager can # reverse-proxy them with TLS. # # - softvowels-db Postgres 16 # - softvowels-cms Payload admin + REST/GraphQL API (Node 20) # - softvowels-web nginx serving the static site (Astro build) # # How to access: # 1. https://softvowels.example -> softvowels-web:80 # 2. https://cms.softvowels.example -> softvowels-cms:3000/admin # Add both as "Proxy Hosts" in Nginx Proxy Manager, pointing # to the matching container name + port. See README. # ---------------------------------------------------------------- services: softvowels-db: image: postgres:16-alpine container_name: softvowels-db restart: unless-stopped environment: POSTGRES_USER: payload POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: softvowels volumes: - softvowels-pgdata:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U payload -d softvowels"] interval: 10s timeout: 5s retries: 10 networks: - nginx_proxy_manager softvowels-cms: build: context: . dockerfile: ./apps/cms/Dockerfile container_name: softvowels-cms restart: unless-stopped depends_on: softvowels-db: condition: service_healthy environment: NODE_ENV: production PORT: 3000 DATABASE_URI: postgres://payload:${POSTGRES_PASSWORD}@softvowels-db:5432/softvowels PAYLOAD_SECRET: ${PAYLOAD_SECRET} PAYLOAD_PUBLIC_SERVER_URL: https://${CMS_HOSTNAME} SERVER_URL: https://${CMS_HOSTNAME} CORS_ORIGINS: https://${WEB_HOSTNAME},http://localhost:4321 ASTRO_REVALIDATE_URL: http://host.docker.internal:4321/__revalidate ASTRO_REVALIDATE_TOKEN: ${REVALIDATE_TOKEN} volumes: - softvowels-cms-uploads:/app/apps/cms/media networks: - nginx_proxy_manager # The public site. We deliberately do NOT bake dist/ into the image: # scripts/rebuild.sh (run by the host-side webhook) writes fresh HTML to # ./apps/web/dist on the host, and we mount that path into nginx. That way # publishing in /admin → new content is live within ~30-60s without any # docker build / image push step. softvowels-web: image: nginx:1.27-alpine container_name: softvowels-web restart: unless-stopped depends_on: - softvowels-cms volumes: - ./apps/web/dist:/usr/share/nginx/html:ro - ./apps/web/nginx-default.conf:/etc/nginx/conf.d/default.conf:ro networks: - nginx_proxy_manager volumes: softvowels-pgdata: softvowels-cms-uploads: networks: nginx_proxy_manager: name: nginx_proxy_manager driver: bridge external: true