10 KiB
DevOps - GoHorseJobs (Development Environment)
Infraestrutura, CI/CD e deploy do projeto GoHorseJobs no servidor apolo.
Last Updated: 2026-02-17 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 |
| yamamoto@rede5.com.br | |
| Plan | Free Website |
| Name Servers | chuck.ns.cloudflare.com, fatima.ns.cloudflare.com |
API Access
# 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 |
| local.gohorsejobs.com | A | 185.194.141.70 | No |
| api-local.gohorsejobs.com | A | 185.194.141.70 | No |
| b-local.gohorsejobs.com | A | 185.194.141.70 | No |
| s-local.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 | local.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 |
API Reference
Base URL: http://185.194.141.70:8000/api/v1
Server UUID: m844o4gkwkwcc0k48swgs8c8
# Listar aplicações
curl -s -H "Authorization: Bearer $(cat ~/.ssh/coolify-redbull-token)" \
"http://185.194.141.70:8000/api/v1/applications"
# Atualizar domínios (requer http:// ou https://)
curl -s -X PATCH -H "Authorization: Bearer $(cat ~/.ssh/coolify-redbull-token)" \
-H "Content-Type: application/json" \
"http://185.194.141.70:8000/api/v1/applications/<UUID>" \
-d '{"domains":"http://local.gohorsejobs.com","instant_deploy":true}'
# Deploy aplicação
curl -s -H "Authorization: Bearer $(cat ~/.ssh/coolify-redbull-token)" \
"http://185.194.141.70:8000/api/v1/deploy?uuid=<UUID>"
# Ver domínios do servidor
curl -s -H "Authorization: Bearer $(cat ~/.ssh/coolify-redbull-token)" \
"http://185.194.141.70:8000/api/v1/servers/m844o4gkwkwcc0k48swgs8c8/domains"
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
- 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.
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/gohorsejobsand/mnt/data/postgres-generalare 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_proxynetwork (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