Server Deployment
Learn how to deploy the Portr admin dashboard and tunnel server with Docker Compose to self-host your own tunneling infrastructure.
For quick setup, use the production compose file from the Portr repository:
https://github.com/amalshaji/portr/blob/main/docker-compose.prod.yaml
Services Overview
The production compose file includes 3 services:
- caddy: The reverse proxy for routing and SSL termination
- server: The combined admin and tunnel server
- postgres: The PostgreSQL database
Deployment Steps
Download the compose file
Download docker-compose.prod.yaml from the repository and place it in your server directory.
Set up environment variables
Create a .env file in the same directory with the following values:
Generate unique credentials for each deployment. Replace every placeholder in
the .env file, and use the same database secret in POSTGRES_PASSWORD and
PORTR_DB_URL.
Environment Variable Reference
| Variable | Description | Default |
|---|---|---|
PORTR_DOMAIN | Your server domain | localhost:8001 |
PORTR_DB_URL | PostgreSQL connection URL | Required |
PORTR_SERVER_URL | Public server URL for clients | http://localhost:8001 |
PORTR_SSH_URL | Public SSH URL for clients | localhost:2222 |
PORTR_SSH_PORT | SSH server port | 2222 |
PORTR_SSH_HOST_KEY | PEM-encoded Ed25519 private key | Required |
PORTR_ADMIN_PORT | Admin server port | 8000 |
PORTR_ADMIN_GITHUB_CLIENT_ID | GitHub OAuth client ID | Optional |
PORTR_ADMIN_GITHUB_CLIENT_SECRET | GitHub OAuth client secret | Optional |
PORTR_RESERVED_SUBDOMAIN_LIMIT | Maximum reserved subdomains per team membership; use 0 to disable new reservations | 3 |
PORTR_AUTO_MIGRATE | Auto-run database migrations | false |
CLOUDFLARE_API_TOKEN | Cloudflare API token for SSL | Required (bundled Caddy) |
If you run on SQLite instead of PostgreSQL, see SQLite Backups for the LITESTREAM_* variables that replicate the database to object storage.
If you already run a reverse proxy or manage TLS certificates manually, see Custom Reverse Proxy — the Cloudflare token is only needed by the bundled Caddy service.
Generate SSH Host Key
Generate an Ed25519 private key and set it as an environment variable:
Or use portrd to generate and print a key:
For Docker deployments, you can pass the key as a multi-line environment variable in your .env file or use Docker secrets.
Start the services
Run the following command to start all services:
The server container runs as a non-root user. If you keep the default ./data
bind mount, make sure that directory is writable by the container user before
starting the service.
Access the admin dashboard
Once the servers are running, navigate to your domain (e.g., https://example.com) and log in to the admin dashboard. The first login will be treated as a superuser account.
Alternative Database Setup
If you want to run PostgreSQL separately and not as a Docker service, you can exclude the following environment variables from your .env file:
POSTGRES_USERPOSTGRES_PASSWORDPOSTGRES_DB
Troubleshooting
Service Health Checks
Check if all services are running properly:
View Service Logs
Check logs for any specific service:
SSL Certificate Issues
If you're having SSL certificate issues, ensure:
- Your DNS records are properly configured
- Your Cloudflare API token has the correct permissions
- Your domain is added to Cloudflare
Port Accessibility
Verify that the required ports are accessible:
Server Setup
Guide to setting up the self-hosted Portr server, covering the admin dashboard, tunnel backend, DNS, and TLS certificate configuration.
SQLite Backups
Continuously replicate the Portr server's SQLite database to S3-compatible storage with Litestream, and restore it automatically after a lost volume.