# Deploying raycer to Coolify raycer runs in production at **https://raycer.altweb.me** as a Docker Compose application managed by Coolify v4 on the `cool2026` instance. ## Where things live - **Coolify dashboard:** https://cool2026.altweb.me - **Server:** `personal` (Linode 91853095, Amsterdam, 2 GB) - server UUID: `locg048kwko4sws8wcggc0o4` - public IP: `172.235.183.140` - **Project:** `tools` (UUID `u8wooo0wwk4k8wcw48ww8oo8`) - **Source:** Forgejo, `https://forgejo-rko8sk40400wscowk4scko0w.altweb.me/spencer/raycer.git`, branch `main` (mirrored to GitLab `spencerflagg/raycer`) - **Compose file:** `/docker-compose.coolify.yaml` (the local-dev `docker-compose.yml` is for `raycer.test` only and is not used in prod) ## Containers | Service | Image source | Internal port | Public | Memory limit | |----------|-----------------------------|---------------|-------------|--------------| | backend | built from `./backend` | 3000 | (internal) | 256 MiB | | frontend | built from `./frontend` | 80 | raycer.altweb.me | 64 MiB | The frontend's nginx reverse-proxies `/api/*` to `http://backend:3000`. ## Required env (set in Coolify dashboard) | Variable | Value | Notes | |-----------------------------|------------------------------------|-------| | `SERVICE_FQDN_FRONTEND_80` | `https://raycer.altweb.me` | Coolify magic var; injects Traefik labels for the frontend service. | The backend's `NODE_ENV`, `PORT`, and `DB_PATH` are set inside the compose file. ## Persistent storage A named Docker volume `raycer-data` is mounted into the backend at `/data` and holds `raycer.sqlite`. Coolify creates and manages this volume; it survives redeploys. To inspect or back up: ```bash ssh root@172.235.183.140 docker volume inspect # find via: docker volume ls | grep raycer docker run --rm -v :/data -v $(pwd):/backup alpine \ tar czf /backup/raycer-sqlite-$(date +%F).tgz -C /data . ``` ## Healthchecks Both containers have a `HEALTHCHECK` (backend hits `/api/health`, frontend hits `/`). Coolify's "deployment healthy" gate uses these. ## DNS A record `raycer.altweb.me -> 172.235.183.140` (Linode domain ID `1544692`, TTL 300). To recreate: ```bash linode-cli domains records-create 1544692 \ --type A --name raycer --target 172.235.183.140 --ttl_sec 300 ``` ## How the app was created The Coolify v4 dashboard does not have a great "create from existing config" path, so the original create call hit the API directly: ```bash TOKEN=$(jq -r '.instances[] | select(.name=="cool2026") | .token' \ ~/.config/coolify/config.json) curl -X POST https://cool2026.altweb.me/api/v1/applications/public \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "project_uuid": "u8wooo0wwk4k8wcw48ww8oo8", "server_uuid": "locg048kwko4sws8wcggc0o4", "environment_name": "production", "git_repository": "https://forgejo-rko8sk40400wscowk4scko0w.altweb.me/spencer/raycer.git", "git_branch": "main", "build_pack": "dockercompose", "docker_compose_location": "/docker-compose.coolify.yaml", "name": "raycer", "instant_deploy": false }' ``` After creation, the FQDN env var was set: ```bash curl -X POST https://cool2026.altweb.me/api/v1/applications//envs \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"key":"SERVICE_FQDN_FRONTEND_80","value":"https://raycer.altweb.me","is_preview":false}' ``` Then deployed: ```bash curl -X POST "https://cool2026.altweb.me/api/v1/deploy?uuid=&force=false" \ -H "Authorization: Bearer $TOKEN" ``` ## Re-deploy Pushing to `main` on Forgejo triggers an automatic redeploy via the Coolify webhook (configured at app create time). To force a manual redeploy: ```bash coolify deploy --context cool2026 # or curl -X POST "https://cool2026.altweb.me/api/v1/deploy?uuid=" \ -H "Authorization: Bearer $TOKEN" ``` ## Verification ```bash curl https://raycer.altweb.me/api/health # {"ok":true,...} curl https://raycer.altweb.me/api/goals # both seeded goals coolify app list --context cool2026 --format json | jq '.[] | select(.name=="raycer")' ``` ## Resource notes The `personal` server is 2 GB and tightly accounted for; `mem_limit` values in [docker-compose.coolify.yaml](../docker-compose.coolify.yaml) must be respected. Backend's `better-sqlite3` requires a brief native compile during the image build (~10 s, ~100 MB peak); first deploy may take a minute longer than subsequent ones.