Expose a service
The quickest way to put a service behind ProxyOS is the Expose flow. Click + Expose service on the Dashboard or navigate to /expose.
Fields
- Name — a friendly label (e.g. "Home Assistant")
- Domain — the public hostname Caddy will listen on (e.g.
ha.home.example.com) - Upstream URL — the internal address of your service (e.g.
http://192.168.1.50:8123) - TLS mode — how Caddy obtains a certificate (see TLS section below)
- SSO — optionally gate the service behind a forward-auth provider
What happens
- A route record is saved to the database
- Caddy is told about the route via its Admin API — no restart needed
- If TLS mode is
autoordns, Caddy begins certificate provisioning immediately - The route appears in
/routeswithin seconds
Managing routes
All proxy rules live under /routes. Each route maps one domain to one or more upstreams.
Route list
- Green dot = enabled and live in Caddy
- Grey dot = disabled (Caddy rule removed, upstream unreachable won't affect other routes)
- Click a route to open its detail page
Route detail
From the detail page you can:
- Edit — change upstreams, TLS mode, SSO, rate limiting, IP allowlist, headers
- Toggle — enable or disable the route without deleting it
- Test — probe each upstream and see HTTP status + latency
- Logs — view per-route access log entries
- SLO — set uptime targets and see availability over time
- Delete — permanently removes the route and its Caddy rule
Advanced options
- Rate limiting — requests per window (e.g. 100 req / 1m)
- IP allowlist — CIDR blocks that are allowed through (all others blocked)
- Basic auth — username/password layer in front of the upstream
- Compression — gzip/zstd response compression (on by default)
- WebSocket / HTTP2 / HTTP3 — protocol support toggles
- Health check — path and interval for upstream health probing
TLS & certificates
ProxyOS delegates all TLS to Caddy. Choose a mode per route:
TLS modes
- auto (default) — Caddy obtains a Let's Encrypt certificate via HTTP-01. Requires port 80 reachable from the internet and a valid public DNS record pointing to your server.
- dns — DNS-01 challenge. Works behind NAT or firewalls. Requires a DNS provider credential (see DNS Providers). Supports wildcard certs.
- internal — Caddy issues a self-signed cert from its internal CA. Useful for LAN-only services. Your browser will show an untrusted cert warning unless you import the CA.
- off — Plain HTTP only. No TLS. Useful when another proxy terminates TLS upstream.
Certificate list
Navigate to /certificates to see all certificates Caddy is managing, their expiry, renewal status, and source. You can also:
- Request a multi-domain (SAN) certificate under
Certificates → Multi-domain - Set up ACME settings under
Certificates → ACME - View Certificate Transparency logs under
Certificates → CT
DNS providers
DNS providers are credentials that Caddy uses to complete DNS-01 ACME challenges. Required when using tlsMode: dns.
Adding a DNS provider
- Go to
/dnsand click Add provider - Select the provider type (Cloudflare, Route53, DigitalOcean, etc.)
- Enter your API credentials (token or key+secret depending on provider)
- Save — the provider is now available when creating or editing routes
Supported providers
Cloudflare, AWS Route53, DigitalOcean, Namecheap, Porkbun, Gandi, and any provider supported by the Caddy DNS module ecosystem.
SSO / forward auth
ProxyOS can gate any route behind a forward-auth provider. Supported providers include Authelia, Authentik, Keycloak, and any service that implements the forward-auth protocol.
Setting up a provider
- Go to
/ssoand click Add provider - Give it a name and select the type
- Forward auth URL — the URL Caddy will call to verify each request (e.g.
https://auth.example.com/api/verify) - Auth response headers — headers the auth service returns and that Caddy forwards to the upstream (e.g.
Remote-User,Remote-Groups) - Trusted IPs — CIDRs that bypass SSO (e.g. your LAN subnet)
- Click Test to verify the provider URL is reachable before saving
Enabling SSO on a route
- Open the route detail and toggle SSO enabled
- Select the provider from the dropdown
- Save — Caddy immediately requires auth before proxying requests to the upstream
Analytics
The Analytics page (/analytics) shows traffic data parsed from Caddy's JSON access log at /tmp/proxyos-access.log.
- Request volume — requests per hour/day broken down by route
- Status distribution — 2xx / 3xx / 4xx / 5xx split
- Top upstreams — which backends receive the most traffic
- Latency — p50 / p95 / p99 response times per route
- Bandwidth — bytes in/out per route
Use the time range picker to zoom into specific windows. The data refreshes on every page load.
Agents & federation
Agents let you manage remote ProxyOS instances from a single dashboard — useful for multi-server homelabs or edge deployments.
Adding an agent
- Go to
/agentsand click Add agent - Enter the remote ProxyOS URL and its API token
- The agent is polled for health and route count
Connections
/connections manages outbound webhook connections to external systems (Slack, Discord, PagerDuty, custom webhooks). These are used by the Alerts and Monitors features.
Scanner
/scanner scans your network for running services and suggests routes. Enter a CIDR range and port list; the scanner probes each host and returns a list of discovered endpoints you can expose with one click.
Import existing config
Already running Nginx, Traefik, or Caddy? Import your existing configuration at /import.
Supported formats
- Nginx — paste or upload an
nginx.conf/ server block file - Traefik — paste a YAML dynamic config or Docker labels export
- Caddy — paste a Caddyfile
Import flow
- Upload or paste your config
- ProxyOS parses it and shows a preview of routes it detected
- Deselect any routes you don't want to import
- Click Import — routes are created in the database and pushed to Caddy
- Import history is saved under
/import/history
Security rules
/security provides a global security overview and lets you configure rules that apply across all routes.
- Global IP blocklist — block individual IPs or CIDRs from all routes
- Bot protection — block known bad user agents and crawler signatures
- Geo blocking — restrict traffic by country code (requires MaxMind GeoIP)
- Security headers — enforce HSTS, CSP, X-Frame-Options, etc. globally
- Vulnerability scanner — passive scan of incoming requests for common attack patterns
Monitors & alerts
/monitors runs periodic uptime checks against your exposed services.
Adding a monitor
- Click Add monitor and enter the URL to check
- Set the check interval (30 s – 60 min)
- Optionally set expected HTTP status and a response body substring to assert
- Assign one or more notification connections (Slack, email, webhook)
Alerts
/alerts shows triggered alert events. Each event records the monitor that fired, the time, the status code received, and the error message. Alerts auto-resolve when the next successful check completes.
Logs
/logs shows three log streams in one place:
- System — internal ProxyOS events (startup, Caddy push errors, auth events). Filter by level (info / warn / error) and category (caddy / auth / system / api / user).
- Access — HTTP access log from Caddy. Shows method, path, status, latency, and client IP for every request.
- Alerts — monitor alert events (same as the Alerts page, surfaced here for convenience).
Filtering
- Use the search box to full-text search log messages
- Use the date range pickers to scope to a time window
- Use the level and category dropdowns to narrow results
- Click Export CSV to download the filtered results
caddy with level error and include the full error message, domain, and TLS mode for easy diagnosis.Audit log
/audit is an immutable record of every user action: route create/update/delete, SSO changes, user management, billing events, and settings changes.
- Each entry shows the action, resource name, actor (user email), timestamp, and detail JSON
- Filter by action type or search by resource name
- Export to CSV for compliance reporting
Billing & licences
/billing manages your ProxyOS subscription or self-hosted licence key.
Cloud plans
- Free — 3 routes, community support
- Solo ($9/mo) — unlimited routes, SSO, DNS challenge, analytics
- Teams ($29/mo) — everything in Solo plus multi-user, federation agents, priority support
Click Upgrade on any plan card to be taken to the checkout. After payment you are redirected back to the dashboard and your plan is activated automatically.
Self-hosted licence keys
If you are running ProxyOS as a self-hosted deployment with a licence key:
- Scroll to the Self-hosted licence section on the Billing page
- Paste your licence key and click Activate
- The key is verified against the Lemon Squeezy API and stored locally
- To deactivate (e.g. to move to another server) click Deactivate
Manage billing
Click Manage billing to open the Lemon Squeezy customer portal where you can update your payment method, download invoices, or cancel your subscription.
Settings
Profile (/settings/profile)
Update your display name, email, password, and avatar.
Users (/settings/users)
Invite additional users by email. Assign roles (admin or viewer). Admins can create and edit routes; viewers have read-only access.
API keys (/settings/api-keys)
Generate long-lived API tokens for programmatic access to the ProxyOS tRPC API. Tokens are shown once — store them securely.
Templates (/settings/templates)
Save route configurations as reusable templates (e.g. a standard WordPress setup with compression + rate limiting). Apply a template when creating a new route to pre-fill all fields.
Integrations (/settings/integrations)
Connect ProxyOS to third-party services: GitHub (for automation triggers), Grafana (push metrics), and Slack (notifications).
Caddy (/settings/caddy)
View the raw Caddy config currently loaded and manually trigger a config reload. Useful for debugging Caddy-level issues.
Export (/settings/export)
Export your entire ProxyOS configuration as JSON — routes, providers, settings — for backup or migration.
Tracing (/settings/tracing)
Enable OpenTelemetry tracing and configure an OTLP endpoint (Jaeger, Tempo, etc.) to receive distributed traces from ProxyOS.
Tailscale / Netbird
ProxyOS works fully on private networks. If you access your homelab via Tailscale or Netbird you do not need a public domain — use the device IP and port directly.
Configuration
# In .env — use your Tailscale IP or MagicDNS hostname PROXYOS_URL=http://100.x.x.x:3000 # Or with Tailscale MagicDNS PROXYOS_URL=https://myserver.tail1234.ts.net:3000
Routing services over Tailscale
- Set TLS mode to
internalso Caddy issues a self-signed cert (no Let's Encrypt needed since the domain isn't public) - Or use
offfor plain HTTP inside the Tailscale tunnel - Set the upstream to the Tailscale IP of the target machine (e.g.
http://100.x.x.x:8080)
tlsMode: off on ProxyOS and let Tailscale terminate TLS at the edge.Troubleshooting
Caddy admin API not reachable
ProxyOS talks to Caddy on localhost:2019 inside the container. If you see "Caddy admin API not reachable" in Logs, check that the Caddy process started correctly:
docker logs proxyos | grep caddy
TLS push errors (invalid traversal path)
This occurs when Caddy has a persistent config volume from an older version that did not include the TLS app. Since v2, ProxyOS initialises the TLS app on every startup so this should not occur after rebuilding the container.
docker compose up -d --build
Port already in use
If port 80 or 443 is taken by another service, change the host-side ports in .env:
PROXYOS_HTTP_PORT=8080 PROXYOS_HTTPS_PORT=8443
Caddy still listens on 80/443 inside the container — only the host mapping changes.
Dashboard not loading after port change
Set PROXYOS_DASHBOARD_PORT in .env and access the dashboard on the new port. The container-internal Next.js server always runs on port 3000.
Viewing full error details
All Caddy push errors are written to the System log in the UI. Go to /logs, set category to caddy and level to error. Each entry includes the domain, TLS mode, and the raw Caddy error message.
Database location
The SQLite database is stored at /data/proxyos/proxyos.db inside the container, backed by the proxyos-data Docker volume. To inspect it:
docker exec -it proxyos sqlite3 /data/proxyos/proxyos.db .tables
Reset everything
To start completely fresh, remove the volumes:
docker compose down -v docker compose up -d
.env is not affected.