Saltar a contenido

Despliegue en Coolify (Contabo)

Runbook corto para desplegar FarmAPI en el proyecto farmaestudio de Coolify usando el repo privado 686f6c61/farmapi.

Artefacto de despliegue

  • fichero Compose: docker-compose.coolify.yml
  • plantilla de variables: .env.coolify.example

Qué levanta en Contabo

  • app: FastAPI pública + admin + docs in-app
  • coordinate-worker: reparación automática de coordenadas
  • ops-scheduler: sync diario + retry de territorios degradados + retry de webhooks
  • postgres: base de datos propia de FarmAPI
  • redis: rate limiting y soporte operativo

Ruta pública esperada

  • dominio canónico: https://estudioapi.com/farmapi
  • alias www: https://www.estudioapi.com/farmapi
  • admin: https://estudioapi.com/farmapi/admin
  • docs: https://estudioapi.com/farmapi/docs/

Alta en Coolify

  1. Crear una nueva aplicación en el proyecto farmaestudio, entorno production.
  2. Elegir Private GitHub App.
  3. Repositorio: 686f6c61/farmapi.
  4. Branch: main.
  5. Build pack: Docker Compose.
  6. Compose path: docker-compose.coolify.yml.
  7. Servicio público: app.
  8. Dominio/FQDN:
  9. https://estudioapi.com/farmapi
  10. https://www.estudioapi.com/farmapi

Variables mínimas obligatorias en Coolify

Base

  • FARMAAPI_ENV=prod
  • APP_BASE_PATH=/farmapi
  • PUBLIC_EXAMPLE_BASE_URL=https://estudioapi.com/farmapi
  • TRUSTED_HOSTS_CSV=estudioapi.com,www.estudioapi.com
  • ADMIN_ALLOWED_ORIGINS_CSV=https://estudioapi.com,https://www.estudioapi.com
  • GITHUB_REDIRECT_URI=https://estudioapi.com/farmapi/auth/github/callback
  • TZ=Europe/Madrid
  • DOCKER_STARTUP_PREFLIGHT_MODE=prod

Seguridad

  • ADMIN_SESSION_SECRET
  • ADMIN_PII_ENCRYPTION_KEY
  • ADMIN_PII_HASH_PEPPER
  • API_KEY_HASH_PEPPER
  • INTERNAL_API_TOKEN

GitHub SSO

Geocoding

  • MAPS_GEOCODING_API_KEY
  • MAPS_GEOCODING_ENABLED=true
  • OSM_GEOCODING_ENABLED=false
  • ARCGIS_GEOCODING_ENABLED=true

Raw oficial

  • RAW_STORAGE_BACKEND=local
  • RAW_LOCAL_DIR=/app/.local/raw
  • RAW_BUCKET=

En Contabo/Coolify el raw oficial se guarda en el volumen persistente farmaapi_local. No uses RAW_STORAGE_BACKEND=gcs salvo que hayas montado credenciales ADC de GCP y un bucket real.

Resend

  • RESEND_API_KEY
  • RESEND_FROM_EMAIL
  • RESEND_API_BASE_URL=https://api.resend.com
  • [email protected]

Publicación al SaaS

  • SAAS_BASE_URL=https://estudioapi.com/farmapi
  • SAAS_OAUTH_TOKEN_URL=https://estudioapi.com/farmapi/oauth/token
  • SAAS_OAUTH_CLIENT_ID
  • SAAS_OAUTH_CLIENT_SECRET
  • SAAS_MOCK_MODE=false

Variables operativas recomendadas

  • SYNC_DAILY_LOCAL_TIME=03:00
  • SYNC_RUN_MISSED_DAILY_ON_START=true
  • WEBHOOK_RETRY_INTERVAL_SECONDS=60
  • WEBHOOK_RETRY_LIMIT=200
  • DEGRADED_RETRY_INTERVAL_SECONDS=7200
  • COORD_REPAIR_INTERVAL_SECONDS=60
  • COORD_REPAIR_LIMIT=200
  • COORD_REPAIR_INCLUDE_MISSING=true
  • SYNC_MAX_PARALLEL_TERRITORIES=4
  • SYNC_MAX_PARALLEL_REGCESS_TERRITORIES=1

Nota importante

Con el guard de arranque actual, el contenedor no arrancará en prod si faltan:

  • Resend real
  • OAuth GitHub real
  • credenciales reales del SaaS (SAAS_MOCK_MODE=false)

Esto es intencionado: evita sacar a producción una instalación “a medias”.

DNS en Cloudflare

Usar el mismo patrón que farmaestudio.com:

  • A estudioapi.com -> 5.189.187.104
  • A www.estudioapi.com -> 5.189.187.104
  • proxied = true
  • ttl = 60

Cloudflare queda en modo SSL Full. El proxy de Cloudflare evita que www.estudioapi.com exponga certificados internos si Traefik tarda en renovar.

Verificacion tras cada despliegue

Sin API key real, una ruta publica protegida debe responder 401, no 404:

curl -sS -o /tmp/farmapi-nearby.out -w '%{http_code}\n' \
  'https://estudioapi.com/farmapi/v1/farmacias/nearby?territory_code=ES-MD&lat=40.4168&lng=-3.7038&radius_m=750'

Con API key, el verificador live debe dejar en verde api_nearby:

uv run python scripts/verify_live_surface.py \
  --base-url https://estudioapi.com/farmapi \
  --api-key "$FARMAAPI_API_KEY" \
  --trial-territory ES-MD \
  --require-ok