Files
web_server/docker-compose.yml
Adam French ee97ec9b23
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 38s
Pin app-network subnet to match trusted proxy CIDR
Gin's trusted proxies list is hardcoded to 172.28.0.0/16, but Docker was
assigning the bridge network whatever subnet was free, so c.ClientIP()
often returned nginx's container IP instead of the real client.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 00:43:29 +01:00

184 lines
5.0 KiB
YAML

networks:
app-network:
driver: bridge
ipam:
config:
- subnet: 172.28.0.0/16
volumes:
dbdata:
uploads:
vue_dist:
searxng_data:
services:
vue:
build:
context: ./vue
dockerfile: Dockerfile
container_name: vue
volumes:
- vue_dist:/output
networks:
- app-network
nginx:
build:
context: ./nginx
dockerfile: Dockerfile
container_name: nginx
env_file: ./.env
restart: always
depends_on:
- vue
- backend
- icecast2
- gitea
- hasura
- quartz
- searxng
networks:
- app-network
ports:
- 80:80
- 443:443
volumes:
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
- uploads:/uploads
- vue_dist:/etc/nginx/html
certbot:
image: certbot/certbot:v3.1.0
container_name: certbot
volumes:
- ./certbot/entrypoint.sh:/entrypoint.sh
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
entrypoint: ["/entrypoint.sh"]
env_file:
- .env
networks:
- app-network
backend:
build:
context: ./backend
dockerfile: Dockerfile
container_name: "${BACKEND_HOST}"
restart: always
depends_on:
- db
networks:
- app-network
env_file:
- ./.env
volumes:
- ./backend/token/:/backend/token
- ${OBSIDIAN_DIR}:/backend/notes
- ./logs:/backend/logs
- uploads:/backend/uploads
- ./icecast2/fallback_music:/backend/fallback_music
db:
image: postgres:16
container_name: "${POSTGRES_HOST}"
restart: always
env_file:
- ./.env
networks:
- app-network
volumes:
- dbdata:/var/lib/postgresql/data
hasura:
image: hasura/graphql-engine:v2.44.0
container_name: "${HASURA_HOST}"
restart: always
depends_on:
- db
networks:
- app-network
environment:
HASURA_GRAPHQL_DATABASE_URL: "postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}"
HASURA_GRAPHQL_ADMIN_SECRET: "${HASURA_GRAPHQL_ADMIN_SECRET}"
HASURA_GRAPHQL_ENABLE_CONSOLE: "false"
HASURA_GRAPHQL_DEV_MODE: "false"
HASURA_GRAPHQL_ENABLED_LOG_TYPES: "startup, http-log, webhook-log, websocket-log, query-log"
icecast2:
build:
context: ./icecast2
dockerfile: Dockerfile
container_name: "${ICECAST_HOST}"
restart: always
networks:
- app-network
env_file:
- ./.env
volumes:
- ./icecast2/fallback_music:/music:ro
ports:
- "${LIQUIDSOAP_HARBOR_PORT:-8001}:${LIQUIDSOAP_HARBOR_PORT:-8001}"
quartz:
build:
context: ./quartz
dockerfile: Dockerfile
container_name: "${QUARTZ_HOST}"
restart: always
networks:
- app-network
env_file:
- ./.env
volumes:
- ${OBSIDIAN_DIR}:/quartz/content:ro
searxng:
build:
context: ./searxng
dockerfile: Dockerfile
container_name: "${SEARXNG_HOST}"
restart: unless-stopped
networks:
- app-network
environment:
- BASE_URL=https://www.${DOMAIN}/searxng/
- INSTANCE_NAME=searxng
- SEARXNG_SECRET_KEY=${SEARXNG_SECRET_KEY}
volumes:
- searxng_data:/etc/searxng
gitea:
image: docker.gitea.com/gitea:1.25.4-rootless
container_name: "${GITEA_HOST}"
entrypoint: ["/usr/bin/dumb-init", "--", "/etc/gitea/entrypoint.sh"]
networks:
- app-network
environment:
- GITEA__database__DB_TYPE=postgres
- GITEA__database__HOST=${POSTGRES_HOST}
- GITEA__database__NAME=${POSTGRES_GITEA_DB}
- GITEA__database__USER=${POSTGRES_USER}
- GITEA__database__PASSWD=${POSTGRES_PASSWORD}
- GITEA__server__LFS_JWT_SECRET=${GITEA_LFS_JWT_SECRET}
- GITEA__security__INTERNAL_TOKEN=${GITEA_INTERNAL_TOKEN}
- GITEA__oauth2__JWT_SECRET=${GITEA_OAUTH2_JWT_SECRET}
- USER_UID=1000
- USER_GID=1000
restart: always
volumes:
- ./gitea/data:/var/lib/gitea
- ./gitea/config:/etc/gitea
- ./gitea/entrypoint.sh:/etc/gitea/entrypoint.sh:ro
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "2222:2222"
- "3000:3000"
depends_on:
- db