Repository Configuration (preview-config.yml)
Required. Place this file in your repository root. The orchestrator reads it after cloning; if the file is missing or validation fails, the deployment fails with a clear error. Required fields are validated; optional fields override defaults and auto-detection (e.g. framework is taken from this file when present, otherwise detected from the repo).
Required Fields
Optional Fields
Repo-owned preview Compose (docker-compose.preview.yml)
You can provide your own Docker Compose file strictly for preview by placing docker-compose.preview.yml or docker-compose.preview.yaml in your repository root (exact names only; no fuzzy matching). When present, the orchestrator uses it instead of generating one from framework templates (same idea as using your own Dockerfile).
- File names:
docker-compose.preview.ymlordocker-compose.preview.yaml(in repo root). Only these two exact filenames are accepted. If you use.yaml, the orchestrator renames it to.ymlso one standard path is used everywhere. - When used: If either file exists after clone/checkout, the orchestrator parses it, injects host port mappings (see Ports), and writes
docker-compose.preview.generated.ymlin the deployment directory. That generated file is used fordocker compose up/down. Otherwise the orchestrator generatesdocker-compose.preview.ymlfrom templates. - Ports: Do not specify host ports for the
appordbservices in your compose file. The orchestrator injects them at runtime so each preview gets unique ports and nginx can route correctly. Use service namesappanddb. Container ports are inferred from framework (NestJS 3000, Go 8080, Laravel 8000, Rust 8080, Python 8000) and database type (Postgres 5432, MySQL 3306, MongoDB 27017). If you omitportsforapp/db, we add them; if you had host ports, we override them. - Project name: The orchestrator always runs with
-p <deploymentId>(e.g.myorg-myapp-12). Do not rely on a fixed project name in your file. - Rebuild/cleanup: Update and cleanup use the same generated file:
docker-compose.preview.generated.ymlwhen you provide repo compose, otherwisedocker-compose.preview.yml(orchestrator-generated).
CLI Configuration (~/.preview-deployer/config.yml)
Generated by preview init. Sensitive values are stored in OS keychain.
Environment Variables
Orchestrator Service
Set in Ansible or systemd service file. When running locally (e.g. for development), the orchestrator loads a.env file from its working directory if present, so you can keep secrets out of the shell.
API reference (OpenAPI)
The orchestrator exposes OpenAPI 3.0 documentation so you can generate API references (e.g. for a separate doc site) or explore the API interactively.- OpenAPI JSON:
GET /openapi.json— Returns the OpenAPI 3.0 spec. Your doc site or API tooling can fetch this URL (from the orchestrator host, e.g.http://SERVER_IP:3000/openapi.json) to generate the API reference. - Swagger UI:
GET /api-docs— Serves Swagger UI that loads the same spec, for interactive exploration (similar to NestJS’s default docs page).
servers[].url is set from ORCHESTRATOR_PUBLIC_URL if present, otherwise from PREVIEW_BASE_URL. If neither is set, the spec omits servers and clients can use the request host as the base URL.
Terraform Variables
Set interraform/terraform.tfvars:
Available Regions
nyc1,nyc3: New Yorksfo3: San Franciscoams3: Amsterdamsgp1: Singaporelon1: Londonfra1: Frankfurttor1: Torontoblr1: Bangalore
Available Droplet Sizes
s-1vcpu-2gb: $12/months-2vcpu-4gb: $24/month (default)s-4vcpu-8gb: $48/months-8vcpu-16gb: $96/month
Ansible Variables
Set via-e flag or in playbook:
Optional SSL (Let’s Encrypt)
When you have a domain pointing at the server, set these so the nginx role obtains a certificate and serves HTTPS:preview_base_url (and orchestrator env) to https://preview.example.com so PR comments get HTTPS preview links. Certbot runs via the nginx role (webroot); HTTP is redirected to HTTPS and ACME challenges are served on port 80 for renewal.
Docker Compose Templates
Templates are located underorchestrator/templates/docker-compose/ and orchestrator/templates/dockerfile/:
docker-compose/docker-compose.nestjs.yml.hbs: NestJS applicationdocker-compose/docker-compose.go.yml.hbs: Go applicationdocker-compose/docker-compose.laravel.yml.hbs: Laravel applicationdocker-compose/docker-compose.rust.yml.hbs: Rust applicationdocker-compose/docker-compose.python.yml.hbs: Python applicationdockerfile/Dockerfile.nestjs.hbs,Dockerfile.go.hbs,Dockerfile.laravel.hbs,Dockerfile.rust.hbs,Dockerfile.python.hbs: Default Dockerfiles per framework
Template Variables
{{prNumber}}: PR number{{appPort}}: Allocated app port (exposed on host){{dbPort}}: Allocated database port (exposed on host)
Container Resources
Default limits (configurable in templates):Nginx Configuration
The nginx role installs nginx and a default server block (port 80, or 80+443 when SSL is enabled). Optional SSL is handled inside the same role: whenpreview_domain and ssl_email are set, it installs certbot, obtains a certificate (webroot), and re-deploys nginx with listen 443 and HTTP→HTTPS redirect.
Preview configs are generated in /etc/nginx/preview-configs/. That directory is owned by the deployment user (e.g. preview-deployer) so the orchestrator can create and remove config files without root. After writing a config, the orchestrator runs nginx -t and nginx -s reload via sudo; Ansible deploys a sudoers fragment at /etc/sudoers.d/preview-deployer-nginx so the deployment user can run only those two nginx commands without a password. The orchestrator systemd unit has NoNewPrivileges=false so that sudo can be used for this limited reload, and ReadWritePaths includes /var/log/nginx and /run so the nginx child process can write its error log and pid file when testing/reloading.
Health Check Configuration
Your application must expose a health check endpoint:NestJS Example
Go Example
Framework detection and Dockerfiles
The orchestrator supports five frameworks: NestJS, Go, Laravel, Rust, and Python. It detects framework from the cloned repo (when not set inpreview-config.yml) and uses the matching docker-compose template from orchestrator/templates/docker-compose/. If the repo has no Dockerfile, the orchestrator injects a default one for that framework from orchestrator/templates/dockerfile/. Repos can override by providing their own Dockerfile at the repo root.
Detection order: NestJS (nest-cli.json or @nestjs/core in package.json) → Go (go.mod) → Laravel (laravel/framework in composer.json). Rust and Python are not auto-detected; set framework: rust or framework: python in preview-config.yml. If none match, NestJS is assumed.
Custom Dockerfiles
If your repository has a custom Dockerfile, ensure it:- Exposes the correct port (3000 NestJS, 8080 Go, 8000 Laravel)
- Includes a health check endpoint (or
/healthfor orchestrator polling) - Runs as non-root user (recommended)
- Handles SIGTERM gracefully
Example Dockerfile (NestJS)
Database Configuration
PostgreSQL (Default)
MySQL
MongoDB
GitHub Webhook Configuration
Webhooks are automatically created by the CLI. Manual configuration:- Go to repository Settings > Webhooks
- Add webhook:
- Payload URL:
http://YOUR_SERVER_IP/webhook/github - Content type:
application/json - Secret: From
~/.preview-deployer/config.yml - Events: Select “Pull requests”
- Active: Checked
- Payload URL:
Logging Configuration
Orchestrator Logs
The orchestrator uses pino and writes to stdout/stderr. In production, the systemd unit redirects stdout to.../logs/orchestrator.log and stderr to .../logs/orchestrator-error.log.
Location: /opt/preview-deployer/logs/
orchestrator.log: Application logs (stdout)orchestrator-error.log: Error logs (stderr)
journalctl -u preview-orchestrator -f for the service unit output.
Docker Logs
View container logs:Nginx Logs
Location:/var/log/nginx/
access.log: Access logserror.log: Error logs