DDEV preview environments on any Linux server.
Trafic turns a VPS into a preview server for your web projects. It handles authentication, scale-to-zero, auto-start, and deployments from CI β all powered by DDEV and Traefik.
- DDEV-native β No custom Dockerfiles needed. Works with WordPress, Laravel, Drupal, and any DDEV-compatible project.
- Scale-to-zero β Idle projects are stopped automatically to save RAM. They restart on the next request.
- Authentication β Forward auth via Traefik with IP whitelist, tokens, basic auth, and per-hostname rules.
- Preview environments β Create and destroy environments from CI, like Vercel but for PHP.
- Backups on removal β
destroy --backupdumps the database and upload directories first. - Scheduled removal β
destroy --delay 48hkeeps a preview for a while; a new deploy cancels it. - Running limit β
max_running_projectscaps how many projects run at once. - Simple CLI β
setup(server),deploy(CI),destroy(cleanup). - TOML config β Simple, readable configuration.
- Zero vendor lock-in β Runs on any Linux VPS with SSH access.
flowchart TD
request[HTTPS request] --> traefik[Traefik / DDEV router]
traefik --> forwardAuth[forwardAuth β trafic agent]
forwardAuth --> |200 OK| ddev-web[DDEV project]
forwardAuth --> |401| basic-auth[Basic auth prompt]
traefik --> |502 error| errors[errors middleware β trafic agent]
errors --> |known project| waiting[Waiting page + auto-start]
errors --> |unknown project| error-page[Error page]
errors --> |project being removed| removing[Error page 503]
# Setup a server over SSH (run from your machine or from CI)
npx @studiometa/trafic-cli setup \
--host=server.example.com \
--tld=previews.example.com \
--email=admin@example.com
# β¦or run it on the server itself, as root
npx @studiometa/trafic-agent setup --tld=previews.example.com --email=admin@example.com
# Deploy from CI
npx @studiometa/trafic-cli deploy \
--host=server.example.com \
--name=my-app \
--branch=main \
--sync="dist/" \
--script="composer install --no-dev"
# Your app is live at https://my-app.previews.example.com| Package | Description | npm |
|---|---|---|
@studiometa/trafic-cli |
CLI for deploying projects from CI | |
@studiometa/trafic-agent |
Server agent (auth, scale-to-zero) |
Server:
- Ubuntu 24.04 LTS
- Root access, or a user with passwordless sudo (for initial setup)
- Wildcard DNS (
*.previews.example.comβ server IP)
CI:
- Node.js 24+
- SSH access to the server
GitLab CI
deploy_preview:
stage: deploy
image: node:24
before_script:
- chmod 600 "$SSH_PRIVATE_KEY"
script:
- npx @studiometa/trafic-cli deploy
--host $SSH_HOST
--name $CI_PROJECT_PATH_SLUG
--preview $CI_MERGE_REQUEST_IID
--ssh-options="-i $SSH_PRIVATE_KEY -o IdentitiesOnly=yes"
--sync "dist/"
--script "composer install --no-dev"
rules:
- if: $CI_MERGE_REQUEST_ID
destroy_preview:
stage: deploy
image: node:24
when: manual
before_script:
- chmod 600 "$SSH_PRIVATE_KEY"
script:
- npx @studiometa/trafic-cli destroy
--host $SSH_HOST
--name $CI_PROJECT_PATH_SLUG
--preview $CI_MERGE_REQUEST_IID
--ssh-options="-i $SSH_PRIVATE_KEY -o IdentitiesOnly=yes"
rules:
- if: $CI_MERGE_REQUEST_IDSSH_PRIVATE_KEY is a file-type CI variable. Do not use ssh-agent in GitLab CI: see the CLI README.
GitHub Actions
deploy_preview:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v4
- uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- run: npx @studiometa/trafic-cli deploy
--host ${{ vars.SSH_HOST }}
--name ${{ github.event.repository.name }}
--preview ${{ github.event.pull_request.number }}
--sync "dist/"
--script "composer install --no-dev"
destroy_preview:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request' && github.event.action == 'closed'
steps:
- uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- run: npx @studiometa/trafic-cli destroy
--host ${{ vars.SSH_HOST }}
--name ${{ github.event.repository.name }}
--preview ${{ github.event.pull_request.number }}Two Agent Skills teach a coding agent to use Trafic:
trafic-cli: write and fix the CI jobs that runtrafic setup,trafic deployandtrafic destroy.trafic-agent: operate the server (setup, upgrade, audit,destroy,config.toml).
Install them in a project or for your user:
npx skills add studiometa/trafic
# or, with the GitHub CLI
gh skill install studiometa/traficEach package also prints the skill that matches its version: trafic skill and trafic-agent skill.
- CLI README β Deploy and destroy commands
- Agent README β Server setup and configuration
- Example config β Full configuration reference
See CONTRIBUTING.md for development setup and guidelines.
See SECURITY.md for reporting vulnerabilities.
MIT Β© Studio Meta