services: # Gitea - Self-hosted Git service gitea: image: ${DEV_GITEA_IMAGE:-gitea/gitea:latest} container_name: ${DEV_COMPOSE_PROJECT_NAME}_gitea restart: unless-stopped depends_on: - gitea_runner ports: - "2222:2222" volumes: - gitea_data:/data - gitea_config:/etc/gitea - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro - ./public:/data/gitea/public:ro - ./templates:/data/gitea/templates:ro environment: TZ: ${TIMEZONE:-Europe/Berlin} USER_UID: 1000 USER_GID: 1000 GITEA__APP_NAME: dev.pivoine.art GITEA__database__DB_TYPE: postgres GITEA__database__HOST: ${CORE_DB_HOST}:${CORE_DB_PORT} GITEA__database__NAME: ${DEV_GITEA_DB_NAME} GITEA__database__USER: ${DB_USER} GITEA__database__PASSWD: ${DB_PASSWORD} GITEA__server__DOMAIN: ${DEV_GITEA_TRAEFIK_HOST} GITEA__server__SSH_DOMAIN: ${DEV_GITEA_TRAEFIK_HOST} GITEA__server__ROOT_URL: https://${DEV_GITEA_TRAEFIK_HOST}/ GITEA__server__PROTOCOL: http GITEA__server__HTTP_PORT: 3000 GITEA__server__START_SSH_SERVER: true GITEA__server__SSH_PORT: 2222 GITEA__server__SSH_LISTEN_PORT: 2222 GITEA__mailer__ENABLED: true GITEA__mailer__PROTOCOL: smtp GITEA__mailer__SMTP_ADDR: net_mailpit GITEA__mailer__SMTP_PORT: 1025 GITEA__mailer__FROM: ${EMAIL_FROM} GITEA__service__DISABLE_REGISTRATION: false GITEA__service__REQUIRE_SIGNIN_VIEW: false GITEA__service__ENABLE_NOTIFY_MAIL: true GITEA__service__DEFAULT_EMAIL_NOTIFICATIONS: enabled GITEA__packages__ENABLED: true GITEA__actions__ENABLED: true GITEA__ui__THEMES: gitea-auto,gitea-light,gitea-dark,arc-green,edge-auto,edge-dark,edge-light,everforest-auto,everforest-dark,everforest-light,gruvbox-auto,gruvbox-dark,gruvbox-light,gruvbox-material-auto,gruvbox-material-dark,gruvbox-material-light,nord,palenight,soft-era,sonokai,sonokai-andromeda,sonokai-atlantis,sonokai-espresso,sonokai-maia,sonokai-shusia GITEA__ui__DEFAULT_THEME: edge-dark GITEA__ui__ENABLE_FEED: true networks: - compose_network labels: - "traefik.enable=${DEV_TRAEFIK_ENABLED}" # HTTP to HTTPS redirect - "traefik.http.middlewares.${DEV_COMPOSE_PROJECT_NAME}-gitea-redirect-web-secure.redirectscheme.scheme=https" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-gitea-web.middlewares=${DEV_COMPOSE_PROJECT_NAME}-gitea-redirect-web-secure" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-gitea-web.rule=Host(`${DEV_GITEA_TRAEFIK_HOST}`)" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-gitea-web.entrypoints=web" # HTTPS router - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-gitea-web-secure.rule=Host(`${DEV_GITEA_TRAEFIK_HOST}`)" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-gitea-web-secure.tls.certresolver=resolver" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-gitea-web-secure.entrypoints=web-secure" - "traefik.http.middlewares.${DEV_COMPOSE_PROJECT_NAME}-gitea-web-secure-compress.compress=true" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-gitea-web-secure.middlewares=${DEV_COMPOSE_PROJECT_NAME}-gitea-web-secure-compress,security-headers@file" # Service - "traefik.http.services.${DEV_COMPOSE_PROJECT_NAME}-gitea-web-secure.loadbalancer.server.port=3000" - "traefik.docker.network=${NETWORK_NAME}" # Watchtower - "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}" # Gitea Runner - Act runner for Gitea Actions gitea_runner: image: ${DEV_GITEA_RUNNER_IMAGE:-gitea/act_runner:latest} container_name: ${DEV_COMPOSE_PROJECT_NAME}_gitea_runner restart: unless-stopped privileged: true command: ["act_runner", "daemon", "--config", "/data/config.yaml"] volumes: - gitea_runner_data:/data - /var/run/docker.sock:/var/run/docker.sock - ./runner-config.yaml:/data/config.yaml:ro environment: TZ: ${TIMEZONE:-Europe/Berlin} GITEA_INSTANCE_URL: https://${DEV_GITEA_TRAEFIK_HOST} GITEA_RUNNER_REGISTRATION_TOKEN: ${DEV_GITEA_RUNNER_TOKEN} GITEA_RUNNER_NAME: ${DEV_GITEA_RUNNER_NAME:-docker-runner} GITEA_RUNNER_LABELS: ubuntu-latest:docker://catthehacker/ubuntu:act-latest,ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04,ubuntu-20.04:docker://catthehacker/ubuntu:act-20.04 DOCKER_HOST: unix:///var/run/docker.sock networks: - compose_network # Coolify - Self-hosted deployment platform coolify: image: ${DEV_COOLIFY_IMAGE:-ghcr.io/coollabsio/coolify:latest} container_name: ${DEV_COMPOSE_PROJECT_NAME}_coolify restart: unless-stopped depends_on: coolify_soketi: condition: service_started volumes: - coolify_data:/data/coolify - /var/run/docker.sock:/var/run/docker.sock - /data/coolify/ssh:/var/www/html/storage/app/ssh - /data/coolify/applications:/var/www/html/storage/app/applications - /data/coolify/databases:/var/www/html/storage/app/databases - /data/coolify/services:/var/www/html/storage/app/services - /data/coolify/backups:/var/www/html/storage/app/backups environment: - APP_ID=${DEV_COOLIFY_APP_ID} - APP_KEY=${DEV_COOLIFY_APP_KEY} - APP_NAME=Coolify - APP_ENV=production - APP_URL=https://${DEV_COOLIFY_TRAEFIK_HOST} - APP_PORT=8080 - DB_HOST=${CORE_DB_HOST} - DB_PORT=${CORE_DB_PORT} - DB_DATABASE=${DEV_COOLIFY_DB_NAME} - DB_USERNAME=${DB_USER} - DB_PASSWORD=${DB_PASSWORD} - REDIS_HOST=${CORE_REDIS_HOST} - REDIS_PORT=${CORE_REDIS_PORT} - PUSHER_HOST=realtime.${DEV_COOLIFY_TRAEFIK_HOST} - PUSHER_PORT=443 - PUSHER_APP_ID=${DEV_COOLIFY_PUSHER_APP_ID} - PUSHER_APP_KEY=${DEV_COOLIFY_PUSHER_APP_KEY} - PUSHER_APP_SECRET=${DEV_COOLIFY_PUSHER_APP_SECRET} - PUSHER_SCHEME=https - SSL_MODE=off networks: - compose_network labels: - "traefik.enable=${DEV_TRAEFIK_ENABLED}" # Main web interface - HTTP to HTTPS redirect - "traefik.http.middlewares.${DEV_COMPOSE_PROJECT_NAME}-coolify-redirect-web-secure.redirectscheme.scheme=https" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web.middlewares=${DEV_COMPOSE_PROJECT_NAME}-coolify-redirect-web-secure" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web.rule=Host(`${DEV_COOLIFY_TRAEFIK_HOST}`)" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web.entrypoints=web" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web.service=${DEV_COMPOSE_PROJECT_NAME}-coolify" # Main web interface - HTTPS router - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure.rule=Host(`${DEV_COOLIFY_TRAEFIK_HOST}`)" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure.tls.certresolver=resolver" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure.entrypoints=web-secure" - "traefik.http.middlewares.${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure-compress.compress=true" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure.middlewares=${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure-compress,security-headers@file" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure.service=${DEV_COMPOSE_PROJECT_NAME}-coolify" - "traefik.http.services.${DEV_COMPOSE_PROJECT_NAME}-coolify.loadbalancer.server.port=8080" # Network - "traefik.docker.network=${NETWORK_NAME}" # Watchtower - "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}" # Coolify Soketi (WebSocket server for realtime) coolify_soketi: image: quay.io/soketi/soketi:1.0-16-alpine container_name: ${DEV_COMPOSE_PROJECT_NAME}_coolify_soketi restart: unless-stopped environment: - SOKETI_DEFAULT_APP_ID=${DEV_COOLIFY_PUSHER_APP_ID} - SOKETI_DEFAULT_APP_KEY=${DEV_COOLIFY_PUSHER_APP_KEY} - SOKETI_DEFAULT_APP_SECRET=${DEV_COOLIFY_PUSHER_APP_SECRET} healthcheck: test: ["CMD", "wget", "-qO-", "http://127.0.0.1:6001/ready"] interval: 5s timeout: 5s retries: 10 networks: - compose_network labels: - "traefik.enable=${DEV_TRAEFIK_ENABLED}" # HTTP router - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-soketi-web.rule=Host(`realtime.${DEV_COOLIFY_TRAEFIK_HOST}`)" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-soketi-web.entrypoints=web" # HTTPS router - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-soketi-web-secure.rule=Host(`realtime.${DEV_COOLIFY_TRAEFIK_HOST}`)" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-soketi-web-secure.tls.certresolver=resolver" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-soketi-web-secure.entrypoints=web-secure" # Service - "traefik.http.services.${DEV_COMPOSE_PROJECT_NAME}-soketi-web-secure.loadbalancer.server.port=6001" - "traefik.docker.network=${NETWORK_NAME}" # Watchtower - "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}" # Coolify Terminal (WebSocket server on port 6002 for terminal) coolify_terminal: image: quay.io/soketi/soketi:1.0-16-alpine container_name: ${DEV_COMPOSE_PROJECT_NAME}_coolify_terminal restart: unless-stopped environment: - SOKETI_DEFAULT_APP_ID=${DEV_COOLIFY_PUSHER_APP_ID} - SOKETI_DEFAULT_APP_KEY=${DEV_COOLIFY_PUSHER_APP_KEY} - SOKETI_DEFAULT_APP_SECRET=${DEV_COOLIFY_PUSHER_APP_SECRET} - SOKETI_PORT=6002 healthcheck: test: ["CMD", "wget", "-qO-", "http://127.0.0.1:6002/ready"] interval: 5s timeout: 5s retries: 10 networks: - compose_network labels: - "traefik.enable=${DEV_TRAEFIK_ENABLED}" # Strip /terminal prefix - "traefik.http.middlewares.${DEV_COMPOSE_PROJECT_NAME}-terminal-strip.stripprefix.prefixes=/terminal" # HTTPS router - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-terminal.rule=Host(`${DEV_COOLIFY_TRAEFIK_HOST}`) && PathPrefix(`/terminal/ws`)" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-terminal.entrypoints=web-secure" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-terminal.tls.certresolver=resolver" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-terminal.priority=100" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-terminal.middlewares=${DEV_COMPOSE_PROJECT_NAME}-terminal-strip" # Service - "traefik.http.services.${DEV_COMPOSE_PROJECT_NAME}-terminal.loadbalancer.server.port=6002" - "traefik.docker.network=${NETWORK_NAME}" # Watchtower - "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}" # n8n - Workflow automation platform n8n: image: ${DEV_N8N_IMAGE:-docker.n8n.io/n8nio/n8n} container_name: ${DEV_COMPOSE_PROJECT_NAME}_n8n restart: unless-stopped volumes: - n8n_data:/home/node/.n8n environment: TZ: ${TIMEZONE:-Europe/Berlin} GENERIC_TIMEZONE: ${TIMEZONE:-Europe/Berlin} N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS: "true" N8N_RUNNERS_ENABLED: "true" DB_TYPE: postgresdb DB_POSTGRESDB_DATABASE: ${DEV_N8N_DB_NAME} DB_POSTGRESDB_HOST: ${CORE_DB_HOST} DB_POSTGRESDB_PORT: ${CORE_DB_PORT} DB_POSTGRESDB_USER: ${DB_USER} DB_POSTGRESDB_PASSWORD: ${DB_PASSWORD} DB_POSTGRESDB_SCHEMA: ${DEV_N8N_DB_SCHEMA:-public} N8N_HOST: ${DEV_N8N_TRAEFIK_HOST} N8N_PORT: 5678 N8N_PROTOCOL: https WEBHOOK_URL: https://${DEV_N8N_TRAEFIK_HOST}/ N8N_EMAIL_MODE: smtp N8N_SMTP_HOST: net_mailpit N8N_SMTP_PORT: 1025 N8N_SMTP_SENDER: ${EMAIL_FROM} N8N_SMTP_SSL: "false" MATTERMOST_WEBHOOK_URL: ${MATTERMOST_WEBHOOK_URL:-} depends_on: - postgres networks: - compose_network labels: - "traefik.enable=${DEV_TRAEFIK_ENABLED}" # HTTP to HTTPS redirect - "traefik.http.middlewares.${DEV_COMPOSE_PROJECT_NAME}-n8n-redirect-web-secure.redirectscheme.scheme=https" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-n8n-web.middlewares=${DEV_COMPOSE_PROJECT_NAME}-n8n-redirect-web-secure" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-n8n-web.rule=Host(`${DEV_N8N_TRAEFIK_HOST}`)" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-n8n-web.entrypoints=web" # HTTPS router - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-n8n-web-secure.rule=Host(`${DEV_N8N_TRAEFIK_HOST}`)" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-n8n-web-secure.tls.certresolver=resolver" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-n8n-web-secure.entrypoints=web-secure" - "traefik.http.middlewares.${DEV_COMPOSE_PROJECT_NAME}-n8n-web-secure-compress.compress=true" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-n8n-web-secure.middlewares=${DEV_COMPOSE_PROJECT_NAME}-n8n-web-secure-compress,security-headers@file" # Service - "traefik.http.services.${DEV_COMPOSE_PROJECT_NAME}-n8n-web-secure.loadbalancer.server.port=5678" - "traefik.docker.network=${NETWORK_NAME}" # Watchtower - "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}" # Asciinema - Terminal recording and sharing platform asciinema: image: ${DEV_ASCIINEMA_IMAGE:-ghcr.io/asciinema/asciinema-server:latest} container_name: ${DEV_COMPOSE_PROJECT_NAME}_asciinema restart: unless-stopped volumes: - asciinema_data:/var/opt/asciinema - ./asciinema-custom.exs:/opt/app/etc/custom.exs:ro environment: SECRET_KEY_BASE: ${ASCIINEMA_SECRET_KEY} URL_HOST: ${DEV_ASCIINEMA_TRAEFIK_HOST} URL_SCHEME: https DATABASE_URL: postgresql://${DB_USER}:${DB_PASSWORD}@${CORE_DB_HOST}/${DEV_ASCIINEMA_DB_NAME}?pool_size=10 SMTP_HOST: net_mailpit SMTP_PORT: 1025 SMTP_FROM_ADDRESS: ${EMAIL_FROM} SIGN_UP_DISABLED: ${DEV_ASCIINEMA_SIGN_UP_DISABLED:-false} DEFAULT_AVATAR: gravatar networks: - compose_network labels: - "traefik.enable=${DEV_TRAEFIK_ENABLED}" # Main web interface - HTTP to HTTPS redirect - "traefik.http.middlewares.${DEV_COMPOSE_PROJECT_NAME}-asciinema-redirect-web-secure.redirectscheme.scheme=https" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-web.middlewares=${DEV_COMPOSE_PROJECT_NAME}-asciinema-redirect-web-secure" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-web.rule=Host(`${DEV_ASCIINEMA_TRAEFIK_HOST}`)" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-web.entrypoints=web" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-web.service=${DEV_COMPOSE_PROJECT_NAME}-asciinema" # Main web interface - HTTPS router - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-web-secure.rule=Host(`${DEV_ASCIINEMA_TRAEFIK_HOST}`)" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-web-secure.tls.certresolver=resolver" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-web-secure.entrypoints=web-secure" - "traefik.http.middlewares.${DEV_COMPOSE_PROJECT_NAME}-asciinema-compress.compress=true" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-web-secure.middlewares=${DEV_COMPOSE_PROJECT_NAME}-asciinema-compress,security-headers@file" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-web-secure.service=${DEV_COMPOSE_PROJECT_NAME}-asciinema" - "traefik.http.services.${DEV_COMPOSE_PROJECT_NAME}-asciinema.loadbalancer.server.port=4000" # Admin interface - HTTP to HTTPS redirect - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin-web.middlewares=${DEV_COMPOSE_PROJECT_NAME}-asciinema-redirect-web-secure" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin-web.rule=Host(`admin.${DEV_ASCIINEMA_TRAEFIK_HOST}`)" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin-web.entrypoints=web" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin-web.service=${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin" # Admin interface - HTTPS router with Authelia - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin-web-secure.rule=Host(`admin.${DEV_ASCIINEMA_TRAEFIK_HOST}`)" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin-web-secure.tls.certresolver=resolver" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin-web-secure.entrypoints=web-secure" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin-web-secure.middlewares=${DEV_COMPOSE_PROJECT_NAME}-asciinema-compress,net-authelia,security-headers@file" - "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin-web-secure.service=${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin" - "traefik.http.services.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin.loadbalancer.server.port=4002" # Network - "traefik.docker.network=${NETWORK_NAME}" # Watchtower - "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}" volumes: gitea_data: name: ${DEV_COMPOSE_PROJECT_NAME}_gitea_data gitea_config: name: ${DEV_COMPOSE_PROJECT_NAME}_gitea_config gitea_runner_data: name: ${DEV_COMPOSE_PROJECT_NAME}_gitea_runner_data coolify_data: name: ${DEV_COMPOSE_PROJECT_NAME}_coolify_data n8n_data: name: ${DEV_COMPOSE_PROJECT_NAME}_n8n_data asciinema_data: name: ${DEV_COMPOSE_PROJECT_NAME}_asciinema_data networks: compose_network: name: ${NETWORK_NAME} external: true