CI/CD·8 min read·

Dynamic Ephemeral Staging Environments per Pull Request with Traefik and Wildcard DNS

Provision isolated preview URLs automatically for every pull request branch on a shared VPS host with automated Let's Encrypt wildcard certificates.

NB

Netbay Infrastructure Team

Netbay Engineering

On this page

Static staging environments are a notorious bottleneck in modern software engineering teams. When five developers want to test their pull requests simultaneously, they find themselves competing for a single 'staging.example.in' server. Someone overwrites the database, another deploys broken code, and testing grinds to a halt.

Ephemeral staging environments solve this by giving every pull request its own live, isolated preview URL (e.g., 'https://pr-42.preview.example.in'). When the PR is closed or merged, the environment is automatically decommissioned.

Using a single Netbay VPS host, Traefik proxy, wildcard DNS, and Docker Compose, you can run dozens of dynamic PR preview environments concurrently with automated SSL.

Dynamic Preview Routing Architecture

The ephemeral staging host relies on three automated pillars:

  • Wildcard DNS: A single DNS record '*.preview.example.in' points to the staging VPS public IP address.
  • Traefik Edge Router: Listens to the local Docker socket. Whenever a container with matching labels boots, Traefik automatically routes its sub-domain and attaches a valid wildcard TLS certificate.
  • GitHub Actions Webhook: On pull request open or update, CI clones the branch, boots the preview container, and comments the live URL directly on the PR.
Ephemeral PR Staging Router Architecture GitHub Webhook PR Opened / Synchronize Branch: feature/checkout PR Number: #142 Traefik Ingress Router Wildcard DNS (*.preview.example.in) ACME DNS Challenge TLS Auto-Discovers Docker Labels Zero Manual Proxy Config pr-140.preview.example.in Container: pr-140-app pr-142.preview.example.in Container: pr-142-app Resource Isolation & Auto-Teardown Each container has its own SQLite/Postgres schema and isolated cgroup memory limits Closing or merging a pull request immediately tears down containers and wipes disk state

Docker Compose Template with Traefik Labels

Below is the dynamic Compose template launched by CI for each PR:

yaml
# docker-compose.pr.yml
version: '3.8'

services:
  app:
    image: registry.example.in/app:pr-$PR_NUMBER
    container_name: pr-$PR_NUMBER-app
    restart: on-failure
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.pr-$PR_NUMBER.rule=Host('pr-$PR_NUMBER.preview.example.in')"
      - "traefik.http.routers.pr-$PR_NUMBER.entrypoints=websecure"
      - "traefik.http.routers.pr-$PR_NUMBER.tls=true"
      - "traefik.http.services.pr-$PR_NUMBER.loadbalancer.server.port=3000"
    environment:
      - DATABASE_URL=file:/data/pr.sqlite
      - PR_NUMBER=$PR_NUMBER
    deploy:
      resources:
        limits:
          memory: 512M
          cpus: '0.5'

Automated GitHub Actions Deploy Step

In the repository CI workflow, spin up the preview environment and comment the URL:

bash
# .github/workflows/preview.yml step
- name: Deploy Ephemeral Staging
  run: |
    export PR_NUMBER=${{ github.event.pull_request.number }}
    ssh deploy@staging.example.in "
      export PR_NUMBER=$PR_NUMBER
      docker compose -f docker-compose.pr.yml up -d --remove-orphans
    "
    echo "Preview ready at: https://pr-$PR_NUMBER.preview.example.in"
Expand
Pull Request Staging Collaboration
Pull request staging collaboration

Video Reference on Container Ingress & Routing

Review container networking, reverse proxies, and ingress routing architecture:

Kubernetes Tutorial for Beginners
YouTube

Ephemeral staging preview URLs empower product managers, QA testers, and developers to review changes concurrently without staging conflicts.

Deploy dedicated staging and preview hosts on Netbay Cloud VPS instances with instant scaling at netbayhosts.in.

Keep reading

Follow along on a real VPS

Deploy Linux in under 60 seconds

These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.

Deploy an instance