feat: Update CI/CD workflow to trigger separate backend and dashboard deployments; enhance deployment documentation with Nginx proxy details and OAuth callback URLs
CI-CD / Bot Lint Test Build (push) Successful in 1m24s
CI-CD / Dashboard Lint Build (push) Successful in 14s
CI-CD / Deploy to Coolify (push) Failing after 3s

This commit is contained in:
2026-05-17 19:08:26 +02:00
parent 2b509ce9fe
commit cf564f2886
5 changed files with 188 additions and 97 deletions
+31 -10
View File
@@ -66,23 +66,44 @@ jobs:
- dashboard-checks
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
steps:
- name: Trigger Coolify deploy hook
- name: Trigger backend deploy
env:
COOLIFY_DEPLOY_HOOK_URL: ${{ secrets.COOLIFY_DEPLOY_HOOK_URL }}
COOLIFY_DEPLOY_TOKEN: ${{ secrets.COOLIFY_DEPLOY_TOKEN }}
HOOK_URL: ${{ secrets.COOLIFY_DEPLOY_HOOK_URL_BOT }}
HOOK_TOKEN: ${{ secrets.COOLIFY_DEPLOY_TOKEN_BOT }}
run: |
if [ -z "$COOLIFY_DEPLOY_HOOK_URL" ]; then
echo "Missing COOLIFY_DEPLOY_HOOK_URL secret"
if [ -z "$HOOK_URL" ]; then
echo "Missing COOLIFY_DEPLOY_HOOK_URL_BOT"
exit 1
fi
if [ -n "$COOLIFY_DEPLOY_TOKEN" ]; then
if [ -n "$HOOK_TOKEN" ]; then
curl --fail --show-error --silent \
-X POST \
-H "Authorization: Bearer $COOLIFY_DEPLOY_TOKEN" \
"$COOLIFY_DEPLOY_HOOK_URL"
-H "Authorization: Bearer $HOOK_TOKEN" \
"$HOOK_URL"
else
curl --fail --show-error --silent -X POST "$COOLIFY_DEPLOY_HOOK_URL"
curl --fail --show-error --silent -X POST "$HOOK_URL"
fi
echo "Coolify deploy triggered"
echo "Backend deploy triggered"
- name: Trigger dashboard deploy
env:
HOOK_URL: ${{ secrets.COOLIFY_DEPLOY_HOOK_URL_DASHBOARD }}
HOOK_TOKEN: ${{ secrets.COOLIFY_DEPLOY_TOKEN_DASHBOARD }}
run: |
if [ -z "$HOOK_URL" ]; then
echo "Missing COOLIFY_DEPLOY_HOOK_URL_DASHBOARD"
exit 1
fi
if [ -n "$HOOK_TOKEN" ]; then
curl --fail --show-error --silent \
-X POST \
-H "Authorization: Bearer $HOOK_TOKEN" \
"$HOOK_URL"
else
curl --fail --show-error --silent -X POST "$HOOK_URL"
fi
echo "Dashboard deploy triggered"
+105 -61
View File
@@ -9,12 +9,17 @@ This document covers production deployment for the `omo-bot` Coolify project wit
Recommended domains:
- `api.yourdomain.com` -> `omo-bot-backend`
- `admin.yourdomain.com` -> `omo-bot-dashboard`
- `api.openmicodyssey.com` -> `omo-bot-backend`
- `admin.openmicodyssey.com` -> `omo-bot-dashboard`
Recommended edge topology:
- Internet -> Nginx reverse proxy -> Coolify resources
- Nginx routes by hostname to backend/dashboard resource domains or internal ports
Optional same-origin pattern:
- `admin.yourdomain.com` serves dashboard and reverse-proxies `/admin/*` + `/health` to backend.
- `admin.openmicodyssey.com` serves dashboard and reverse-proxies `/admin/*` + `/health` to backend.
## 1. Create Coolify Project and Resources
@@ -22,13 +27,80 @@ Optional same-origin pattern:
2. Add resource `omo-bot-backend` from this repository:
- Build context: repository root
- Start command: `npm start`
- Port: `8787` (Admin API) if exposed
- Internal port: `8787` (Admin API)
3. Add resource `omo-bot-dashboard` from this repository:
- Base directory: `admin-dashboard`
- Build command: `npm run build`
- Publish directory: `dist`
- Internal port: `80` (typical static web port behind Coolify)
4. Configure domains for each resource and enable TLS certificates.
## 1.1 Nginx Reverse Proxy in Front of Coolify
Use this pattern when you want one public edge server in front of Coolify-managed services.
Recommended flow:
1. Public DNS for `api.openmicodyssey.com` and `admin.openmicodyssey.com` points to Nginx host.
2. Nginx terminates TLS and forwards traffic to Coolify resource domains or private IP:port targets.
3. Coolify resources stay private or restricted to internal network where possible.
Example host-based routing:
```nginx
server {
listen 80;
server_name api.openmicodyssey.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name api.openmicodyssey.com;
ssl_certificate /etc/letsencrypt/live/api.openmicodyssey.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.openmicodyssey.com/privkey.pem;
location / {
proxy_pass http://coolify-backend.internal:8787;
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 https;
}
}
server {
listen 80;
server_name admin.openmicodyssey.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name admin.openmicodyssey.com;
ssl_certificate /etc/letsencrypt/live/admin.openmicodyssey.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/admin.openmicodyssey.com/privkey.pem;
location / {
proxy_pass http://coolify-dashboard.internal:80;
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 https;
}
}
```
If you prefer same-origin routing for dashboard + API through one public domain, proxy `location /admin/` and `location /health` to backend while keeping `/` on dashboard.
Recommended OAuth callback route:
- `https://admin.openmicodyssey.com/oauth/discord/callback`
If you use this callback path, make sure dashboard hosting serves the SPA entrypoint for that route instead of returning `404`.
## 2. Configure Runtime Variables
Backend (`omo-bot-backend`) minimum:
@@ -39,14 +111,21 @@ Backend (`omo-bot-backend`) minimum:
Dashboard (`omo-bot-dashboard`) minimum:
- `VITE_ADMIN_API_BASE_URL` (for split-domain deployment, set to `https://api.yourdomain.com`)
- `VITE_ADMIN_API_BASE_URL` (for split-domain deployment, set to `https://api.openmicodyssey.com`)
- `VITE_DISCORD_CLIENT_ID`
- `VITE_DISCORD_REDIRECT_URI` (must match Discord OAuth2 redirect list)
- `VITE_DISCORD_REDIRECT_URI` (recommended: `https://admin.openmicodyssey.com/oauth/discord/callback`)
OAuth alignment:
- Discord Developer Portal redirect URI must match dashboard redirect domain.
- Config DB key `OAUTH_BRIDGE_REDIRECT_URI` must match the same URI.
- Discord Developer Portal redirect URI must exactly match the dashboard callback URL.
- Config DB key `OAUTH_BRIDGE_REDIRECT_URI` must match the same callback URL.
- Dashboard env `VITE_DISCORD_REDIRECT_URI` must match the same callback URL.
Discord OAuth authorize URL shape:
```text
https://discord.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&response_type=code&redirect_uri=https%3A%2F%2Fadmin.openmicodyssey.com%2Foauth%2Fdiscord%2Fcallback&scope=identify%20guilds&prompt=consent
```
## 3. Get Coolify Deployment Hooks and Tokens
@@ -71,68 +150,33 @@ In Gitea repository settings, add Actions secrets:
- `COOLIFY_DEPLOY_HOOK_URL_DASHBOARD`
- `COOLIFY_DEPLOY_TOKEN_DASHBOARD` (optional)
Current workflow in `.gitea/workflows/ci-cd.yml` uses a single pair:
Current workflow in `.gitea/workflows/ci-cd.yml` triggers backend and dashboard deploys separately using these four secrets.
- `COOLIFY_DEPLOY_HOOK_URL`
- `COOLIFY_DEPLOY_TOKEN`
## 5. Domain and DNS Checklist
If you use separate resources with separate hooks, update workflow deploy step to call both hooks.
1. Create DNS records to Nginx edge host (or directly to Coolify if no edge proxy):
## 5. Example Deploy Step for Two Coolify Resources
- `A` record for root/subdomain targets
- `CNAME` where appropriate
```yaml
deploy-coolify:
name: Deploy to Coolify
runs-on: ubuntu-latest
needs:
- bot-checks
- dashboard-checks
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
steps:
- name: Trigger backend deploy
env:
HOOK_URL: ${{ secrets.COOLIFY_DEPLOY_HOOK_URL_BOT }}
HOOK_TOKEN: ${{ secrets.COOLIFY_DEPLOY_TOKEN_BOT }}
run: |
if [ -z "$HOOK_URL" ]; then
echo "Missing COOLIFY_DEPLOY_HOOK_URL_BOT"
exit 1
fi
if [ -n "$HOOK_TOKEN" ]; then
curl --fail --show-error --silent -X POST -H "Authorization: Bearer $HOOK_TOKEN" "$HOOK_URL"
else
curl --fail --show-error --silent -X POST "$HOOK_URL"
fi
2. Verify certificates issued on Nginx or Coolify, depending on TLS termination point.
3. Verify Nginx upstreams match deployed ports:
- name: Trigger dashboard deploy
env:
HOOK_URL: ${{ secrets.COOLIFY_DEPLOY_HOOK_URL_DASHBOARD }}
HOOK_TOKEN: ${{ secrets.COOLIFY_DEPLOY_TOKEN_DASHBOARD }}
run: |
if [ -z "$HOOK_URL" ]; then
echo "Missing COOLIFY_DEPLOY_HOOK_URL_DASHBOARD"
exit 1
fi
if [ -n "$HOOK_TOKEN" ]; then
curl --fail --show-error --silent -X POST -H "Authorization: Bearer $HOOK_TOKEN" "$HOOK_URL"
else
curl --fail --show-error --silent -X POST "$HOOK_URL"
fi
```
- backend -> `8787`
- dashboard -> `80`
## 6. Domain and DNS Checklist
4. Verify OAuth callback route resolves through dashboard hosting:
1. Create DNS records to Coolify host:
- `A` record for root/subdomain targets
- `CNAME` where appropriate
2. Verify certificates issued for both domains.
3. Verify dashboard can call API at configured `VITE_ADMIN_API_BASE_URL`.
4. Verify API health endpoint over TLS:
- `GET https://api.yourdomain.com/health`
- `https://admin.openmicodyssey.com/oauth/discord/callback`
## 7. Post-Deploy Verification
5. Verify dashboard can call API at configured `VITE_ADMIN_API_BASE_URL`.
6. Verify API health endpoint over TLS:
- `GET https://api.openmicodyssey.com/health`
## 6. Post-Deploy Verification
1. `npm run register:commands` (if bot app/guild IDs changed).
2. Confirm bot online in Discord and slash commands visible.
3. Open dashboard URL and run OAuth login flow.
4. Validate Admin API auth behavior with and without bearer token.
4. Confirm Discord redirects back to `https://admin.openmicodyssey.com/oauth/discord/callback` without `404`.
5. Validate Admin API auth behavior with and without bearer token.
+11
View File
@@ -92,6 +92,7 @@ This project uses the arc42 template. Chapters are in `docs/`.
3. Copy these values for runtime config (`bot_settings`):
- `DISCORD_TOKEN` from Bot tab (Reset Token if needed)
- `DISCORD_CLIENT_ID` from OAuth2 > General
- `OAUTH_BRIDGE_REDIRECT_URI` as exact callback URL, recommended: `https://admin.openmicodyssey.com/oauth/discord/callback`
4. In `Bot` > `Privileged Gateway Intents`, enable only:
- `Server Members Intent` (required by current code)
5. Keep these disabled unless code changes require them:
@@ -171,6 +172,16 @@ npm run dev
Dashboard environment template: `admin-dashboard/.env.example`.
Recommended production OAuth callback URL:
- `https://admin.openmicodyssey.com/oauth/discord/callback`
This same URL must match:
- Discord OAuth2 redirect whitelist
- `VITE_DISCORD_REDIRECT_URI`
- `OAUTH_BRIDGE_REDIRECT_URI`
### Validation Commands
```bash
+3 -2
View File
@@ -1,4 +1,5 @@
VITE_ADMIN_API_BASE_URL=http://localhost:8787
VITE_DISCORD_CLIENT_ID=
# Must match Discord OAuth2 redirect URI whitelist.
VITE_DISCORD_REDIRECT_URI=http://localhost:5173
# Must exactly match Discord OAuth2 redirect URI whitelist and OAUTH_BRIDGE_REDIRECT_URI.
# Recommended production route: https://admin.openmicodyssey.com/oauth/discord/callback
VITE_DISCORD_REDIRECT_URI=http://localhost:5173/oauth/discord/callback
+29 -15
View File
@@ -3,15 +3,13 @@
## Infrastructure Overview
```txt
┌──────────────┐ HTTPS/WSS ┌───────────────────────────────────
│ Discord APIs │◄───────────────────►│ Coolify deployment
└──────────────┘ │ ┌───────────────────────────────┐
│ │ Backend container │
│ │ - Discord gateway runtime
│ │ - Admin API (Express)
│ │ - Dailies pollers │ │
│ └──────────────┬────────────────┘ │
└─────────────────│──────────────────┘
┌──────────────┐ HTTPS/WSS ┌──────────────────────────────┐
│ Discord APIs │◄───────────────────►│ Coolify backend resource
└──────────────┘ │ port 8787
│ - Discord gateway runtime
│ - Admin API (Express)
│ - Dailies pollers
└──────────────┬───────────────┘
┌───────────────────┐
@@ -19,10 +17,23 @@
│ mileage + config │
└───────────────────┘
┌──────────────────────────┐ HTTPS ┌─────────────────────────────┐
│ Admin Dashboard (SPA) │◄───────────►│ Admin API + OAuth bridge
│ React/Vite static deploy │ │ │
└──────────────────────────┘ └─────────────────────────────
Internet
──────────────────────────
│ Nginx edge reverse proxy │
│ - TLS termination │
│ - Host/path routing │
└─────────────┬────────────┘
┌────────┴───────────┐
▼ ▼
┌───────────────┐ ┌──────────────────────────┐
│ Coolify │ │ Coolify dashboard │
│ backend │ │ resource │
│ port 8787 │ │ port 80 │
└───────────────┘ │ React/Vite static deploy │
└──────────────────────────┘
```
## CI/CD Pipeline
@@ -32,14 +43,15 @@ Source file: `.gitea/workflows/ci-cd.yml`
1. Bot job: install dependencies, run lint, build, and test.
2. Dashboard job: install dependencies in `admin-dashboard`, run lint/build.
3. Deploy job: on `main`, trigger Coolify webhook (optionally authenticated with token).
4. In two-resource production setup, deploy webhooks can independently trigger backend and dashboard resources.
## Environment Matrix
| Environment | Runtime | Database | Notes |
| ----------------- | --------------------------------- | -------------------------------------- | ------------------------------------------- |
| ----------------- | ------------------------------------------------ | -------------------------------------- | ---------------------------------------------------------------------------- |
| Local development | Node.js process via `npm run dev` | Local/Postgres dev instance | Fast iteration, manual command registration |
| CI | Ephemeral runner | Test/dev DB or mocked integration path | Quality gates before deployment |
| Production | Coolify-managed container(s) | Managed PostgreSQL | Webhook-triggered deployment from Gitea |
| Production | Nginx edge + Coolify backend/dashboard resources | Managed PostgreSQL | Host-based routing, TLS termination, webhook-triggered deployment from Gitea |
## Deployment Risks and Mitigations
@@ -47,3 +59,5 @@ Source file: `.gitea/workflows/ci-cd.yml`
Mitigation: dashboard re-auth flow and short-lived session design.
- Risk: DB connectivity interruptions.
Mitigation: startup validation + retry behavior on mileage writes.
- Risk: edge proxy misroutes dashboard/API traffic.
Mitigation: verify upstream hostnames/ports and health checks after deploy.