From 4a6249dfaeeb93f8861d9282704326511591d6e7 Mon Sep 17 00:00:00 2001 From: Yuri Lima Date: Tue, 29 Jul 2025 10:09:46 +0200 Subject: [PATCH] first commit --- .env | 33 ++ .env.10600.2024-02-22@14:53:32~ | 24 + .env.10625.2024-02-22@14:53:32~ | 24 + .env.10650.2024-02-22@14:53:33~ | 24 + .env.10675.2024-02-22@14:53:33~ | 24 + .env.6892.2024-02-22@13:09:04~ | 24 + .env.6917.2024-02-22@13:09:04~ | 24 + .env.6942.2024-02-22@13:09:05~ | 24 + .env.6967.2024-02-22@13:09:05~ | 24 + .gitignore | 7 + app_custom/xcustom-style.css | 3 + app_custom/xloginscreen-logo.png | Bin 0 -> 101694 bytes crash_diagnose.sh | 87 ++++ docker-compose.yaml | 413 ++++++++++++++++++ ...er-compose.yaml.10700.2024-02-22@14:53:34~ | 162 +++++++ docker-compose.yaml.6992.2024-02-22@13:09:06~ | 162 +++++++ nginx/includes/pgadmin.conf | 18 + nginx/nginx.conf | 402 +++++++++++++++++ server_custom/config.ts | 253 +++++++++++ 19 files changed, 1732 insertions(+) create mode 100755 .env create mode 100755 .env.10600.2024-02-22@14:53:32~ create mode 100755 .env.10625.2024-02-22@14:53:32~ create mode 100755 .env.10650.2024-02-22@14:53:33~ create mode 100755 .env.10675.2024-02-22@14:53:33~ create mode 100755 .env.6892.2024-02-22@13:09:04~ create mode 100755 .env.6917.2024-02-22@13:09:04~ create mode 100755 .env.6942.2024-02-22@13:09:05~ create mode 100755 .env.6967.2024-02-22@13:09:05~ create mode 100644 .gitignore create mode 100755 app_custom/xcustom-style.css create mode 100755 app_custom/xloginscreen-logo.png create mode 100644 crash_diagnose.sh create mode 100755 docker-compose.yaml create mode 100755 docker-compose.yaml.10700.2024-02-22@14:53:34~ create mode 100755 docker-compose.yaml.6992.2024-02-22@13:09:06~ create mode 100755 nginx/includes/pgadmin.conf create mode 100755 nginx/nginx.conf create mode 100755 server_custom/config.ts diff --git a/.env b/.env new file mode 100755 index 0000000..74c7c83 --- /dev/null +++ b/.env @@ -0,0 +1,33 @@ +# ===== Enviroment Stage ====== +NODE_ENV=production +# ====== Database Configuration ====== +POSTGRES_PASSWORD=0SGVvbf42a4g69T +PGADMIN_DEFAULT_PASSWORD=mpXdSohHCKuY9FR +DB_NAME="phoenix" +DB_HOST="phoenixDB" +DB_PORT=5432 +DB_USERNAME="postgres" +PHX_SYSTEM_CONNECTION_POOL_MAX=5 +PHX_WORKER_CONNECTION_POOL_MAX=2 +PGADMIN_DEFAULT_EMAIL="info@phx-erp.de" +MAIL_SERVER="mail.phx-erp.de" +MAIL_PORT=465 +MAIL_USERNAME="yuri.lima@phx-erp.de" +MAIL_PASSWORD="0rB0@et68" +SECURITY_EMAIL_SENDER="'No Reply PHX '" +# ====== Phoenix Super Admin Configuration ====== +SUPER_ADMIN_USER_PASSWORD=betarc +# ====== Redis Configuration ====== +REDIS_PASSWORD=dTvShdBatwFtF9P +# ====== Worker Configuration ====== +RUN_JOB_QUEUE=1 +# ===== Metris Configuration ====== +# Loki API URL -> The IP 5.75.153.161 is the Grafana Server where it has a firewall rule to allow the connection. Please, if you change here, need to be change in NGINX too. +LOKI_URL=http://grafana.phx-erp.de:3100/loki/api/v1/push +LOKI_RETRIES=5 +LOKI_BATCH_SIZE=500 +# ===== HTTPS-PORTAL Configuration ====== +HTTPS_PORTAL_DOMAINS='beta-rc.phx-erp.de -> http://phoenix-app:80' +# ====== PHX-SYSTEM Configuration ====== +PHOENIX_SYSTEM_REPLICAS=1 +PHX_HOST_NAME='beta-rc.phx-erp.de' \ No newline at end of file diff --git a/.env.10600.2024-02-22@14:53:32~ b/.env.10600.2024-02-22@14:53:32~ new file mode 100755 index 0000000..ea9e639 --- /dev/null +++ b/.env.10600.2024-02-22@14:53:32~ @@ -0,0 +1,24 @@ +# ===== Enviroment Stage ====== +ENV_MODE=production +# ====== Database Configuration ====== +POSTGRES_PASSWORD= +PGADMIN_DEFAULT_PASSWORD= +# ====== Phoenix Super Admin Configuration ====== +SUPER_ADMIN_USER_PASSWORD= +# ====== Redis Configuration ====== +REDIS_PASSWORD= +# ====== Worker Configuration ====== +RUN_JOB_QUEUE=1 +# ====== Email Configuration ====== +SMTP_FROM="info@phx-erp.de" +SMTP_TYPE='smtp' +SMTP_NAME='mail.phx-erp.de' +SMTP_HOST='mail.phx-erp.de' +SMTP_PORT=465 +SMTP_SECURE='true' +SMTP_USER='yuri.lima@phx-erp.de' +SMTP_PASS='0rB0@et68' +SMTP_LOGGING='true' +SMTP_DEBUG='true' +SMTP_TLS_REJECT_UNAUTHORIZED='false' # If true will reject self-signed certificates. It will show: Hostname/IP does not match certificate's altnames: Host: mail.phx-erp.de. is not in the cert's altnames: DNS:*.netcup.net, DNS:netcup.net trace +SMTP_SECURE_CONNECTION='true' # Not in use diff --git a/.env.10625.2024-02-22@14:53:32~ b/.env.10625.2024-02-22@14:53:32~ new file mode 100755 index 0000000..b030c73 --- /dev/null +++ b/.env.10625.2024-02-22@14:53:32~ @@ -0,0 +1,24 @@ +# ===== Enviroment Stage ====== +ENV_MODE=production +# ====== Database Configuration ====== +POSTGRES_PASSWORD=0SGVvbf42a4g69T +PGADMIN_DEFAULT_PASSWORD= +# ====== Phoenix Super Admin Configuration ====== +SUPER_ADMIN_USER_PASSWORD= +# ====== Redis Configuration ====== +REDIS_PASSWORD= +# ====== Worker Configuration ====== +RUN_JOB_QUEUE=1 +# ====== Email Configuration ====== +SMTP_FROM="info@phx-erp.de" +SMTP_TYPE='smtp' +SMTP_NAME='mail.phx-erp.de' +SMTP_HOST='mail.phx-erp.de' +SMTP_PORT=465 +SMTP_SECURE='true' +SMTP_USER='yuri.lima@phx-erp.de' +SMTP_PASS='0rB0@et68' +SMTP_LOGGING='true' +SMTP_DEBUG='true' +SMTP_TLS_REJECT_UNAUTHORIZED='false' # If true will reject self-signed certificates. It will show: Hostname/IP does not match certificate's altnames: Host: mail.phx-erp.de. is not in the cert's altnames: DNS:*.netcup.net, DNS:netcup.net trace +SMTP_SECURE_CONNECTION='true' # Not in use diff --git a/.env.10650.2024-02-22@14:53:33~ b/.env.10650.2024-02-22@14:53:33~ new file mode 100755 index 0000000..6633926 --- /dev/null +++ b/.env.10650.2024-02-22@14:53:33~ @@ -0,0 +1,24 @@ +# ===== Enviroment Stage ====== +ENV_MODE=production +# ====== Database Configuration ====== +POSTGRES_PASSWORD=0SGVvbf42a4g69T +PGADMIN_DEFAULT_PASSWORD=mpXdSohHCKuY9FR +# ====== Phoenix Super Admin Configuration ====== +SUPER_ADMIN_USER_PASSWORD= +# ====== Redis Configuration ====== +REDIS_PASSWORD= +# ====== Worker Configuration ====== +RUN_JOB_QUEUE=1 +# ====== Email Configuration ====== +SMTP_FROM="info@phx-erp.de" +SMTP_TYPE='smtp' +SMTP_NAME='mail.phx-erp.de' +SMTP_HOST='mail.phx-erp.de' +SMTP_PORT=465 +SMTP_SECURE='true' +SMTP_USER='yuri.lima@phx-erp.de' +SMTP_PASS='0rB0@et68' +SMTP_LOGGING='true' +SMTP_DEBUG='true' +SMTP_TLS_REJECT_UNAUTHORIZED='false' # If true will reject self-signed certificates. It will show: Hostname/IP does not match certificate's altnames: Host: mail.phx-erp.de. is not in the cert's altnames: DNS:*.netcup.net, DNS:netcup.net trace +SMTP_SECURE_CONNECTION='true' # Not in use diff --git a/.env.10675.2024-02-22@14:53:33~ b/.env.10675.2024-02-22@14:53:33~ new file mode 100755 index 0000000..6db5090 --- /dev/null +++ b/.env.10675.2024-02-22@14:53:33~ @@ -0,0 +1,24 @@ +# ===== Enviroment Stage ====== +ENV_MODE=production +# ====== Database Configuration ====== +POSTGRES_PASSWORD=0SGVvbf42a4g69T +PGADMIN_DEFAULT_PASSWORD=mpXdSohHCKuY9FR +# ====== Phoenix Super Admin Configuration ====== +SUPER_ADMIN_USER_PASSWORD= +# ====== Redis Configuration ====== +REDIS_PASSWORD=dTvShdBatwFtF9P +# ====== Worker Configuration ====== +RUN_JOB_QUEUE=1 +# ====== Email Configuration ====== +SMTP_FROM="info@phx-erp.de" +SMTP_TYPE='smtp' +SMTP_NAME='mail.phx-erp.de' +SMTP_HOST='mail.phx-erp.de' +SMTP_PORT=465 +SMTP_SECURE='true' +SMTP_USER='yuri.lima@phx-erp.de' +SMTP_PASS='0rB0@et68' +SMTP_LOGGING='true' +SMTP_DEBUG='true' +SMTP_TLS_REJECT_UNAUTHORIZED='false' # If true will reject self-signed certificates. It will show: Hostname/IP does not match certificate's altnames: Host: mail.phx-erp.de. is not in the cert's altnames: DNS:*.netcup.net, DNS:netcup.net trace +SMTP_SECURE_CONNECTION='true' # Not in use diff --git a/.env.6892.2024-02-22@13:09:04~ b/.env.6892.2024-02-22@13:09:04~ new file mode 100755 index 0000000..ea9e639 --- /dev/null +++ b/.env.6892.2024-02-22@13:09:04~ @@ -0,0 +1,24 @@ +# ===== Enviroment Stage ====== +ENV_MODE=production +# ====== Database Configuration ====== +POSTGRES_PASSWORD= +PGADMIN_DEFAULT_PASSWORD= +# ====== Phoenix Super Admin Configuration ====== +SUPER_ADMIN_USER_PASSWORD= +# ====== Redis Configuration ====== +REDIS_PASSWORD= +# ====== Worker Configuration ====== +RUN_JOB_QUEUE=1 +# ====== Email Configuration ====== +SMTP_FROM="info@phx-erp.de" +SMTP_TYPE='smtp' +SMTP_NAME='mail.phx-erp.de' +SMTP_HOST='mail.phx-erp.de' +SMTP_PORT=465 +SMTP_SECURE='true' +SMTP_USER='yuri.lima@phx-erp.de' +SMTP_PASS='0rB0@et68' +SMTP_LOGGING='true' +SMTP_DEBUG='true' +SMTP_TLS_REJECT_UNAUTHORIZED='false' # If true will reject self-signed certificates. It will show: Hostname/IP does not match certificate's altnames: Host: mail.phx-erp.de. is not in the cert's altnames: DNS:*.netcup.net, DNS:netcup.net trace +SMTP_SECURE_CONNECTION='true' # Not in use diff --git a/.env.6917.2024-02-22@13:09:04~ b/.env.6917.2024-02-22@13:09:04~ new file mode 100755 index 0000000..9eae0cb --- /dev/null +++ b/.env.6917.2024-02-22@13:09:04~ @@ -0,0 +1,24 @@ +# ===== Enviroment Stage ====== +ENV_MODE=production +# ====== Database Configuration ====== +POSTGRES_PASSWORD=LzJO0zfwQkRkh4x +PGADMIN_DEFAULT_PASSWORD= +# ====== Phoenix Super Admin Configuration ====== +SUPER_ADMIN_USER_PASSWORD= +# ====== Redis Configuration ====== +REDIS_PASSWORD= +# ====== Worker Configuration ====== +RUN_JOB_QUEUE=1 +# ====== Email Configuration ====== +SMTP_FROM="info@phx-erp.de" +SMTP_TYPE='smtp' +SMTP_NAME='mail.phx-erp.de' +SMTP_HOST='mail.phx-erp.de' +SMTP_PORT=465 +SMTP_SECURE='true' +SMTP_USER='yuri.lima@phx-erp.de' +SMTP_PASS='0rB0@et68' +SMTP_LOGGING='true' +SMTP_DEBUG='true' +SMTP_TLS_REJECT_UNAUTHORIZED='false' # If true will reject self-signed certificates. It will show: Hostname/IP does not match certificate's altnames: Host: mail.phx-erp.de. is not in the cert's altnames: DNS:*.netcup.net, DNS:netcup.net trace +SMTP_SECURE_CONNECTION='true' # Not in use diff --git a/.env.6942.2024-02-22@13:09:05~ b/.env.6942.2024-02-22@13:09:05~ new file mode 100755 index 0000000..dc689ba --- /dev/null +++ b/.env.6942.2024-02-22@13:09:05~ @@ -0,0 +1,24 @@ +# ===== Enviroment Stage ====== +ENV_MODE=production +# ====== Database Configuration ====== +POSTGRES_PASSWORD=LzJO0zfwQkRkh4x +PGADMIN_DEFAULT_PASSWORD=uAMfCnBzGSsEmOL +# ====== Phoenix Super Admin Configuration ====== +SUPER_ADMIN_USER_PASSWORD= +# ====== Redis Configuration ====== +REDIS_PASSWORD= +# ====== Worker Configuration ====== +RUN_JOB_QUEUE=1 +# ====== Email Configuration ====== +SMTP_FROM="info@phx-erp.de" +SMTP_TYPE='smtp' +SMTP_NAME='mail.phx-erp.de' +SMTP_HOST='mail.phx-erp.de' +SMTP_PORT=465 +SMTP_SECURE='true' +SMTP_USER='yuri.lima@phx-erp.de' +SMTP_PASS='0rB0@et68' +SMTP_LOGGING='true' +SMTP_DEBUG='true' +SMTP_TLS_REJECT_UNAUTHORIZED='false' # If true will reject self-signed certificates. It will show: Hostname/IP does not match certificate's altnames: Host: mail.phx-erp.de. is not in the cert's altnames: DNS:*.netcup.net, DNS:netcup.net trace +SMTP_SECURE_CONNECTION='true' # Not in use diff --git a/.env.6967.2024-02-22@13:09:05~ b/.env.6967.2024-02-22@13:09:05~ new file mode 100755 index 0000000..9e76ddc --- /dev/null +++ b/.env.6967.2024-02-22@13:09:05~ @@ -0,0 +1,24 @@ +# ===== Enviroment Stage ====== +ENV_MODE=production +# ====== Database Configuration ====== +POSTGRES_PASSWORD=LzJO0zfwQkRkh4x +PGADMIN_DEFAULT_PASSWORD=uAMfCnBzGSsEmOL +# ====== Phoenix Super Admin Configuration ====== +SUPER_ADMIN_USER_PASSWORD= +# ====== Redis Configuration ====== +REDIS_PASSWORD=DQHae9U8WbJEwAi +# ====== Worker Configuration ====== +RUN_JOB_QUEUE=1 +# ====== Email Configuration ====== +SMTP_FROM="info@phx-erp.de" +SMTP_TYPE='smtp' +SMTP_NAME='mail.phx-erp.de' +SMTP_HOST='mail.phx-erp.de' +SMTP_PORT=465 +SMTP_SECURE='true' +SMTP_USER='yuri.lima@phx-erp.de' +SMTP_PASS='0rB0@et68' +SMTP_LOGGING='true' +SMTP_DEBUG='true' +SMTP_TLS_REJECT_UNAUTHORIZED='false' # If true will reject self-signed certificates. It will show: Hostname/IP does not match certificate's altnames: Host: mail.phx-erp.de. is not in the cert's altnames: DNS:*.netcup.net, DNS:netcup.net trace +SMTP_SECURE_CONNECTION='true' # Not in use diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..559ad0b --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +assets +database +fail2ban +logs +https_portal +pgadmin +redis diff --git a/app_custom/xcustom-style.css b/app_custom/xcustom-style.css new file mode 100755 index 0000000..a70e160 --- /dev/null +++ b/app_custom/xcustom-style.css @@ -0,0 +1,3 @@ +.login-logo-img { + background-image: url("/assets/custom/loginscreen-logo.png")!Important; +} diff --git a/app_custom/xloginscreen-logo.png b/app_custom/xloginscreen-logo.png new file mode 100755 index 0000000000000000000000000000000000000000..282e9d90c3625a0aa590091b9bbb8c761f48a5e7 GIT binary patch literal 101694 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 /dev/null && docker info >/dev/null 2>&1; then + echo -e "\n๐Ÿณ Docker detected and running." + + CONTAINERS=$(docker ps -aq) + if [[ -z "$CONTAINERS" ]]; then + echo -e "\nโš ๏ธ No containers found. Skipping container-specific diagnostics." + else + echo -e "\n๐Ÿณ Docker OOM-Killed Containers:" + docker inspect $CONTAINERS 2>/dev/null | grep -B10 '"OOMKilled": true' || echo "No containers were OOMKilled." + + echo -e "\n๐Ÿ” Recently Restarted Containers:" + docker ps -a --format '{{.Names}}\t{{.Status}}' | grep -i 'restarted' || echo "No recent restarts." + + echo -e "\n๐Ÿ“‰ Top 5 Containers by Memory Usage (now):" + docker stats --no-stream --format "table {{.Name}}\t{{.MemUsage}}" | sort -k2 -hr | head -n 6 + + echo -e "\n๐Ÿ“ˆ Top 5 Containers by CPU Usage (now):" + docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}" | sort -k2 -hr | head -n 6 + + echo -e "\n๐Ÿ“‹ Docker Container Memory Limits:" + docker inspect $CONTAINERS --format '{{ .Name }}: {{ .HostConfig.Memory }} bytes' | grep -v ': 0' || echo "None set" + + echo -e "\n๐Ÿ“‹ Containers With No Memory Limit:" + docker inspect $CONTAINERS --format '{{ .Name }}: {{ .HostConfig.Memory }}' | awk '$2 == 0 {print $1}' + + echo -e "\n๐Ÿ“ Last 100 Log Lines from PHX Containers:" + for name in $(docker ps -a --format '{{.Names}}' | grep -i 'phoenix\|pgadmin\|postgres'); do + echo -e "\n--- Logs for $name ---" + docker logs --tail=100 "$name" 2>/dev/null || echo "No logs for $name" + done + fi +else + echo -e "\n๐Ÿณ ${RED}Docker is not installed or not running.${NC}" +fi + +# Historical CPU/memory usage with 'sar' +if command -v sar &> /dev/null; then + echo -e "\n๐Ÿ“Š Analyzing Memory and CPU Usage via sar (last 60 mins if possible)..." + + echo -e "\n๐Ÿ” Memory Usage (High Usage if >90%):" + sar -r | awk ' + BEGIN { OFS="\t"; print "Time", "%memused", "%commit", "Status" } + /^[0-9]/ { + memused = $4; commit = $8; + status = (memused+0 > 90 || commit+0 > 95) ? "โš ๏ธ HIGH" : "OK"; + printf "%s\t%s%%\t%s%%\t%s\n", $1, memused, commit, status; + }' + + echo -e "\n๐Ÿ” CPU Usage (High if %idle < 10 or %system > 90):" + sar -u | awk ' + BEGIN { OFS="\t"; print "Time", "%user", "%system", "%idle", "Status" } + /^[0-9]/ { + user = $3; sys = $5; idle = $8; + status = (idle+0 < 10 || sys+0 > 90) ? "โš ๏ธ HIGH" : "OK"; + printf "%s\t%s%%\t%s%%\t%s%%\t%s\n", $1, user, sys, idle, status; + }' +else + echo -e "\nโ„น๏ธ 'sar' (sysstat) is not installed. Skipping historical CPU/memory analysis." +fi + +echo -e "\nโœ… ${YELLOW}Done. Use this script after crashes or schedule it in cron for proactive monitoring.${NC}" \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100755 index 0000000..30ab3a2 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,413 @@ +--- +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 \ No newline at end of file diff --git a/docker-compose.yaml.10700.2024-02-22@14:53:34~ b/docker-compose.yaml.10700.2024-02-22@14:53:34~ new file mode 100755 index 0000000..194e6e7 --- /dev/null +++ b/docker-compose.yaml.10700.2024-02-22@14:53:34~ @@ -0,0 +1,162 @@ +version: "2.1" +services: + postgres: + restart: always + image: "postgres:15.1-alpine" + container_name: phoenixDB + networks: + - backend + ports: + - "5432:5432" + environment: + - DEBUG=false + - POSTGRES_DB=phoenix + - "POSTGRES_PASSWORD=${POSTGRES_PASSWORD}" + volumes: + - "./database:/var/lib/postgresql/data" + healthcheck: + test: + - CMD-SHELL + - pg_isready -U postgres + interval: 5s + timeout: 2s + retries: 5 + pgadmin: + image: dpage/pgadmin4 + container_name: pgadmin_container + networks: + - backend + - frontend + environment: + PGADMIN_DEFAULT_EMAIL: "pgadmin4@pgadmin.org" + PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_DEFAULT_PASSWORD} + PGADMIN_CONFIG_SERVER_MODE: 'False' + ports: + - "${PGADMIN_PORT:-5050}:80" + volumes: + - "pgadmin:/var/lib/pgadmin" + phoenix-app: + restart: always + image: "dennx/phoenix-app:beta-rc" + container_name: phoenixApp + volumes: + - "./app_custom:/usr/share/nginx/html/assets/custom" + networks: + - backend + - frontend + depends_on: + - phoenix-system + phoenix-system: + restart: always + image: "dennx/phoenix-system:beta-rc" + environment: + - "DB_HOST=phoenixDB" + - "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} + - SMTP_FROM=${SMTP_FROM} + - SMTP_TYPE=${SMTP_TYPE} + - SMTP_NAME=${SMTP_NAME} + - SMTP_HOST=${SMTP_HOST} + - SMTP_PORT=${SMTP_PORT} + - SMTP_SECURE=${SMTP_SECURE} + - SMTP_USER=${SMTP_USER} + - SMTP_PASS=${SMTP_PASS} + - SMTP_LOGGING=${SMTP_LOGGING} + - SMTP_DEBUG=${SMTP_DEBUG} + - SMTP_TLS_REJECT_UNAUTHORIZED=${SMTP_TLS_REJECT_UNAUTHORIZED} + - SMTP_SECURE_CONNECTION=${SMTP_SECURE_CONNECTION} + - ENV_MODE=${ENV_MODE} + command: ["npm", "run", "start:server"] + deploy: + replicas: 1 #change here if u want to have more replicas. Cant find a way to set via variable right now + networks: + - backend + depends_on: + postgres: + condition: service_healthy + phoenix-redis: + condition: service_healthy + volumes: + - "./assets:/usr/src/app/packages/dev-server/assets" + - "./server_custom:/usr/src/app/packages/dev-server/custom" + phoenix-worker: + restart: always + image: "dennx/phoenix-system:beta-rc" + networks: + - backend + environment: + - DB_HOST=phoenixDB + - "DB_PASSWORD=${POSTGRES_PASSWORD}" + - DB_USERNAME=postgres + - "SUPER_ADMIN_USER_PASSWORD=${SUPER_ADMIN_USER_PASSWORD}" + - REDIS_PASSWORD=${REDIS_PASSWORD} + command: ["npm", "run", "start:worker"] + depends_on: + postgres: + condition: service_healthy + volumes: + - "./assets:/usr/src/app/packages/dev-server/assets" + - "./server_custom:/usr/src/app/packages/dev-server/custom" + phoenix-redis: + image: 'bitnami/redis:latest' + container_name: redis + command: /opt/bitnami/scripts/redis/run.sh --maxmemory 100mb + user: root + networks: + - backend + restart: always + environment: + ALLOW_EMPTY_PASSWORD: "no" + REDIS_PASSWORD: ${REDIS_PASSWORD} + healthcheck: + test: [ "CMD", "redis-cli", "--raw", "incr", "ping" ] + volumes: + - "./redis/data:/bitnami/redis/data" + https_portal: + container_name: https_portal + image: "steveltn/https-portal:1.21" + restart: unless-stopped + user: "root" + networks: + - frontend # [ PgAdmin, Phoenix-App ] + - external # [ Outside of the World] + 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 + # FORCE_RENEW: 'true' + DOMAINS: + volumes: + - ./https_portal/data:/var/lib/https-portal # ssl_certs, vhost.d, htdocs + - ./https_portal/log:/var/log/nginx # nginx logs + depends_on: + - phoenix-app + - phoenix-system + - pgadmin + - phoenix-redis + - postgres + +networks: + backend: + driver: bridge + external: false + + frontend: + driver: bridge + external: false + + external: + driver: bridge + external: true + +volumes: + pgadmin: null diff --git a/docker-compose.yaml.6992.2024-02-22@13:09:06~ b/docker-compose.yaml.6992.2024-02-22@13:09:06~ new file mode 100755 index 0000000..194e6e7 --- /dev/null +++ b/docker-compose.yaml.6992.2024-02-22@13:09:06~ @@ -0,0 +1,162 @@ +version: "2.1" +services: + postgres: + restart: always + image: "postgres:15.1-alpine" + container_name: phoenixDB + networks: + - backend + ports: + - "5432:5432" + environment: + - DEBUG=false + - POSTGRES_DB=phoenix + - "POSTGRES_PASSWORD=${POSTGRES_PASSWORD}" + volumes: + - "./database:/var/lib/postgresql/data" + healthcheck: + test: + - CMD-SHELL + - pg_isready -U postgres + interval: 5s + timeout: 2s + retries: 5 + pgadmin: + image: dpage/pgadmin4 + container_name: pgadmin_container + networks: + - backend + - frontend + environment: + PGADMIN_DEFAULT_EMAIL: "pgadmin4@pgadmin.org" + PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_DEFAULT_PASSWORD} + PGADMIN_CONFIG_SERVER_MODE: 'False' + ports: + - "${PGADMIN_PORT:-5050}:80" + volumes: + - "pgadmin:/var/lib/pgadmin" + phoenix-app: + restart: always + image: "dennx/phoenix-app:beta-rc" + container_name: phoenixApp + volumes: + - "./app_custom:/usr/share/nginx/html/assets/custom" + networks: + - backend + - frontend + depends_on: + - phoenix-system + phoenix-system: + restart: always + image: "dennx/phoenix-system:beta-rc" + environment: + - "DB_HOST=phoenixDB" + - "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} + - SMTP_FROM=${SMTP_FROM} + - SMTP_TYPE=${SMTP_TYPE} + - SMTP_NAME=${SMTP_NAME} + - SMTP_HOST=${SMTP_HOST} + - SMTP_PORT=${SMTP_PORT} + - SMTP_SECURE=${SMTP_SECURE} + - SMTP_USER=${SMTP_USER} + - SMTP_PASS=${SMTP_PASS} + - SMTP_LOGGING=${SMTP_LOGGING} + - SMTP_DEBUG=${SMTP_DEBUG} + - SMTP_TLS_REJECT_UNAUTHORIZED=${SMTP_TLS_REJECT_UNAUTHORIZED} + - SMTP_SECURE_CONNECTION=${SMTP_SECURE_CONNECTION} + - ENV_MODE=${ENV_MODE} + command: ["npm", "run", "start:server"] + deploy: + replicas: 1 #change here if u want to have more replicas. Cant find a way to set via variable right now + networks: + - backend + depends_on: + postgres: + condition: service_healthy + phoenix-redis: + condition: service_healthy + volumes: + - "./assets:/usr/src/app/packages/dev-server/assets" + - "./server_custom:/usr/src/app/packages/dev-server/custom" + phoenix-worker: + restart: always + image: "dennx/phoenix-system:beta-rc" + networks: + - backend + environment: + - DB_HOST=phoenixDB + - "DB_PASSWORD=${POSTGRES_PASSWORD}" + - DB_USERNAME=postgres + - "SUPER_ADMIN_USER_PASSWORD=${SUPER_ADMIN_USER_PASSWORD}" + - REDIS_PASSWORD=${REDIS_PASSWORD} + command: ["npm", "run", "start:worker"] + depends_on: + postgres: + condition: service_healthy + volumes: + - "./assets:/usr/src/app/packages/dev-server/assets" + - "./server_custom:/usr/src/app/packages/dev-server/custom" + phoenix-redis: + image: 'bitnami/redis:latest' + container_name: redis + command: /opt/bitnami/scripts/redis/run.sh --maxmemory 100mb + user: root + networks: + - backend + restart: always + environment: + ALLOW_EMPTY_PASSWORD: "no" + REDIS_PASSWORD: ${REDIS_PASSWORD} + healthcheck: + test: [ "CMD", "redis-cli", "--raw", "incr", "ping" ] + volumes: + - "./redis/data:/bitnami/redis/data" + https_portal: + container_name: https_portal + image: "steveltn/https-portal:1.21" + restart: unless-stopped + user: "root" + networks: + - frontend # [ PgAdmin, Phoenix-App ] + - external # [ Outside of the World] + 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 + # FORCE_RENEW: 'true' + DOMAINS: + volumes: + - ./https_portal/data:/var/lib/https-portal # ssl_certs, vhost.d, htdocs + - ./https_portal/log:/var/log/nginx # nginx logs + depends_on: + - phoenix-app + - phoenix-system + - pgadmin + - phoenix-redis + - postgres + +networks: + backend: + driver: bridge + external: false + + frontend: + driver: bridge + external: false + + external: + driver: bridge + external: true + +volumes: + pgadmin: null diff --git a/nginx/includes/pgadmin.conf b/nginx/includes/pgadmin.conf new file mode 100755 index 0000000..9a73011 --- /dev/null +++ b/nginx/includes/pgadmin.conf @@ -0,0 +1,18 @@ +# pgAdmin reverse proxy (under subpath) +location /pgadmin4 { + proxy_pass http://pgadmin4-ui/; + proxy_set_header X-Script-Name /pgadmin4; + proxy_set_header X-Scheme $scheme; + proxy_set_header X-Forwarded-Proto $forwarded_proto; + # Include headers for proxying + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Proto $forwarded_proto; + # End of headers + proxy_redirect off; + + # โš ๏ธ Rewrite required to remove /pgadmin4 from the path + rewrite ^/pgadmin4(/.*)$ $1 break; +} \ No newline at end of file diff --git a/nginx/nginx.conf b/nginx/nginx.conf new file mode 100755 index 0000000..d2b45a6 --- /dev/null +++ b/nginx/nginx.conf @@ -0,0 +1,402 @@ +# Main process configuration +worker_processes 1; + +events { + worker_connections 1024; +} + +http { + geo $frontend_whitelist { + default 1; + 127.0.0.1 1; + 172.20.0.0/16 1; # Frontend Docker subnet + 5.75.153.161 1; # Grafana or monitoring + 167.235.254.4 1; # Ansible server IP + } + + geo $backend_whitelist { + default 1; + 127.0.0.1 1; + 172.19.0.0/16 1; # Backend Docker subnet + 5.75.153.161 1; # Grafana or monitoring + 167.235.254.4 1; # Ansible server IP + } + + # These settings ensure that $remote_addr reflects the real client IP forwarded by https-portal, which is needed for your allow rules to work correctly + # Recommended for resolving client IP behind proxy + # Docker networks where both frontend and backend containers communicate through NGINX. + # To avoid potential misclassification of real client IPs from backend routes. + # The set_real_ip_from directive doesnโ€™t allow access โ€” it just instructs NGINX to trust the X-Forwarded-For header from those IPs. + set_real_ip_from 172.20.0.0/16; # Replace with your Docker network subnet (matches your `frontend` network) + set_real_ip_from 172.19.0.0/16; # Replace with your Docker network subnet (matches your `backend` network) + real_ip_header X-Forwarded-For; + real_ip_recursive on; + + resolver 127.0.0.11 valid=10s; + resolver_timeout 5s; + + upstream phoenix_system_cluster { + zone phoenix_system_cluster 64k; + least_conn; + server phoenix-system:3000 resolve fail_timeout=1s max_fails=0; + # ADD_SYSTEM_SERVERS_HERE + } + + upstream phoenix_worker_cluster { + zone phoenix_worker_cluster 64k; + least_conn; + server phoenix-worker:3001 resolve fail_timeout=1s max_fails=0; + # ADD_WORKER_SERVERS_HERE + } + + server_tokens off; # Disable NGINX version tokens to avoid leaking NGINX version. + + # File handling & upload limits + sendfile on; + client_max_body_size 64m; + + # Prevent warning when setting many proxy headers, like we do + proxy_headers_hash_max_size 1024; + proxy_headers_hash_bucket_size 128; + + # Gzip compression (for better bandwidth efficiency) + gzip on; + gzip_min_length 1000; + gzip_proxied expired no-cache no-store private auth; + gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; + + # Trust the protocol from upstream proxy/load balancer + map $http_x_forwarded_proto $forwarded_proto { + default $scheme; + https https; + http http; + } + + # File types and default mime type + include /etc/nginx/mime.types; + default_type application/octet-stream; + + # ๐Ÿงฉ Logs + map $request_uri $loggable { + default 1; + ~^/stub_status 0; + ~^/health/system 0; + ~^/health/worker 0; + } + + log_format main_with_realip '$remote_addr - $realip_remote_addr [$time_local] ' + '"$request" $status $body_bytes_sent ' + '"$http_referer" "$http_user_agent"'; + + log_format json_compatible escape=json '{' + '"time":"$time_iso8601",' + '"remote_addr":"$remote_addr",' + '"proxy_addr":"$proxy_protocol_addr",' + '"x_forwarded_for":"$http_x_forwarded_for",' + '"request_method":"$request_method",' + '"request_uri":"$request_uri",' + '"status":$status,' + '"body_bytes_sent":$body_bytes_sent,' + '"request_time":$request_time,' + '"upstream_response_time":"$upstream_response_time",' + '"http_referer":"$http_referer",' + '"http_user_agent":"$http_user_agent",' + '"host":"$host",' + '"realip":"$realip_remote_addr"' + '}'; + + access_log /var/log/nginx/access_json.log json_compatible if=$loggable; # JSON format for Loki + access_log /var/log/nginx/access.log main_with_realip if=$loggable; + # End of logs + + ################################################################## + # ๐Ÿงฉ HTTP Server Block + ################################################################## + server { + listen 80; + server_name _; + + # Security headers + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-XSS-Protection "1; mode=block" always; + add_header X-Content-Type-Options "nosniff" always; + add_header Referrer-Policy "no-referrer-when-downgrade" always; + + root /usr/share/nginx/html; + index index.html index.htm; + + # Frontend SPA fallback + location / { + try_files $uri $uri/ /index.html; + } + + # Backend API routes + location /backend-api/ { + proxy_pass http://phoenix_system_cluster/; + # Include headers for proxying + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Proto $forwarded_proto; + # End of headers + # Increase timeout settings for file uploads + proxy_connect_timeout 600; + proxy_send_timeout 600; + proxy_read_timeout 600; + send_timeout 600; + } + + location /admin-api { + proxy_pass http://phoenix_system_cluster/admin-api; + # Include headers for proxying + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Proto $forwarded_proto; + # End of headers + } + + location /remote-assets { + proxy_pass http://phoenix_system_cluster/remote-assets; + # Include headers for proxying + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Proto $forwarded_proto; + # End of headers + } + + location /sti { + proxy_pass http://phoenix_system_cluster/sti; + # Include headers for proxying + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Proto $forwarded_proto; + # End of headers + } + + # WebSocket support + location /ws { + proxy_pass http://phoenix_system_cluster/graphql; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + # Include headers for proxying + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Proto $forwarded_proto; + # End of headers + } + + # Reverse proxy for pgAdmin (subpath support) + include /etc/nginx/includes/*.conf; + + # Health check endpoints -> used by the health check exporter + location /health/system { + proxy_pass http://phoenix_system_cluster/health; + # Secure the health check endpoint + if ($backend_whitelist = 0) { + return 403; + } + # End of security + # Include headers for proxying + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $forwarded_proto; + # End of headers + } + + # location /health/system/metrics { + # proxy_pass http://phoenix_system_cluster/health/metrics; + # # Secure the health check endpoint + # # if ($backend_whitelist = 0) { + # # return 403; + # # } + # # End of security + # # Include headers for proxying + # proxy_set_header Host $host; + # proxy_set_header X-Real-IP $remote_addr; + # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + # proxy_set_header X-Forwarded-Proto $forwarded_proto; + # # End of headers + # } + + location /health/worker { + proxy_pass http://phoenix_worker_cluster/health; + # Secure the health check endpoint + if ($backend_whitelist = 0) { + return 403; + } + # End of security + # Include headers for proxying + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $forwarded_proto; + # End of headers + } + + # location /health/worker/metrics { + # proxy_pass http://phoenix_worker_cluster/health/metrics; + # # Secure the health check endpoint + # # if ($backend_whitelist = 0) { + # # return 403; + # # } + # # End of security + # # Include headers for proxying + # proxy_set_header Host $host; + # proxy_set_header X-Real-IP $remote_addr; + # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + # proxy_set_header X-Forwarded-Proto $forwarded_proto; + # # End of headers + # } + + location /stub_status { + stub_status; + # Secure the stub status endpoint + if ($frontend_whitelist = 0) { + return 403; + } + # End of security + } + } + + ################################################################## + # ๐Ÿ” HTTPS Server Block + ################################################################## + server { + listen 443 ssl; + http2 on; + server_name _; + + # Security headers + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-XSS-Protection "1; mode=block" always; + add_header X-Content-Type-Options "nosniff" always; + add_header Referrer-Policy "no-referrer-when-downgrade" always; + + ssl_certificate /etc/nginx/external-certificate/certificate.crt; + ssl_certificate_key /etc/nginx/external-certificate/certificate.key; + + root /usr/share/nginx/html; + index index.html index.htm; + + location / { + try_files $uri $uri/ /index.html; + } + + # Secure API routes + location /backend-api/ { + proxy_pass http://phoenix_system_cluster/; + # Include headers for proxying + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Proto $forwarded_proto; + # End of headers + # Increase timeout settings for file uploads + proxy_connect_timeout 600; + proxy_send_timeout 600; + proxy_read_timeout 600; + send_timeout 600; + } + + location /admin-api { + proxy_pass http://phoenix_system_cluster/admin-api; + # Include headers for proxying + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Proto $forwarded_proto; + # End of headers + } + + location /remote-assets { + proxy_pass http://phoenix_system_cluster/remote-assets; + # Include headers for proxying + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Proto $forwarded_proto; + # End of headers + } + + location /sti { + proxy_pass http://phoenix_system_cluster/sti; + # Include headers for proxying + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Proto $forwarded_proto; + # End of headers + } + + location /ws { + proxy_pass http://phoenix_system_cluster/graphql; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + # Include headers for proxying + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Proto $forwarded_proto; + # End of headers + } + + # Reverse proxy for pgAdmin (subpath support) + include /etc/nginx/includes/*.conf; + + location /health/system { + proxy_pass http://phoenix_system_cluster/health; + # Secure the health check endpoint + if ($backend_whitelist = 0) { + return 403; + } + # End of security + # Include headers for proxying + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $forwarded_proto; + # End of headers + } + + location /health/worker { + proxy_pass http://phoenix_worker_cluster/health; + # Secure the health check endpoint + if ($backend_whitelist = 0) { + return 403; + } + # End of security + # Include headers for proxying + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $forwarded_proto; + # End of headers + } + + location /stub_status { + stub_status; + # Secure the stub status endpoint + if ($frontend_whitelist = 0) { + return 403; + } + # End of security + } + } +} \ No newline at end of file diff --git a/server_custom/config.ts b/server_custom/config.ts new file mode 100755 index 0000000..0210844 --- /dev/null +++ b/server_custom/config.ts @@ -0,0 +1,253 @@ +/* tslint:disable:no-console */ +import { AssetServerPlugin } from '@phoenix/asset-server-plugin'; +import { ADMIN_API_PATH, API_PORT, SHOP_API_PATH, SUPER_ADMIN_USER_IDENTIFIER } from '@phoenix/common'; +import { DefaultJobQueuePlugin, WinstonLogger, LogLevel, RedisSessionCachePlugin, SystemConfig, TypeOrmLogger } from '@phoenix/core'; +import { EmailPlugin, EmailPluginOptions, FileBasedTemplateLoader, defaultEmailHandlers } from '@phoenix/email-plugin'; +import path from 'path'; +import { ConnectionOptions } from 'typeorm'; +// Import EmailSettingsService + +//DEV for now +// import { BonnEmailEventHandler } from './plugins/bonn-api-plugin/handler/bonn-email-handler'; + +/** + * Config settings used during development + */ +export const devConfig: SystemConfig = { + apiOptions: { + port: API_PORT, + // sslPort: API_SSL_PORT, + //sslCertPath: path.join(__dirname, './secrets/certificate.crt'), + //sslKeyPath: path.join(__dirname, './secrets/certificate.key'), + adminApiPath: ADMIN_API_PATH, + shopApiPath: SHOP_API_PATH, + cors: { + origin: true, + credentials: true, + }, + adminApiPlayground: true + }, + authOptions: { + disableAuth: true, + sessionSecret: 'some-secret', + requireVerification: false, + tokenMethod: "bearer", + superadminCredentials: { + identifier: SUPER_ADMIN_USER_IDENTIFIER, + password: process.env.SUPER_ADMIN_USER_PASSWORD || 'superadmin' + } + }, + dbConnectionOptions: { + // synchronize: true, + // logging: true, + logger: new TypeOrmLogger(), + migrations: [path.join(__dirname, 'migrations/*.ts')], + ...getDbConfig(), + // migrationsRun: true, + // migrations: ["migration/*.js"], + // cli: { + // migrationsDir: "migration" + // } + // logging: ["error"] + }, + // dbConnectionOptionsEx: [{ + // name: "sl", + // synchronize: false, + // host: 'localhost', + // username: 'sa', + // password: 'sa', + // database: 'SL_MWAWI', + // options: { encrypt: false, instanceName: "" }, + // extra: { trustedConnection: false }, + // logger: new TypeOrmLogger(), + // type: 'mssql' + // } as any], + // paymentOptions: { + // // paymentMethodHandlers: [examplePaymentHandler], + // }, + customFields: { + + Product: [ + // { + // name: 'customFieldx', + // type: 'string', + // } + + ], + DocumentLineItem: [ + + ], + }, + searchableFields: { + processResource: [ + "scanId" + ] + }, + logger: new WinstonLogger({ level: LogLevel.Debug }), + workerLogger: new WinstonLogger({ level: LogLevel.Info }), + importExportOptions: { + importProductAssetsDir: path.join(__dirname, 'import', 'product-assets'), + }, + defaults: { + defaultTakeNumber: 100, + }, + plugins: [ + // not needed for local dev + RedisSessionCachePlugin.init({ + namespace: 'phx-session', + redisOptions: { + host: process.env.REDIS_HOST || 'redis', + port: process.env.REDIS_PORT ? parseInt(process.env.REDIS_PORT) : 6379, + db: process.env.REDIS_DB ? parseInt(process.env.REDIS_DB) : 0, + password: process.env.REDIS_PASSWORD || 'admin' + } + }), + AssetServerPlugin.init({ + route: 'remote-assets', + assetUploadDir: path.join(__dirname, 'assets'), + port: 5002, + assetUrlPrefix: "\\remote-assets\\" // to make it relative for client + }), + // only 4 dev + // BonnAPIPlugin.init({ + // callerID: 'b64f845c-e4ed-43e9-b1f8-2e0b274afde0', + // apikey: 'ab9748dd-ac5f-40d8-954c-5c6d01092d80', + // XAccessToken: '48jerefi21r9itwp7ax88fxv2v20blhh', + // lotInfoUrl: 'https://api.zf.com/ZFMessTraceAuxSvc/v2.0/bptrace/lot-info', + // emailReceiver: 'ds@cts-schmid.de', + // autoBelegReportId: "9d77ddff-afec-4412-97dd-9272b497e0c3", + // printerHost: 'DESKTOP-OEEV0PG', + // MESAssignLotUrl: "" + // }), + // BonnAPIPlugin.init({ + // callerID: '18265a9e-7792-4671-88b2-8fa2ac4af5d4', + // apikey: '83997009-248c-472d-8579-5ec681c29daa', + // XAccessToken: 'gjyntdym13u7hsb8wxnk0bfwnxko52xo', + // lotInfoUrl: 'https://apidev.zf.com/ZFMessTraceAuxSvc/v1.0/bptrace/lot-info' + // }), + // ReinerSCTPlugin.init( + // { + // hostname: 'https://timecard.bonn-unternehmensgruppe.de', + // username: 'ctsapi', + // password: 'Tje6tiuEsY' + // } + // ) + // , + //just for dev for now + // EdiTransusPlugin.init({ + // url: "https://webconnect.transus.com/exchange.asmx", + // clientId: "10904548", + // clientKey: "R304WGXHKBZG" + // }), + DefaultJobQueuePlugin.init({}), + // DefaultStoragePlaceRankPlugin.init({}) + // new DefaultSearchPlugin(), + // new ElasticsearchPlugin({ + // host: 'http://192.168.99.100', + // port: 9200, + // }), + // DocusignPlugin.init({ + // devMode:true, + // handlers: defaultDocusignHandlers, + // assetDownloadDir: path.join(__dirname, 'docusign'), + // assetUploadDir: path.join(__dirname, 'docusign'), + // port: API_PORT, + // route: "docusign" + // }), + EmailPlugin.init({ + route: 'mailbox', + handlers: [...defaultEmailHandlers], + // Dynamic Email Templates + templateLoader: new FileBasedTemplateLoader(path.join(__dirname, '../email-plugin/templates')), + outputPath: path.join(__dirname, 'test-emails'), + globalTemplateVars: { + verifyEmailAddressUrl: 'http://localhost:4201/verify', + passwordResetUrl: 'http://localhost:4201/reset-password', + changeEmailAddressUrl: 'http://localhost:4201/change-email-address', + }, + // transport: { + // type: 'smtp', + // host: '', + // port: null, + // secure: false, + // auth: { + // user: '', + // pass: '', + // }, + // tls: { + // rejectUnauthorized: false, + // }, + // } + } as EmailPluginOptions), + ], +}; + +function getDbConfig(): ConnectionOptions { + const dbType = process.env.DB || 'postgres'; + const dbHost = process.env.DB_HOST || 'localhost'; + const dbPort = +process.env.DB_PORT || 5432; + + const connectionPoolMax = process.env.CONNECTION_POOL_MAX ?? 20; + + const dbUsername = process.env.DB_USERNAME || 'postgres'; + const password = process.env.DB_PASSWORD || 'admin'; + const database = process.env.DB_NAME || 'phoenix' + + if (password == "admin") + console.warn("default postgres password is used!"); + + if (process.env.DB_HOST) + console.log(`using DB Host ${dbHost} from env`); + + console.log(`using Database ${database}`); + console.log(`using User ${dbUsername}`); + + switch (dbType) { + case 'postgres': + console.log('Using postgres connection at ' + dbHost); + return { + synchronize: true, + type: 'postgres', + //host: '127.0.0.1', + host: dbHost, + port: dbPort, + username: dbUsername, + password: password, + database: database, + // logging: "all", + extra: { + max: connectionPoolMax + }, + cache: { + alwaysEnabled: false, + duration: 10000 + } + }; + case 'sqlite': + console.log('Using sqlite connection'); + return { + type: 'sqlite', + database: path.join(__dirname, 'phoenix.sqlite'), + }; + case 'sqljs': + console.log('Using sql.js connection'); + return { + type: 'sqljs', + autoSave: true, + database: new Uint8Array([]), + location: path.join(__dirname, 'phoenix.sqlite'), + }; + case 'mysql': + default: + console.log('Using mysql connection'); + return { + synchronize: true, + type: 'mysql', + host: '192.168.99.100', + port: 3306, + username: 'root', + password: '', + database: 'phoenix-dev', + }; + } +}