fix: decouple app URL from Coolify-managed SERVICE_FQDN_* variable

SERVICE_FQDN_* gets regenerated with a random hash on each Coolify save,
making custom domains impossible to persist. Introduce APP_URL as a single
user-controlled variable (never auto-generated) for all app URLs. Derive
VITE_BACKEND_WS_URL automatically from VITE_BASE_URL in aio_run.mjs so
only APP_URL needs to be set. SERVICE_FQDN_HOPPSCOTCH_80 is kept solely
for Coolify proxy routing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
thibaud-leclere 2026-05-11 17:08:34 +02:00
parent eae320c76d
commit d56fb7d3d4
4 changed files with 25 additions and 21 deletions

View file

@ -48,10 +48,9 @@ API_CLIENT_TAG=latest
#-----------------------Coolify Prod Local Defaults----------------# #-----------------------Coolify Prod Local Defaults----------------#
# Used only when running docker-compose.prod.yml locally. # Used only when running docker-compose.prod.yml locally.
# In production, Coolify auto-generates SERVICE_FQDN_* and SERVICE_URL_* from the # In production, set APP_URL once in Coolify's env vars UI — it never gets overwritten.
# domain configured in the Coolify UI (editable per deployment). # SERVICE_FQDN_HOPPSCOTCH_80 is only used by Coolify for proxy routing (value is managed by Coolify).
APP_URL=http://localhost:3000
SERVICE_FQDN_HOPPSCOTCH_80=http://localhost:3000 SERVICE_FQDN_HOPPSCOTCH_80=http://localhost:3000
SERVICE_FQDN_HOPPSCOTCH=http://localhost:3000
SERVICE_URL_HOPPSCOTCH=localhost:3000
SERVICE_PASSWORD_POSTGRES=testpass SERVICE_PASSWORD_POSTGRES=testpass
SERVICE_BASE64_HOPPSCOTCH=0123456789abcdef0123456789abcdef SERVICE_BASE64_HOPPSCOTCH=0123456789abcdef0123456789abcdef

View file

@ -118,17 +118,15 @@ Le compose prod utilise l'image AIO et un seul domaine Coolify :
- `/admin` : admin - `/admin` : admin
- `/backend` : backend GraphQL/API - `/backend` : backend GraphQL/API
Variables auto-générées par Coolify (éditables dans l'UI) : Variables à configurer dans Coolify :
- `SERVICE_FQDN_HOPPSCOTCH_80` : déclenche la génération du domaine public et la configuration du proxy - `APP_URL` : URL publique du service (ex: `https://hoppscotch.mondomaine.fr`). À renseigner une fois manuellement — jamais écrasée par Coolify. L'URL WebSocket est dérivée automatiquement au démarrage.
- `SERVICE_FQDN_HOPPSCOTCH` : URL publique avec schéma (`https://api-xxx.host.fr`) - `SERVICE_PASSWORD_POSTGRES` : mot de passe PostgreSQL généré par Coolify
- `SERVICE_URL_HOPPSCOTCH` : domaine sans schéma, utilisé pour l'URL WebSocket (`wss://`) - `SERVICE_BASE64_HOPPSCOTCH` : clé stable de 32 caractères pour `DATA_ENCRYPTION_KEY`, générée par Coolify
- `SERVICE_PASSWORD_POSTGRES` : mot de passe PostgreSQL généré
- `SERVICE_BASE64_HOPPSCOTCH` : clé stable de 32 caractères pour `DATA_ENCRYPTION_KEY`
Coolify génère un domaine aléatoire au premier déploiement. Il est ensuite `SERVICE_FQDN_HOPPSCOTCH_80` est géré par Coolify pour la configuration du proxy — sa valeur n'affecte pas l'app, seul `APP_URL` compte.
modifiable dans l'UI Coolify sur le service `hoppscotch`. Les URLs
app/admin/backend sont dérivées par sous-chemins automatiquement. Les URLs app/admin/backend sont dérivées de `APP_URL` par sous-chemins.
Démarrer avec le tag `latest` : Démarrer avec le tag `latest` :

View file

@ -34,6 +34,14 @@ function runChildProcessWithPrefix(command, args, prefix) {
return childProcess return childProcess
} }
// Derive VITE_BACKEND_WS_URL from VITE_BASE_URL when not explicitly set,
// so only APP_URL (→ VITE_BASE_URL) needs to be configured in Coolify.
if (!process.env.VITE_BACKEND_WS_URL && process.env.VITE_BASE_URL) {
process.env.VITE_BACKEND_WS_URL = process.env.VITE_BASE_URL
.replace(/^https:\/\//, "wss://")
.replace(/^http:\/\//, "ws://") + "/backend/graphql"
}
const envFileContent = Object.entries(process.env) const envFileContent = Object.entries(process.env)
.filter(([env]) => env.startsWith("VITE_")) .filter(([env]) => env.startsWith("VITE_"))
.sort(([envA], [envB]) => envA.localeCompare(envB)) .sort(([envA], [envB]) => envA.localeCompare(envB))

View file

@ -26,18 +26,17 @@ services:
- SERVICE_BASE64_HOPPSCOTCH - SERVICE_BASE64_HOPPSCOTCH
- DATABASE_URL=postgresql://postgres:${SERVICE_PASSWORD_POSTGRES}@hoppscotch-db:5432/${POSTGRES_DB:-hoppscotch} - DATABASE_URL=postgresql://postgres:${SERVICE_PASSWORD_POSTGRES}@hoppscotch-db:5432/${POSTGRES_DB:-hoppscotch}
- DATA_ENCRYPTION_KEY=${SERVICE_BASE64_HOPPSCOTCH} - DATA_ENCRYPTION_KEY=${SERVICE_BASE64_HOPPSCOTCH}
- REDIRECT_URL=${SERVICE_FQDN_HOPPSCOTCH} - REDIRECT_URL=${APP_URL}
- VITE_BASE_URL=${SERVICE_FQDN_HOPPSCOTCH} - VITE_BASE_URL=${APP_URL}
- VITE_SHORTCODE_BASE_URL=${SERVICE_FQDN_HOPPSCOTCH} - VITE_SHORTCODE_BASE_URL=${APP_URL}
- VITE_ADMIN_URL=${SERVICE_FQDN_HOPPSCOTCH}/admin - VITE_ADMIN_URL=${APP_URL}/admin
- VITE_BACKEND_GQL_URL=${SERVICE_FQDN_HOPPSCOTCH}/backend/graphql - VITE_BACKEND_GQL_URL=${APP_URL}/backend/graphql
- VITE_BACKEND_WS_URL=wss://${SERVICE_URL_HOPPSCOTCH}/backend/graphql - VITE_BACKEND_API_URL=${APP_URL}/backend/v1
- VITE_BACKEND_API_URL=${SERVICE_FQDN_HOPPSCOTCH}/backend/v1
- VITE_APP_TOS_LINK=${VITE_APP_TOS_LINK:-https://docs.hoppscotch.io/support/terms} - VITE_APP_TOS_LINK=${VITE_APP_TOS_LINK:-https://docs.hoppscotch.io/support/terms}
- VITE_APP_PRIVACY_POLICY_LINK=${VITE_APP_PRIVACY_POLICY_LINK:-https://docs.hoppscotch.io/support/privacy} - VITE_APP_PRIVACY_POLICY_LINK=${VITE_APP_PRIVACY_POLICY_LINK:-https://docs.hoppscotch.io/support/privacy}
- VITE_PROXYSCOTCH_ACCESS_TOKEN=${VITE_PROXYSCOTCH_ACCESS_TOKEN:-} - VITE_PROXYSCOTCH_ACCESS_TOKEN=${VITE_PROXYSCOTCH_ACCESS_TOKEN:-}
- ENABLE_SUBPATH_BASED_ACCESS=true - ENABLE_SUBPATH_BASED_ACCESS=true
- WHITELISTED_ORIGINS=${SERVICE_FQDN_HOPPSCOTCH}/backend,${SERVICE_FQDN_HOPPSCOTCH},${SERVICE_FQDN_HOPPSCOTCH}/admin - WHITELISTED_ORIGINS=${APP_URL}/backend,${APP_URL},${APP_URL}/admin
- TRUST_PROXY=${TRUST_PROXY:-true} - TRUST_PROXY=${TRUST_PROXY:-true}
depends_on: depends_on:
hoppscotch-db: hoppscotch-db: