Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ricardomb-tech/surqo/llms.txt

Use this file to discover all available pages before exploring further.

The Surqo backend runs on Fly.io instead of Render or Railway for one critical reason: auto_stop_machines = false. Render’s free tier hibernates containers after 15 minutes of inactivity, causing 60-second cold starts that break the persistent MQTT consumer and WebSocket broadcast manager. Fly.io’s min_machines_running = 1 guarantees at least one machine is always live — no delays, no dropped MQTT messages, no stale WebSocket connections.

Prerequisites

Before deploying, install flyctl and authenticate:
# Install flyctl
curl -L https://fly.io/install.sh | sh

# Authenticate
flyctl auth login

Deployment Steps

1

Launch the app on Fly.io

From the backend/ directory, initialise the Fly.io application. The --region dfw flag places the VM in Dallas — the closest Fly.io region to Colombia, minimising latency for MQTT messages coming from HiveMQ Cloud.
cd backend
flyctl launch --name surqo-api --region dfw
When prompted, answer No to overwriting the existing fly.toml — the configuration is already committed in the repository.
2

Set all required secrets

Surqo reads every sensitive credential from environment variables. Push them as Fly secrets (encrypted at rest, injected at runtime):
flyctl secrets set \
  LLM_PROVIDER="groq" \
  GROQ_API_KEY="gsk_..." \
  SUPABASE_URL="https://..." \
  SUPABASE_KEY="..." \
  SUPABASE_JWK_X="..." \
  SUPABASE_JWK_Y="..." \
  SUPABASE_JWK_KID="..." \
  DATABASE_URL="postgresql+asyncpg://..." \
  REDIS_URL="rediss://..." \
  HIVEMQ_HOST="..." \
  HIVEMQ_USERNAME="..." \
  HIVEMQ_PASSWORD="..." \
  RESEND_API_KEY="re_..." \
  FROM_EMAIL="alertas@surqo.online" \
  APP_ENV="production" \
  CORS_ORIGINS='["https://surqo.online"]'
Copy the full variable list from backend/.env.example, which documents every key and where to obtain it (Groq console, Supabase dashboard, Upstash, HiveMQ Cloud, Resend).
3

Deploy the container

The --remote-only flag builds the Docker image on Fly.io’s remote builders — no local Docker daemon required.
flyctl deploy --remote-only
4

Verify the deployment

Confirm the machine is running and the health endpoint responds:
# Check machine status
flyctl status

# Tail live logs
flyctl logs -a surqo-api

# Hit the health endpoint
curl https://surqo-api.fly.dev/health
A healthy response looks like:
{ "status": "ok", "db": "ok", "env": "production" }

fly.toml Configuration

The backend/fly.toml file controls every aspect of the deployment. The most important settings are auto_stop_machines = false and min_machines_running = 1, which together guarantee the MQTT consumer and WebSocket manager are never interrupted.
backend/fly.toml
app            = "surqo-api"
primary_region = "dfw"   # Dallas — closest to Colombia

[build]
  dockerfile = "Dockerfile"

[env]
  APP_ENV     = "production"
  PORT        = "8080"
  HIVEMQ_PORT = "8883"
  FROM_EMAIL  = "alertas@surqo.io"

[http_service]
  internal_port        = 8080
  force_https          = true
  auto_stop_machines   = false   # No hibernation — always responsive
  auto_start_machines  = true
  min_machines_running = 1

  [http_service.concurrency]
    type       = "connections"
    hard_limit = 200
    soft_limit = 150

[[vm]]
  size   = "shared-cpu-1x"
  memory = "512mb"

[checks]
  [checks.health]
    grace_period = "10s"
    interval     = "30s"
    method       = "GET"
    path         = "/health"
    port         = 8080
    timeout      = "5s"
    type         = "http"
Fly.io polls /health every 30 seconds. If the check fails, Fly.io automatically restarts the machine and routes traffic away until it recovers.

Dockerfile

The container image uses python:3.11-slim with uv as the package manager (10–100× faster than pip) and serves the application with Uvicorn on port 8080 to match Fly.io’s expected internal port.
backend/Dockerfile
FROM python:3.11-slim

WORKDIR /app

# Install uv package manager
RUN pip install uv

# Copy dependency files first (layer caching)
COPY pyproject.toml uv.lock ./

# Install production dependencies only
RUN uv sync --frozen --no-dev

# Copy application source
COPY app/ app/

# Expose Fly.io's default internal port
EXPOSE 8080

CMD ["uv", "run", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8080"]
The --no-dev flag in uv sync excludes development tools (ruff, pytest, etc.) from the production image, keeping it lean.

Ongoing Operations

After the initial deploy, use these commands for day-to-day management:
# Trigger a new deploy (CI/CD does this automatically on push to master)
flyctl deploy --remote-only

# Stream live application logs
flyctl logs -a surqo-api

# Check machine health and current status
flyctl status

# Open an SSH session inside the running VM
flyctl ssh console

Production URLs

ResourceURL
API basehttps://surqo-api.fly.dev
Health checkhttps://surqo-api.fly.dev/health
The Swagger/ReDoc UI is disabled in production for security. For interactive API exploration, run the backend locally with uv run fastapi dev app/main.py and open http://localhost:8000/docs.

Build docs developers (and LLMs) love