--- services: postgres: restart: always image: "postgres:15.1-alpine" container_name: phoenixDB # Hostname # logging: # driver: loki # options: # loki-url: "${LOKI_URL}" # loki-retries: "${LOKI_RETRIES}" # loki-batch-size: "${LOKI_BATCH_SIZE}" # loki-external-labels: "service=phx-postgres,env=prod" networks: - backend environment: DEBUG: true POSTGRES_DB: ${DB_NAME} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} volumes: - "./database:/var/lib/postgresql/data" healthcheck: test: [ "CMD-SHELL", "pg_isready -U postgres" ] interval: 5s # Time between each health check timeout: 2s # Number of failures before marking as unhealthy retries: 5 # Grace period before health checks start pgadmin: restart: always image: dpage/pgadmin4 container_name: pgAdmin4-ui user: "5050:5050" # logging: # driver: loki # options: # loki-url: "${LOKI_URL}" # loki-retries: "${LOKI_RETRIES}" # loki-batch-size: "${LOKI_BATCH_SIZE}" # loki-external-labels: "service=phx-pgadmin,env=prod" networks: - backend - frontend environment: PGADMIN_DEFAULT_EMAIL: ${PGADMIN_DEFAULT_EMAIL} PGADMIN_DEFAULT_PASSWORD: ${SUPER_ADMIN_USER_PASSWORD} PGADMIN_CONFIG_SERVER_MODE: 'True' PGADMIN_CONFIG_WSGI_SCRIPT_NAME: "'/pgadmin4'" PGADMIN_CONFIG_PROXY_X_PROTO_COUNT: 1 PGADMIN_SERVER_JSON_FILE: '/var/lib/pgadmin/servers.json' PGADMIN_REPLACE_SERVERS_ON_STARTUP: 'True' PGADMIN_CONFIG_DATA_DIR: "'/var/lib/pgadmin'" PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED: 'False' # pgpass dynamic vars PGPASSFILE: /var/lib/pgadmin/pgpass PGPASS_HOST: ${DB_HOST} PGPASS_PORT: ${DB_PORT} PGPASS_DB: ${DB_NAME} PGPASS_USER: ${DB_USERNAME} PGPASS_PASSWORD: ${POSTGRES_PASSWORD} # Other config ALLOW_SAVE_PASSWORD: 'False' MFA_ENABLED: 'True' MFA_FORCE_REGISTRATION: 'False' MFA_SUPPORTED_METHODS: 'email' MFA_EMAIL_SUBJECT: 'Your MFA code by PHX-ERP' MAX_LOGIN_ATTEMPTS: 5 ENHANCED_COOKIE_PROTECTION: 'True' SHOW_GRAVATAR_IMAGE: 'True' SECURITY_EMAIL_SENDER: ${SECURITY_EMAIL_SENDER} MAIL_SERVER: ${MAIL_SERVER} MAIL_PORT: ${MAIL_PORT} MAIL_USE_SSL: 'False' MAIL_USE_TLS: 'False' MAIL_USERNAME: ${MAIL_USERNAME} MAIL_PASSWORD: ${MAIL_PASSWORD} MAIL_DEBUG: 'False' volumes: - ./pgadmin/data:/var/lib/pgadmin - ./pgadmin/pgadmin-entrypoint.sh:/docker-entrypoint.sh:ro entrypoint: ["/bin/sh", "/docker-entrypoint.sh"] depends_on: postgres: condition: service_healthy healthcheck: test: ["CMD", "wget", "-O", "-", "http://localhost:80/misc/ping"] interval: 15s timeout: 10s retries: 5 start_period: 60s phoenix-app: restart: always image: "phxerp/phoenix-app:beta" container_name: phoenix-app ports: - "3000:3000" # Restrict to only allow access from Grafana Server IP # logging: # driver: loki # options: # loki-url: "${LOKI_URL}" # loki-retries: "${LOKI_RETRIES}" # loki-batch-size: "${LOKI_BATCH_SIZE}" # loki-external-labels: "service=phx-app,env=prod,project=phoenix" volumes: - ./app_custom:/usr/share/nginx/html/assets/custom - ./nginx/nginx.conf:/etc/nginx/nginx.conf - ./nginx/includes:/etc/nginx/includes:ro networks: - backend - frontend depends_on: pgadmin: condition: service_healthy healthcheck: test: ["CMD", "wget", "--spider", "-q", "http://phoenix-app/login"] # localhost checks that the NGINX server inside the container is serving something at the root interval: 10s # check every 10 seconds timeout: 5s # allow 5 seconds per check retries: 5 # mark as unhealthy after 5 failures start_period: 15s # wait 15 seconds after container start before checking phoenix-system: restart: always image: "phxerp/phoenix-system:beta" # logging: # driver: loki # options: # loki-url: "${LOKI_URL}" # loki-retries: "${LOKI_RETRIES}" # loki-batch-size: "${LOKI_BATCH_SIZE}" # loki-external-labels: "service=phoenix-system,env=prod" environment: - "DB_HOST=phoenixDB" - "DB_NAME=${DB_NAME}" - "DB_PASSWORD=${POSTGRES_PASSWORD}" - "DB_USERNAME=postgres" - "SUPER_ADMIN_USER_PASSWORD=${SUPER_ADMIN_USER_PASSWORD}" - "REDIS_PASSWORD=${REDIS_PASSWORD}" - RUN_JOB_QUEUE=${RUN_JOB_QUEUE} - NODE_ENV=${NODE_ENV} - PHX_HOST_NAME=${PHX_HOST_NAME} command: ["npm", "run", "start:server"] deploy: replicas: ${PHOENIX_SYSTEM_REPLICAS} #change here if u want to have more replicas. Cant find a way to set via variable right now networks: backend: aliases: - phoenix-system depends_on: postgres: condition: service_healthy phoenix-redis: condition: service_healthy healthcheck: test: ["CMD-SHELL", "curl -s http://phoenix-system:3000/health | grep -q '\"admin-api\":{\"status\":\"up\"}' && curl -s http://phoenix-system:3000/health | grep -q '\"database\":{\"status\":\"up\"}'"] # Checks both admin-api and database status interval: 10s # Time between each health check timeout: 6s # Max time to wait for each check retries: 10 # Number of failures before marking as unhealthy start_period: 40s # Grace period before health checks start volumes: - "./assets:/usr/src/app/packages/dev-server/assets" - "./server_custom:/usr/src/app/packages/dev-server/custom" # - "./logs:/usr/src/app/packages/dev-server/logs" phoenix-worker: restart: always image: "phxerp/phoenix-system:beta" container_name: "phoenix-worker" ports: - "3001:3001" # Restrict to only allow access from Grafana Server IP # logging: # driver: loki # options: # loki-url: "${LOKI_URL}" # loki-retries: "${LOKI_RETRIES}" # loki-batch-size: "${LOKI_BATCH_SIZE}" # loki-external-labels: "service=phx-worker,env=prod" networks: - backend environment: - DB_HOST=phoenixDB - "DB_NAME=${DB_NAME}" - "DB_PASSWORD=${POSTGRES_PASSWORD}" - DB_USERNAME=postgres - "SUPER_ADMIN_USER_PASSWORD=${SUPER_ADMIN_USER_PASSWORD}" - REDIS_PASSWORD=${REDIS_PASSWORD} - NODE_ENV=${NODE_ENV} - PHX_HOST_NAME=${PHX_HOST_NAME} command: ['npm', 'run', 'start:worker'] depends_on: phoenix-system: condition: service_healthy postgres: condition: service_healthy healthcheck: test: [ "CMD-SHELL", "curl -s http://phoenix-worker:3001/health | grep -q '\"status\":\"ok\"'" ] # Check if worker responds with status ok interval: 10s # Time between each health check timeout: 6s # Max time to wait for each check retries: 20 # Grace period before health checks start start_period: 30s # Grace period before health checks start volumes: - "./assets:/usr/src/app/packages/dev-server/assets" - "./server_custom:/usr/src/app/packages/dev-server/custom" # - "./logs:/usr/src/app/packages/dev-server/logs" phoenix-redis: image: 'bitnami/redis:latest' container_name: redis command: /opt/bitnami/scripts/redis/run.sh --maxmemory 100mb user: root # logging: # driver: loki # options: # loki-url: "${LOKI_URL}" # loki-retries: "${LOKI_RETRIES}" # loki-batch-size: "${LOKI_BATCH_SIZE}" # loki-external-labels: "service=phx-redis,env=prod" networks: - backend restart: always environment: ALLOW_EMPTY_PASSWORD: "no" REDIS_PASSWORD: ${REDIS_PASSWORD} healthcheck: test: [ "CMD", "redis-cli", "--raw", "incr", "ping" ] interval: 5s retries: 10 # Increase retries if Redis takes a while to start timeout: 5s # Increase timeout if needed depends_on: postgres: condition: service_healthy volumes: - "./redis/data:/bitnami/redis/data" phoenix-health-exporter: image: phxerp/phoenix-health-exporter:alpha container_name: health_exporter restart: unless-stopped # logging: # driver: loki # options: # loki-url: "${LOKI_URL}" # loki-retries: "${LOKI_RETRIES}" # loki-batch-size: "${LOKI_BATCH_SIZE}" # loki-external-labels: "service=phx-health-exporter,env=prod" ports: - "9800:9800" environment: DB_HOST: ${DB_HOST} DB_NAME: ${DB_NAME} DB_PASSWORD: ${POSTGRES_PASSWORD} DB_USERNAME: ${DB_USERNAME} networks: - frontend - backend volumes: - /etc/hostname:/etc/host_hostname:ro # This ensures the container always uses the real machine hostname, even if restarted or recreated. security_opt: - no-new-privileges:true deploy: resources: limits: cpus: '0.25' memory: 128M depends_on: phoenix-system: condition: service_healthy phoenix-worker: condition: service_healthy postgres: condition: service_healthy healthcheck: test: ["CMD-SHELL", "curl -sf http://localhost:9800/healthz || exit 1"] interval: 1m timeout: 5s retries: 3 start_period: 15s node-exporter: image: quay.io/prometheus/node-exporter:latest container_name: node_exporter # logging: # driver: loki # options: # loki-url: "${LOKI_URL}" # loki-retries: "${LOKI_RETRIES}" # loki-batch-size: "${LOKI_BATCH_SIZE}" # loki-external-labels: "service=phx-node-exporter,env=prod" networks: - metrics - frontend restart: unless-stopped ports: - "9100:9100" # Restrict to only allow access from Grafana Server IP command: - "--path.procfs=/host/proc" - "--path.sysfs=/host/sys" - "--path.rootfs=/host" - "--collector.filesystem.ignored-mount-points=^/(sys|proc|dev)($$|/)" volumes: - "/proc:/host/proc:ro" - "/sys:/host/sys:ro" - "/:/host:ro,rslave" security_opt: - no-new-privileges:true deploy: resources: limits: cpus: '0.25' memory: 128M healthcheck: test: ["CMD", "wget", "-qO-", "http://localhost:9100/metrics"] interval: 15s timeout: 5s retries: 3 start_period: 20s # nginx-exporter: # image: nginx/nginx-prometheus-exporter:1.4.2 # container_name: nginx_exporter # restart: unless-stopped # # logging: # # driver: loki # # options: # # loki-url: "${LOKI_URL}" # # loki-retries: "${LOKI_RETRIES}" # # loki-batch-size: "${LOKI_BATCH_SIZE}" # # loki-external-labels: "service=phx-nginx-exporter,env=prod" # ports: # - "9113:9113" # Restrict to only allow access from Grafana Server IP # command: # - '--nginx.scrape-uri=http://phoenix-app/stub_status' # security_opt: # - no-new-privileges:true # deploy: # resources: # limits: # cpus: '0.25' # memory: 128M # depends_on: # phoenix-app: # condition: service_healthy # networks: # - frontend # - metrics # healthcheck: # test: ["CMD", "wget", "-qO-", "http://localhost:9113/metrics"] # Not working as expected # interval: 15s # timeout: 5s # retries: 3 # start_period: 10s https_portal: container_name: https_portal image: "steveltn/https-portal:1.21" restart: unless-stopped # logging: # driver: loki # options: # loki-url: "${LOKI_URL}" # loki-retries: "${LOKI_RETRIES}" # loki-batch-size: "${LOKI_BATCH_SIZE}" # loki-external-labels: "service=phx-https-portal,env=prod" networks: - frontend # [ PgAdmin, Phoenix-App ] ports: - "80:80" - "443:443" # - host:container environment: STAGE: "production" # Use Let's Encrypt production server WEBSOCKET: "true" # Enable websocket support DEBUG: "true" RENEW_MARGIN_DAYS: 30 CLIENT_MAX_BODY_SIZE: 0 SERVER_NAMES_HASH_BUCKET_SIZE: 128 # Increase hash bucket size for server names - good for bigger domains names, if not set correctly, it will throw an error, break the container. # FORCE_RENEW: 'true' DOMAINS: "${HTTPS_PORTAL_DOMAINS}" volumes: - ./https_portal/data:/var/lib/https-portal # ssl_certs, vhost.d, htdocs - ./https_portal/log:/var/log/nginx # nginx logs # - ./https_portal/config/custom_nginx.conf:/opt/custom_nginx.conf:ro # ✅ Mount file in a safe path depends_on: pgadmin: condition: service_healthy postgres: condition: service_healthy fail2ban: image: crazymax/fail2ban:latest container_name: fail2ban network_mode: 'host' cap_add: - NET_ADMIN - NET_RAW volumes: - ./fail2ban/data:/data - ./fail2ban/jail.d:/etc/fail2ban/jail.d - /var/log:/var/log:ro restart: always networks: backend: driver: bridge external: false ipam: config: - subnet: 172.19.0.0/16 frontend: driver: bridge external: false ipam: config: - subnet: 172.20.0.0/16 metrics: driver: bridge external: false ipam: config: - subnet: 172.22.0.0/16