Wire Coolify domain to SITE_NAME and document env template
SERVICE_FQDN_FRONTEND from the frontend domain drives site creation and nginx headers; coolify.env.example adds CUSTOM_IMAGE/CUSTOM_TAG for Jenkins registry pulls. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
cacbce384f
commit
f2f7e6355d
6 changed files with 102 additions and 63 deletions
|
|
@ -28,8 +28,8 @@ See [docs/JENKINS.md](docs/JENKINS.md).
|
||||||
## Coolify deploy (you configure)
|
## Coolify deploy (you configure)
|
||||||
|
|
||||||
1. Docker Compose from this git repo, file `docker-compose.yml`
|
1. Docker Compose from this git repo, file `docker-compose.yml`
|
||||||
2. Env vars from [`example.env`](example.env) — use `CUSTOM_TAG` from latest green Jenkins build
|
2. Env vars from [`coolify.env.example`](coolify.env.example) — `CUSTOM_IMAGE`, `CUSTOM_TAG` from latest green Jenkins build (`dist/coolify-image.env`)
|
||||||
3. Domain on service **`frontend`**, port **`8080`**
|
3. Domain on service **`frontend`**, port **`8080`** — Coolify sets `SERVICE_FQDN_FRONTEND`; compose uses it for `SITE_NAME` / `FRAPPE_SITE_NAME_HEADER`
|
||||||
|
|
||||||
See [docs/COOLIFY_DEPLOY.md](docs/COOLIFY_DEPLOY.md).
|
See [docs/COOLIFY_DEPLOY.md](docs/COOLIFY_DEPLOY.md).
|
||||||
|
|
||||||
|
|
|
||||||
36
coolify.env.example
Normal file
36
coolify.env.example
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
# Paste into Coolify → erpnext service → Environment Variables
|
||||||
|
# After Jenkins green build, copy CUSTOM_IMAGE / CUSTOM_TAG from dist/coolify-image.env
|
||||||
|
|
||||||
|
# --- Custom image (required — from Jenkins Forgejo registry) ---
|
||||||
|
CUSTOM_IMAGE=git.aexoradao.com/epistemophiliac/erpnext
|
||||||
|
CUSTOM_TAG=main-26933f3
|
||||||
|
PULL_POLICY=always
|
||||||
|
|
||||||
|
# --- Secrets (required — change before first deploy) ---
|
||||||
|
DB_PASSWORD=replace-with-strong-secret
|
||||||
|
ADMIN_PASSWORD=replace-with-strong-secret
|
||||||
|
|
||||||
|
# --- Domain (automatic — do NOT set unless overriding) ---
|
||||||
|
# 1. In Coolify UI: add domain on service "frontend", port 8080
|
||||||
|
# 2. Coolify sets SERVICE_FQDN_FRONTEND → compose uses it for SITE_NAME + nginx header
|
||||||
|
# 3. Deploy AFTER domain is assigned (first deploy creates the Frappe site)
|
||||||
|
#
|
||||||
|
# SITE_NAME=
|
||||||
|
# FRAPPE_SITE_NAME_HEADER=
|
||||||
|
|
||||||
|
# --- Apps installed on first site creation only (order matters) ---
|
||||||
|
INSTALL_APPS=erpnext,payments,hrms,lending,lms
|
||||||
|
|
||||||
|
# --- Redeploy behaviour ---
|
||||||
|
MIGRATE_SITES=true
|
||||||
|
RESTART_POLICY=unless-stopped
|
||||||
|
|
||||||
|
# --- Optional tuning ---
|
||||||
|
GUNICORN_THREADS=4
|
||||||
|
GUNICORN_WORKERS=2
|
||||||
|
GUNICORN_TIMEOUT=120
|
||||||
|
PROXY_READ_TIMEOUT=120
|
||||||
|
CLIENT_MAX_BODY_SIZE=50m
|
||||||
|
UPSTREAM_REAL_IP_ADDRESS=127.0.0.1
|
||||||
|
UPSTREAM_REAL_IP_HEADER=X-Forwarded-For
|
||||||
|
UPSTREAM_REAL_IP_RECURSIVE=off
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
# ERPNext production stack for Coolify.
|
# ERPNext production stack for Coolify.
|
||||||
# Based on https://github.com/frappe/frappe_docker (compose.yaml + mariadb + redis).
|
# Domain: assign in Coolify UI → service `frontend` → port 8080.
|
||||||
# Coolify: assign your domain to service `frontend` on port 8080.
|
# SITE_NAME + FRAPPE_SITE_NAME_HEADER use SERVICE_FQDN_FRONTEND automatically.
|
||||||
|
# Image: set CUSTOM_IMAGE / CUSTOM_TAG from Jenkins (dist/coolify-image.env).
|
||||||
# No ports: — routing uses SERVICE_URL_FRONTEND_8080.
|
# No ports: — routing uses SERVICE_URL_FRONTEND_8080.
|
||||||
|
|
||||||
x-customizable-image: &customizable_image
|
x-customizable-image: &customizable_image
|
||||||
|
|
@ -99,12 +100,13 @@ services:
|
||||||
- >
|
- >
|
||||||
B=/usr/local/bin/bench;
|
B=/usr/local/bin/bench;
|
||||||
SITE=$$SITE_NAME;
|
SITE=$$SITE_NAME;
|
||||||
|
if [ -z "$$SITE" ]; then echo "[create-site] ERROR: SITE_NAME empty — assign domain to frontend:8080 in Coolify (SERVICE_FQDN_FRONTEND)"; exit 1; fi;
|
||||||
wait-for-it -t 120 db:3306;
|
wait-for-it -t 120 db:3306;
|
||||||
wait-for-it -t 120 redis-cache:6379;
|
wait-for-it -t 120 redis-cache:6379;
|
||||||
wait-for-it -t 120 redis-queue:6379;
|
wait-for-it -t 120 redis-queue:6379;
|
||||||
if [ -d "sites/$$SITE" ]; then echo "[create-site] exists"; $$B use "$$SITE"; else echo "[create-site] creating"; INSTALL_ARGS=""; IFS=',' read -r -a apps <<< "$$INSTALL_APPS"; for app in "$${apps[@]}"; do INSTALL_ARGS="$$INSTALL_ARGS --install-app $$app"; done; $$B new-site "$$SITE" --mariadb-user-host-login-scope='%' --admin-password "$$ADMIN_PASSWORD" --db-root-password "$$DB_PASSWORD" $$INSTALL_ARGS --set-default; fi
|
if [ -d "sites/$$SITE" ]; then echo "[create-site] exists"; $$B use "$$SITE"; else echo "[create-site] creating"; INSTALL_ARGS=""; IFS=',' read -r -a apps <<< "$$INSTALL_APPS"; for app in "$${apps[@]}"; do INSTALL_ARGS="$$INSTALL_ARGS --install-app $$app"; done; $$B new-site "$$SITE" --mariadb-user-host-login-scope='%' --admin-password "$$ADMIN_PASSWORD" --db-root-password "$$DB_PASSWORD" $$INSTALL_ARGS --set-default; fi
|
||||||
environment:
|
environment:
|
||||||
- 'SITE_NAME=${SITE_NAME:-erp.example.com}'
|
- 'SITE_NAME=${SITE_NAME:-${SERVICE_FQDN_FRONTEND}}'
|
||||||
- 'ADMIN_PASSWORD=${ADMIN_PASSWORD:-changeme}'
|
- 'ADMIN_PASSWORD=${ADMIN_PASSWORD:-changeme}'
|
||||||
- 'DB_PASSWORD=${DB_PASSWORD:-changeme}'
|
- 'DB_PASSWORD=${DB_PASSWORD:-changeme}'
|
||||||
- 'INSTALL_APPS=${INSTALL_APPS:-erpnext,payments,hrms,lending,lms}'
|
- 'INSTALL_APPS=${INSTALL_APPS:-erpnext,payments,hrms,lending,lms}'
|
||||||
|
|
@ -172,9 +174,10 @@ services:
|
||||||
- nginx-entrypoint.sh
|
- nginx-entrypoint.sh
|
||||||
environment:
|
environment:
|
||||||
- SERVICE_URL_FRONTEND_8080
|
- SERVICE_URL_FRONTEND_8080
|
||||||
|
- SERVICE_FQDN_FRONTEND
|
||||||
- 'BACKEND=backend:8000'
|
- 'BACKEND=backend:8000'
|
||||||
- 'SOCKETIO=websocket:9000'
|
- 'SOCKETIO=websocket:9000'
|
||||||
- 'FRAPPE_SITE_NAME_HEADER=${FRAPPE_SITE_NAME_HEADER:-${SITE_NAME:-erp.example.com}}'
|
- 'FRAPPE_SITE_NAME_HEADER=${FRAPPE_SITE_NAME_HEADER:-${SERVICE_FQDN_FRONTEND}}'
|
||||||
- 'UPSTREAM_REAL_IP_ADDRESS=${UPSTREAM_REAL_IP_ADDRESS:-127.0.0.1}'
|
- 'UPSTREAM_REAL_IP_ADDRESS=${UPSTREAM_REAL_IP_ADDRESS:-127.0.0.1}'
|
||||||
- 'UPSTREAM_REAL_IP_HEADER=${UPSTREAM_REAL_IP_HEADER:-X-Forwarded-For}'
|
- 'UPSTREAM_REAL_IP_HEADER=${UPSTREAM_REAL_IP_HEADER:-X-Forwarded-For}'
|
||||||
- 'UPSTREAM_REAL_IP_RECURSIVE=${UPSTREAM_REAL_IP_RECURSIVE:-off}'
|
- 'UPSTREAM_REAL_IP_RECURSIVE=${UPSTREAM_REAL_IP_RECURSIVE:-off}'
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,11 @@
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
- Coolify v4+ with Docker Compose support
|
- Coolify v4+ with Docker Compose support
|
||||||
- Jenkins green build published image to `git.aexoradao.com/epistemophiliac/erpnext`
|
- Jenkins green build → image in Forgejo Packages
|
||||||
- Server: **minimum 4 GB RAM**, **8 GB+** recommended (custom image + LMS frontend assets)
|
- **4 GB+ RAM** (8 GB+ recommended)
|
||||||
- Public domain (e.g. `erp.yourdomain.com`)
|
- Compose file: `docker-compose.yml`
|
||||||
|
|
||||||
## 1. Create the Coolify service (you do this)
|
## 1. Create the Coolify service
|
||||||
|
|
||||||
| Setting | Value |
|
| Setting | Value |
|
||||||
|---------|--------|
|
|---------|--------|
|
||||||
|
|
@ -16,53 +16,55 @@
|
||||||
| Branch | `main` |
|
| Branch | `main` |
|
||||||
| Compose file | `docker-compose.yml` |
|
| Compose file | `docker-compose.yml` |
|
||||||
|
|
||||||
## 2. Environment variables
|
## 2. Environment variables (Coolify UI)
|
||||||
|
|
||||||
From latest **green Jenkins build**, use `dist/coolify-image.env` or:
|
Copy from [`coolify.env.example`](../coolify.env.example). **Required before first deploy:**
|
||||||
|
|
||||||
| Variable | Required | Example | Notes |
|
| Variable | Set in Coolify? | Source |
|
||||||
|----------|----------|---------|-------|
|
|----------|----------------|--------|
|
||||||
| `CUSTOM_IMAGE` | yes | `git.aexoradao.com/epistemophiliac/erpnext` | Forgejo registry |
|
| `CUSTOM_IMAGE` | yes | Jenkins artifact / `dist/coolify-image.env` |
|
||||||
| `CUSTOM_TAG` | yes | `main-3eefb73` or `main` | Pin SHA for prod; `main` = latest CI |
|
| `CUSTOM_TAG` | yes | e.g. `main-26933f3` (pin) or `main` |
|
||||||
| `PULL_POLICY` | yes | `always` | Pull from registry on deploy |
|
| `PULL_POLICY` | yes | `always` |
|
||||||
| `DB_PASSWORD` | yes | strong secret | MariaDB root |
|
| `DB_PASSWORD` | yes | strong secret |
|
||||||
| `SITE_NAME` | yes | `erp.yourdomain.com` | Must match domain |
|
| `ADMIN_PASSWORD` | yes | Frappe `Administrator` password |
|
||||||
| `ADMIN_PASSWORD` | yes | strong secret | Frappe login |
|
| `INSTALL_APPS` | yes | `erpnext,payments,hrms,lending,lms` |
|
||||||
| `FRAPPE_SITE_NAME_HEADER` | yes | same as `SITE_NAME` | Single-site routing |
|
| `SITE_NAME` | **no** (auto) | From Coolify domain via `SERVICE_FQDN_FRONTEND` |
|
||||||
| `INSTALL_APPS` | yes | `erpnext,payments,hrms,lending,lms` | First site only |
|
| `FRAPPE_SITE_NAME_HEADER` | **no** (auto) | Same as domain via `SERVICE_FQDN_FRONTEND` |
|
||||||
| `MIGRATE_SITES` | no | `true` | Migrate on redeploy |
|
|
||||||
|
|
||||||
> **Coolify env cache:** Changing defaults in `docker-compose.yml` does not update values already stored in Coolify. Edit them in the UI.
|
> **Coolify env cache:** If you previously set `SITE_NAME=erp.example.com` in Coolify, **delete it** so compose defaults use your real domain. Changing `docker-compose.yml` defaults alone does not update stored values.
|
||||||
|
|
||||||
## 3. Domain routing
|
## 3. Domain (before first deploy)
|
||||||
|
|
||||||
1. Add domain: `erp.yourdomain.com`
|
1. Coolify → your service → **Domains**
|
||||||
2. Attach to service **`frontend`**
|
2. Add domain, e.g. `erp.aexoradao.com`
|
||||||
3. Port **`8080`**
|
3. Attach to service **`frontend`**, port **`8080`**
|
||||||
|
4. Coolify writes `SERVICE_FQDN_FRONTEND=erp.aexoradao.com` into the stack `.env`
|
||||||
|
5. Compose sets:
|
||||||
|
- `create-site` → `SITE_NAME=erp.aexoradao.com`
|
||||||
|
- `frontend` → `FRAPPE_SITE_NAME_HEADER=erp.aexoradao.com`
|
||||||
|
|
||||||
## 4. First deploy timeline
|
**Order matters:** assign domain **then** deploy. If `create-site` runs with an empty site name, the stack exits with a clear error.
|
||||||
|
|
||||||
|
## 4. First deploy
|
||||||
|
|
||||||
```text
|
```text
|
||||||
pull custom image → db (healthy) → redis → configurator
|
pull CUSTOM_IMAGE:TAG → db → redis → configurator
|
||||||
→ create-site (install erpnext + payments + hrms + lending + lms, ~10–20 min)
|
→ create-site (install apps, ~10–20 min)
|
||||||
→ migrator → backend / workers / frontend
|
→ migrator → backend / workers / frontend
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Login: `https://your-domain` — user `Administrator`, password = `ADMIN_PASSWORD`.
|
||||||
|
|
||||||
## 5. Upgrades
|
## 5. Upgrades
|
||||||
|
|
||||||
1. Push app changes to git → Jenkins builds new image
|
1. Jenkins builds new image → update `CUSTOM_TAG` in Coolify
|
||||||
2. Set `CUSTOM_TAG` in Coolify to new `main-<sha>`
|
2. Redeploy — `migrator` runs `bench migrate`
|
||||||
3. Redeploy — `migrator` runs `bench migrate`
|
|
||||||
|
|
||||||
## Apps in the image
|
|
||||||
|
|
||||||
See [`apps.json`](../apps.json). Site install list: `INSTALL_APPS` in [`example.env`](../example.env).
|
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
| Symptom | Fix |
|
| Symptom | Fix |
|
||||||
|---------|-----|
|
|---------|-----|
|
||||||
| Image pull failed | Check registry login on Coolify host; verify tag exists in Forgejo Packages |
|
| `SITE_NAME empty` on create-site | Assign domain on `frontend:8080` before deploy |
|
||||||
| create-site fails on LMS | Ensure `payments` is in `INSTALL_APPS` before `lms` |
|
| Wrong site / 404 nginx | Delete old `SITE_NAME` in Coolify UI; ensure header matches domain |
|
||||||
| 502 / unhealthy frontend | Wait for create-site; check `backend` health |
|
| Site created with wrong name | Wipe `sites` volume or rename site manually — env change alone won't rename |
|
||||||
| Wrong site | `SITE_NAME` and `FRAPPE_SITE_NAME_HEADER` must match Coolify domain |
|
| Image pull failed | Check `CUSTOM_IMAGE` / `CUSTOM_TAG` in Forgejo Packages |
|
||||||
|
|
|
||||||
28
example.env
28
example.env
|
|
@ -1,38 +1,24 @@
|
||||||
# Copy to Coolify Environment Variables (Service > Environment).
|
# Reference for local testing (`docker compose --env-file example.env config`).
|
||||||
# Image tags come from Jenkins (Forgejo container registry).
|
# For Coolify, use coolify.env.example — domain comes from SERVICE_FQDN_FRONTEND.
|
||||||
|
|
||||||
# Custom image built by Jenkins (apps: ERPNext, HRMS, Lending, LMS + payments)
|
# Custom image (match latest Jenkins build — see dist/coolify-image.env)
|
||||||
CUSTOM_IMAGE=git.aexoradao.com/epistemophiliac/erpnext
|
CUSTOM_IMAGE=git.aexoradao.com/epistemophiliac/erpnext
|
||||||
CUSTOM_TAG=main
|
CUSTOM_TAG=main
|
||||||
PULL_POLICY=always
|
PULL_POLICY=always
|
||||||
|
RESTART_POLICY=unless-stopped
|
||||||
|
|
||||||
# Frappe major line — must match apps.json branches (version-16)
|
# Local-only overrides when not using Coolify magic vars
|
||||||
FRAPPE_BRANCH=version-16
|
|
||||||
|
|
||||||
# MariaDB root password (required — change before production)
|
|
||||||
DB_PASSWORD=changeme
|
|
||||||
|
|
||||||
# Frappe site name — MUST match your Coolify domain
|
|
||||||
SITE_NAME=erp.example.com
|
SITE_NAME=erp.example.com
|
||||||
|
|
||||||
# Frappe Administrator password
|
|
||||||
ADMIN_PASSWORD=changeme
|
|
||||||
|
|
||||||
# Nginx site header — for single-site Coolify, same as SITE_NAME
|
|
||||||
FRAPPE_SITE_NAME_HEADER=erp.example.com
|
FRAPPE_SITE_NAME_HEADER=erp.example.com
|
||||||
|
|
||||||
# Apps installed on first site creation (comma-separated, order matters)
|
DB_PASSWORD=changeme
|
||||||
|
ADMIN_PASSWORD=changeme
|
||||||
INSTALL_APPS=erpnext,payments,hrms,lending,lms
|
INSTALL_APPS=erpnext,payments,hrms,lending,lms
|
||||||
|
|
||||||
# Run bench migrate on every deploy (set false to skip)
|
|
||||||
MIGRATE_SITES=true
|
MIGRATE_SITES=true
|
||||||
|
|
||||||
# Gunicorn tuning (optional)
|
|
||||||
GUNICORN_THREADS=4
|
GUNICORN_THREADS=4
|
||||||
GUNICORN_WORKERS=2
|
GUNICORN_WORKERS=2
|
||||||
GUNICORN_TIMEOUT=120
|
GUNICORN_TIMEOUT=120
|
||||||
|
|
||||||
# Proxy / upload limits (optional)
|
|
||||||
PROXY_READ_TIMEOUT=120
|
PROXY_READ_TIMEOUT=120
|
||||||
CLIENT_MAX_BODY_SIZE=50m
|
CLIENT_MAX_BODY_SIZE=50m
|
||||||
UPSTREAM_REAL_IP_ADDRESS=127.0.0.1
|
UPSTREAM_REAL_IP_ADDRESS=127.0.0.1
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,18 @@ else
|
||||||
err "[DC-03] missing SERVICE_URL_FRONTEND_8080 on frontend"
|
err "[DC-03] missing SERVICE_URL_FRONTEND_8080 on frontend"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if grep -q 'SERVICE_FQDN_FRONTEND' "$COMPOSE_FILE"; then
|
||||||
|
pass "[DC-07] SERVICE_FQDN_FRONTEND present (Coolify domain → SITE_NAME)"
|
||||||
|
else
|
||||||
|
warn "[DC-07] missing SERVICE_FQDN_FRONTEND — SITE_NAME will not track Coolify domain"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if grep -q 'CUSTOM_IMAGE' "$COMPOSE_FILE" && grep -q 'CUSTOM_TAG' "$COMPOSE_FILE"; then
|
||||||
|
pass "[DC-10] CUSTOM_IMAGE / CUSTOM_TAG configured for Jenkins registry"
|
||||||
|
else
|
||||||
|
warn "[DC-10] missing CUSTOM_IMAGE or CUSTOM_TAG in compose"
|
||||||
|
fi
|
||||||
|
|
||||||
# Bind mounts ./scripts on long-running services (heuristic)
|
# Bind mounts ./scripts on long-running services (heuristic)
|
||||||
if grep -E '^\s+-\s+['\''"]?\./scripts' "$COMPOSE_FILE" >/dev/null 2>&1; then
|
if grep -E '^\s+-\s+['\''"]?\./scripts' "$COMPOSE_FILE" >/dev/null 2>&1; then
|
||||||
if grep -B30 './scripts' "$COMPOSE_FILE" | grep -qE 'restart:\s+(unless-stopped|always)'; then
|
if grep -B30 './scripts' "$COMPOSE_FILE" | grep -qE 'restart:\s+(unless-stopped|always)'; then
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue