Skip to content
Deployment

Deployment

Miles Ahead runs on a single OCI ARM instance with automated CI/CD via GitHub Actions.

Infrastructure

ComponentTechnologyDetails
ServerOCI ARM (free tier)Ampere A1, Ubuntu
Reverse ProxyCaddyShared via Docker Compose (/opt/fynans/caddy-sites/)
Process Managersystemdmilesahead.service
CI/CDGitHub Actionsci.yml (test) + deploy.yml (build + deploy)
ObservabilityGrafana CloudMetrics via Alloy (Prometheus + Loki)
DatabaseSQLiteWAL mode, stored at /opt/milesahead/data/milesahead.db

CI/CD Pipeline

CI (ci.yml)

Runs on every push and pull request to main:

  1. go vet ./... – static analysis
  2. go test ./... -v -race – unit tests with race detection
  3. go build ./cmd/milesahead – build verification
  4. Screenshot tests – builds the binary, starts the server, captures desktop/tablet/mobile screenshots with Playwright

Deploy (deploy.yml)

Runs on push to main and manual trigger:

  1. Build – cross-compile for linux/arm64, upload binary + seed-cards + cards.json as artifacts
  2. Setup (manual trigger only, full_setup: true) – creates app user, deploys config, systemd service, Caddy config, installs and configures Grafana Alloy
  3. Deploy – SSH into the server, copy binary + templates + static files, atomic swap, restart service, seed reference pages, verify health

The deploy performs an atomic binary swap:

scp milesahead -> /opt/milesahead/milesahead.new
mv milesahead.new -> milesahead
systemctl restart milesahead

Manual Setup

For first-time deployment, trigger the workflow with full_setup: true. This:

  1. Creates the milesahead system user
  2. Creates /opt/milesahead/data, /opt/milesahead/templates, /opt/milesahead/static
  3. Deploys config.yaml with secrets from GitHub Actions
  4. Installs and enables the systemd service
  5. Deploys the Caddy site config to the shared caddy-sites/ directory
  6. Installs Grafana Alloy and deploys its config

Deploy Files

FilePurpose
deploy/milesahead.servicesystemd unit file
deploy/milesahead.caddyCaddy site configuration (reverse proxy)
deploy/alloy-config.alloyGrafana Alloy config for metrics and logs
deploy/alloy.servicesystemd unit for Alloy with Grafana credentials
deploy/backup.shDatabase backup script

Observability

Metrics are exposed in Prometheus format by the application (internal/metrics) and scraped by Grafana Alloy running on the same host. Alloy forwards metrics and logs to Grafana Cloud.

Tracked metrics include:

  • Critic scores (histogram)
  • Image search success/error rates by source
  • Image scoring success/error rates (text and vision phases)
  • Image candidate counts
  • Pipeline execution times

Secrets

The following secrets are configured in GitHub Actions:

SecretPurpose
OCI_SSH_KEYSSH private key for deployment
OCI_HOSTServer hostname/IP
OCI_USERSSH user (typically ubuntu)
NVIDIA_API_KEYNVIDIA API key for AI models
ADMIN_PASSWORD_HASHbcrypt hash of admin password
UNSPLASH_KEYUnsplash API key
PEXELS_KEYPexels API key
PIXABAY_KEYPixabay API key
GRAFANA_API_KEYGrafana Cloud API key
GRAFANA_PROM_URLGrafana Cloud Prometheus endpoint
GRAFANA_PROM_USERGrafana Cloud Prometheus user
GRAFANA_LOKI_URLGrafana Cloud Loki endpoint
GRAFANA_LOKI_USERGrafana Cloud Loki user