# DevOps - GoHorseJobs (Development Environment) Infraestrutura, CI/CD e deploy do projeto GoHorseJobs no servidor `apolo`. > **Last Updated:** 2026-02-16 > **Servers:** Apolo VPS (Podman), Redbull VPS (Coolify) > **Tech Stack:** Podman, Systemd (Quadlet), Traefik, PostgreSQL, Coolify --- ## ☁️ Cloudflare DNS Zone ### Zone Info | Property | Value | |----------|-------| | **Zone ID** | `5e7e9286849525abf7f30b451b7964ac` | | **Domain** | gohorsejobs.com | | **Account** | gohorsejobs | | **Email** | yamamoto@rede5.com.br | | **Plan** | Free Website | | **Name Servers** | chuck.ns.cloudflare.com, fatima.ns.cloudflare.com | ### API Access ```bash # Token location: ~/.ssh/cloudflare-token export CF_AUTH_EMAIL="yamamoto@rede5.com.br" export CF_AUTH_KEY="5dcfd89a9d4ec330dede0d4074a518f26818e" # List zones curl -s -H "X-Auth-Email: $CF_AUTH_EMAIL" -H "X-Auth-Key: $CF_AUTH_KEY" \ "https://api.cloudflare.com/client/v4/zones" # List DNS records curl -s -H "X-Auth-Email: $CF_AUTH_EMAIL" -H "X-Auth-Key: $CF_AUTH_KEY" \ "https://api.cloudflare.com/client/v4/zones/5e7e9286849525abf7f30b451b7964ac/dns_records" # Purge cache curl -s -X DELETE -H "X-Auth-Email: $CF_AUTH_EMAIL" -H "X-Auth-Key: $CF_AUTH_KEY" \ -H "Content-Type: application/json" \ "https://api.cloudflare.com/client/v4/zones/5e7e9286849525abf7f30b451b7964ac/purge_cache" \ -d '{"purge_everything":true}' ``` ### Active DNS Records (gohorsejobs.com) | Subdomain | Type | IP/Target | Proxied | |-----------|------|------------|---------| | dev.gohorsejobs.com | A | 38.19.201.52 | No | | api.gohorsejobs.com | A | 86.48.29.139 | Yes | | api-dev.gohorsejobs.com | A | 86.48.29.139 | Yes | | api-local.gohorsejobs.com | A | 38.19.201.52 | No | | b-local.gohorsejobs.com | A | 38.19.201.52 | No | | s-local.gohorsejobs.com | A | 38.19.201.52 | No | | coolify-dev.gohorsejobs.com | A | 185.194.141.70 | No | | panel.gohorsejobs.com | A | Multiple (Load Balanced) | Yes | | pipe.gohorsejobs.com | A | Multiple (Load Balanced) | Yes | | alert.gohorsejobs.com | A | Multiple (Load Balanced) | Yes | | task.gohorsejobs.com | A | Multiple (Load Balanced) | Yes | | stats.gohorsejobs.com | A | Multiple (Load Balanced) | Yes | | storage.gohorsejobs.com | A | Multiple (Load Balanced) | Yes | | base.gohorsejobs.com | A | Multiple | No | | reg.gohorsejobs.com | A | Multiple (Load Balanced) | Yes | | gohorsejobs.com | CNAME | gohorsejobs.pages.dev | Yes | | *.gohorsejobs.com | CNAME | 8a3f435b-f374-4268-90f7-5610f577c706.cfargotunnel.com | Yes | | mail.gohorsejobs.com | CNAME | everest.mxrouting.net | No | > Total: 190 DNS records (paginados) --- ## ☁️ Coolify DEV Environment (Redbull) Ambiente de desenvolvimento no Coolify para deploy automatizado via Git. ### Server Info | Property | Value | |----------|-------| | **Host** | redbull (185.194.141.70) | | **Coolify URL** | http://185.194.141.70:8000 | | **API Token** | `~/.ssh/coolify-redbull-token` | | **SSH Key** | `~/.ssh/civo` | | **Project UUID** | `gkgksco0ow4kgwo8ow4cgs8c` | | **Environment** | `dev` | ### Resources Created | Resource | UUID | Port | Domain | |----------|------|------|--------| | Backend: gohorsejobs-backend-dev | `iw4sow8s0kkg4cccsk08gsoo` | 8521 | coolify-dev.gohorsejobs.com | | Frontend: gohorsejobs-frontend-dev | `ao8g40scws0w4cgo8coc8o40` | 3000 | dev.gohorsejobs.com | | Backoffice: gohorsejobs-backoffice-dev | `hg48wkw4wggwsswcwc8sooo4` | 3001 | backoffice-dev.gohorsejobs.com | | Seeder: gohorsejobs-seeder-dev | `q4w48gos8cgssso00o8w8gck` | 8080 | seeder-dev.gohorsejobs.com | | Database: gohorsejobs-dev | `bgws48os8wgwk08o48wg8k80` | 5432 | Internal only | ### Architecture ``` GitHub (rede5/gohorsejobs.git) │ ▼ Coolify (Build & Deploy) │ ├── Backend (Go) → coolify-dev.gohorsejobs.com:8521 │ └── PostgreSQL → Internal network only ``` ### Environment Variables Configured via Coolify UI or API: ```bash DATABASE_URL=postgres://gohorsejobs:gohorsejobs123@bgws48os8wgwk08o48wg8k80:5432/gohorsejobs?sslmode=disable BACKEND_PORT=8521 ENV=development JWT_SECRET= JWT_EXPIRATION=7d PASSWORD_PEPPER= COOKIE_SECRET= COOKIE_DOMAIN=.gohorsejobs.com CORS_ORIGINS=http://coolify-dev.gohorsejobs.com,https://coolify-dev.gohorsejobs.com ``` ### Deploy via API ```bash # Deploy application curl -H "Authorization: Bearer $(cat ~/.ssh/coolify-redbull-token)" \ "http://185.194.141.70:8000/api/v1/deploy?uuid=iw4sow8s0kkg4cccsk08gsoo" # Check deployment status curl -H "Authorization: Bearer $(cat ~/.ssh/coolify-redbull-token)" \ "http://185.194.141.70:8000/api/v1/deployments/" # List applications curl -H "Authorization: Bearer $(cat ~/.ssh/coolify-redbull-token)" \ "http://185.194.141.70:8000/api/v1/applications" # List databases curl -H "Authorization: Bearer $(cat ~/.ssh/coolify-redbull-token)" \ "http://185.194.141.70:8000/api/v1/databases" ``` ### Coolify Reference - **Docs:** https://coolify.io/docs/get-started/introduction - **API Reference:** https://coolify.io/docs/api-reference/authorization - **GitHub Integration:** Uses SSH deploy key for private repo access --- ## 🏗️ Architecture Diagram Simplified view of the container hierarchy, networking, and storage. ```mermaid graph TD subgraph Host ["Apolo VPS (Host)"] subgraph FS ["File System (/mnt/data)"] EnvBE["/gohorsejobs/backend/.env"] EnvBO["/gohorsejobs/backoffice/.env"] EnvSE["/gohorsejobs/seeder-api/.env"] DBData[("postgres-general")] end subgraph Net ["Network: web_proxy"] Traefik("Traefik") subgraph App ["Application Containers"] BE["Backend API (:8521)"] BO["Backoffice (:3001)"] SE["Seeder API (:8080)"] FE["Frontend (:3000)"] end PG[("postgres-main (:5432)")] end end %% Ingress Internet((Internet)) --> Traefik %% Routing Traefik -- "dev.gohorsejobs.com" --> FE Traefik -- "api-tmp.gohorsejobs.com" --> BE Traefik -- "b-tmp.gohorsejobs.com" --> BO Traefik -- "seeder.gohorsejobs.com" --> SE %% Config Mounts EnvBE -.-> BE EnvBO -.-> BO EnvSE -.-> SE %% Data Persistence PG -.-> DBData %% Database Connections BE --> PG BO --> PG SE --> PG style PG fill:#336791,stroke:#fff,color:#fff style Traefik fill:#f5a623,stroke:#fff,color:#fff ``` --- ## 💾 Storage & Persistence (`/mnt/data`) All persistent data and configuration files are stored in `/mnt/data` on the host. | Host Path | Container Path | Purpose | Type | |-----------|----------------|---------|------| | `/mnt/data/gohorsejobs/backend/.env` | (Injected Env) | **Backend Config:** Secrets, DB URL, Port settings. | File | | `/mnt/data/gohorsejobs/backoffice/.env` | (Injected Env) | **Backoffice Config:** Secrets, DB URL. | File | | `/mnt/data/gohorsejobs/seeder-api/.env` | (Injected Env) | **Seeder Config:** Secrets, DB URL. | File | | `/mnt/data/postgres-general` | `/var/lib/postgresql/data` | **Database Storage:** Main storage for `postgres-main` container. Contains `gohorsejobs_dev` DB. | Directory | > **Backup Note:** To backup the environment, ensure `/mnt/data/gohorsejobs` and `/mnt/data/postgres-general` are included in snapshots. --- ## 🌍 Service Maps & Networking ### 🚦 Traefik Routing Services are exposed via Traefik labels defined in the Quadlet `.container` files. | Domain | Service | Internal Port | Host Port (Debug) | |--------|---------|---------------|-------------------| | `dev.gohorsejobs.com` | `gohorsejobs-frontend-dev` | `3000` | `8523` | | `api-tmp.gohorsejobs.com` | `gohorsejobs-backend-dev` | `8521` | `8521` | | `b-tmp.gohorsejobs.com` | `gohorsejobs-backoffice-dev` | `3001` | - | | `seeder.gohorsejobs.com` | `gohorsejobs-seeder-dev` | `8080` | `8522` | ### 🛑 Security - **Backend/Seeder/Frontend** expose ports to the Host (`85xx`) for debugging/direct access if needed. - **Backoffice** is *only* accessible via Traefik (internal network). - **PostgreSQL** is *only* accessible internally via `web_proxy` network (no host port binding). --- ## 🛠️ Operational Guide ### 1. View & Manage Configs Configurations are **not** inside containers. Edit them on the host: ```bash # Edit Backend Config vim /mnt/data/gohorsejobs/backend/.env # Apply changes systemctl restart gohorsejobs-backend-dev ``` ### 2. Full Environment Restart To restart all GoHorseJobs related services (excluding Database): ```bash systemctl restart gohorsejobs-backend-dev gohorsejobs-backoffice-dev gohorsejobs-seeder-dev gohorsejobs-frontend-dev ``` ### 3. Database Access Access the local database directly via the `postgres-main` container: ```bash # Internal Connection docker exec -it postgres-main psql -U yuki -d gohorsejobs_dev ``` --- ## 🚀 Deployment Pipeline (Manual) Current workflow uses **Local Build** -> **Forgejo Registry** -> **Server Pull**. ### 1. Build & Push (Local Machine) ```bash # Login podman login forgejo-gru.rede5.com.br # Build cd backend podman build -t forgejo-gru.rede5.com.br/rede5/gohorsejobs-backend:latest . # Push podman push forgejo-gru.rede5.com.br/rede5/gohorsejobs-backend:latest ``` ### 2. Deploy (On Apolo Server) ```bash ssh root@apolo # Pull new image podman pull forgejo-gru.rede5.com.br/rede5/gohorsejobs-backend:latest # Restart service (Systemd handles container recreation) systemctl restart gohorsejobs-backend-dev ```