Configuration Reference
All configuration is via environment variables. The server reads them at startup from the .env file in the Docker Compose directory. After changing .env, restart the server:
docker compose up -d tunnl
Required
The server will not start without these two variables.
| Variable | Description | Example |
|---|---|---|
DOMAIN |
Base domain for the server. Tunnel URLs are <subdomain>.<DOMAIN>. Do not include https://. Must match your DNS wildcard record. |
your.domain.com |
JWT_SECRET |
Secret key for signing authentication tokens. Must be at least 32 characters. Treat as a password — do not share or commit. Generate with openssl rand -hex 32. |
a3f8... (64 hex chars) |
Database
| Variable | Description | Default |
|---|---|---|
DATABASE_URL |
PostgreSQL connection string. In the Docker Compose setup, this is set automatically to the bundled PostgreSQL container. Override to point at an external database. Use sslmode=require for remote databases. |
postgres://tunnl:tunnl@postgres:5432/tunnl?sslmode=disable |
CREATE TABLE and CREATE INDEX privileges. Migrations run automatically on first startup.Server Behavior
| Variable | Description | Default |
|---|---|---|
PORT |
Port the Go server listens on inside Docker. Caddy reverse-proxies to this port. | 8080 |
MAX_TUNNELS |
Maximum concurrent tunnel connections per user account. | 5 |
REQUESTS_PER_HOUR |
Rate limit per tunnel, sliding window. Requests above this limit return 429 Too Many Requests to the caller. |
10000 |
FREE_SESSION_TIMEOUT |
Session timeout in seconds for free-tier users. Set to 0 to disable. Default allows sessions to persist. |
3600 |
TRUSTED_PROXIES |
Comma-separated list of trusted proxy CIDRs for real IP extraction. Set to your load balancer or Caddy IP. Defaults to loopback only. | 127.0.0.1 |
TLS (Caddy)
TLS is handled entirely by Caddy, which runs on the host separately from Docker Compose. There are no TLS-related environment variables in the tunnl-server itself. Configure TLS certificate paths directly in your Caddyfile:
your.domain.com, *.your.domain.com {
tls /etc/ssl/tunnl/fullchain.pem /etc/ssl/tunnl/privkey.pem
reverse_proxy localhost:8080
}
See the Install Guide TLS section for full setup instructions including certificate renewal.
Email (SMTP)
Email is used for account verification and password reset. If not configured, the server logs verification tokens to stdout — usable for local development but not for multi-user deployments.
| Variable | Description | Example |
|---|---|---|
SMTP_HOST |
SMTP server hostname. | smtp.resend.com |
SMTP_PORT |
SMTP port. Use 587 for STARTTLS (recommended), 465 for TLS, 25 for unencrypted. | 587 |
SMTP_USERNAME |
SMTP username for authentication. | resend |
SMTP_PASSWORD |
SMTP password or API key. Keep this secret. | re_... |
SMTP_FROM |
From address for outgoing email. Must be a verified sender domain with your SMTP provider. | noreply@your.domain.com |
Redis (Optional)
Redis is not required. Without it, rate limiting is in-memory and resets on restart. Configure Redis if you plan to run multiple server instances.
| Variable | Description | Example |
|---|---|---|
REDIS_URL |
Redis connection string. Leave blank to use in-memory rate limiting. When set, the rate limiter state persists across restarts and is shared between multiple server instances. | redis://localhost:6379 |
Example .env
A complete .env for a production single-server deployment:
# Required DOMAIN=your.domain.com JWT_SECRET=<output of: openssl rand -hex 32> DB_PASSWORD=<secure-password> SELF_HOSTED_MODE=true # Server behavior (optional) PORT=8080 MAX_TUNNELS=25 REQUESTS_PER_HOUR=50000 TRUSTED_PROXIES=127.0.0.1 FREE_SESSION_TIMEOUT=3600 # Email (optional but recommended for multi-user) SMTP_HOST=smtp.resend.com SMTP_PORT=587 SMTP_USERNAME=resend SMTP_PASSWORD=re_<your_resend_api_key> SMTP_FROM=noreply@your.domain.com # Redis (optional, for distributed rate limiting) REDIS_URL=