gohorsejobs/docs/DEVOPS.md
Tiago Yamamoto 11e0deef2a fix: resolve build errors for Coolify deployment
- Frontend: Remove duplicate useState import in applications page
- Backoffice: Install devDependencies during build for nest CLI
- Seeder: Fix healthcheck port to match app port (8080)
- Add Coolify CI/CD workflow for automatic deployment on push to dev
- Update DEVOPS.md with Coolify environment documentation
2026-02-16 08:42:29 -06:00

7.1 KiB

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


☁️ 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:

DATABASE_URL=postgres://gohorsejobs:gohorsejobs123@bgws48os8wgwk08o48wg8k80:5432/gohorsejobs?sslmode=disable
BACKEND_PORT=8521
ENV=development
JWT_SECRET=<configured>
JWT_EXPIRATION=7d
PASSWORD_PEPPER=<configured>
COOKIE_SECRET=<configured>
COOKIE_DOMAIN=.gohorsejobs.com
CORS_ORIGINS=http://coolify-dev.gohorsejobs.com,https://coolify-dev.gohorsejobs.com

Deploy via API

# 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/<deployment_uuid>"

# 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


🏗️ Architecture Diagram

Simplified view of the container hierarchy, networking, and storage.

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:

# 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):

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:

# 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)

# 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)

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