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.
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.
Docker Compose Template with Traefik Labels
Below is the dynamic Compose template launched by CI for each PR:
# 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:
# .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"Video Reference on Container Ingress & Routing
Review container networking, reverse proxies, and ingress routing architecture:
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