Skip to main content
In development, the OpenClaw gateway listens on localhost:18789 and the website connects to it directly. In production, you need HTTPS and proper domain names. This guide sets up Caddy as a reverse proxy with automatic SSL certificates.

Architecture

Both domains proxy to the same OpenClaw gateway on localhost:18789. The gateway serves the LogLife plugin API (/loglife/*) and the OpenClaw Control UI (/__openclaw__/) on the same port. Caddy handles SSL, domain routing, and access control.

Why a reverse proxy?

  • HTTPS: Without it, API keys and gateway tokens travel in plain text. Caddy gets free SSL certificates from Let’s Encrypt automatically.
  • Access control: The API domain is open (protected by Bearer token). The admin domain adds HTTP basic auth so the Control UI is not publicly accessible.
  • Clean URLs: Users and Vercel connect to https://api.loglife.co instead of http://123.45.67.89:18789.
  • Port isolation: Port 18789 stays closed to the public. Only Caddy reaches it internally.

DNS setup

Add two A records in your DNS provider (e.g. GoDaddy, Cloudflare) pointing to your server’s IP:
TypeNameValueTTL
AapiYour server IP600
AadminYour server IP600
Both records point to the same IP. Caddy differentiates them by domain name.
DNS changes can take up to an hour to propagate, but typically complete in under 5 minutes.

Caddy setup

Install Caddy

sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
  | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
  | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy

Generate a password hash

Pick a username and password for the Control UI. Caddy uses bcrypt hashes:
caddy hash-password --plaintext 'your-password-here'
Copy the output (starts with $2a$14$...).

Configure Caddy

Edit /etc/caddy/Caddyfile:
api.loglife.co {
    reverse_proxy localhost:18789
}

admin.loglife.co {
    basicauth {
        admin $2a$14$PASTE_YOUR_HASH_HERE
    }
    reverse_proxy localhost:18789
}
Replace admin with your chosen username and paste the hash from the previous step.

Gateway token

The Control UI has its own authentication layer (separate from Caddy’s basic auth). After passing basic auth, the Control UI will prompt for the gateway token. The gateway auto-generates this token on first startup and saves it to ~/.openclaw/openclaw.json. Read it with:
./openclaw.mjs config get gateway.auth.token
If you need to regenerate it (e.g. after a suspected leak):
./openclaw.mjs config set gateway.auth.token "$(openssl rand -hex 24)"
./openclaw.mjs gateway restart
The gateway token, the Caddy basic auth password, and the LogLife API key are three separate credentials:
  • Gateway token (gateway.auth.token) — authenticates the Control UI and CLI connections to the gateway
  • Caddy basic auth — protects admin.loglife.co from public access
  • LogLife API key (plugins.entries.loglife.config.apiKey) — authenticates Vercel’s requests to the plugin endpoints

Start Caddy

sudo systemctl restart caddy
sudo systemctl enable caddy
Caddy automatically obtains SSL certificates. No additional configuration needed.

Firewall

Open ports 80 and 443, and close direct access to the gateway port:
sudo ufw allow 80/tcp     # Let's Encrypt ACME challenge
sudo ufw allow 443/tcp    # HTTPS
sudo ufw delete allow 18789/tcp  # close direct access
Hetzner Cloud users: Hetzner has its own firewall layer that runs above ufw. Even if ufw allows a port, Hetzner’s firewall can still block it. Go to the Hetzner Cloud Console > your project > Firewalls and add inbound rules for TCP 80 and TCP 443 from 0.0.0.0/0 and ::/0. Without this, Caddy cannot complete the ACME challenge and SSL certificates will fail with “Timeout during connect (likely firewall problem)”.
Other cloud providers (AWS, GCP, DigitalOcean, etc.) have similar external firewalls — security groups, VPC firewall rules, or cloud firewalls. Always check both the OS-level firewall (ufw, iptables) and the cloud provider’s firewall when ports appear closed.

Verify

# API endpoint (should return 404 — "Session not found")
curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://api.loglife.co/loglife/sessions?phone=healthcheck"

# Admin UI (should prompt for username/password in browser)
curl -I "https://admin.loglife.co/__openclaw__/"
# Expected: 401 Unauthorized (basic auth required)

Update Vercel

After Caddy is running, update the OPENCLAW_API_URL in your Vercel project settings:
VariableOld valueNew value
OPENCLAW_API_URLhttp://SERVER_IP:18789https://api.loglife.co
The OPENCLAW_API_KEY stays the same.

Troubleshooting

DNS

Check your DNS records:
dig api.loglife.co +short
dig admin.loglife.co +short
Both should return your server’s IP. If not, verify the A records in your DNS provider (GoDaddy, Cloudflare, etc.). DNS changes can take up to an hour to propagate — wait and retry.
DNS is fine, but the server isn’t accepting connections. Check that Caddy is running and ports are open:
sudo systemctl status caddy
sudo ss -tlnp | grep -E ':80|:443'
If nothing is listening on 80/443, restart Caddy: sudo systemctl restart caddy.

SSL certificates

This means Let’s Encrypt cannot reach your server on port 80 or 443 to verify domain ownership. Most common causes:
  1. Cloud provider firewall (Hetzner, AWS, GCP, etc.) is blocking inbound traffic — see the warning above about Hetzner Cloud Firewalls.
  2. OS firewall (ufw or iptables) is blocking port 80. Check with sudo ufw status or sudo iptables -L -n.
  3. Another service is already using port 80 (e.g. Apache). Check with sudo ss -tlnp | grep :80.
After fixing the firewall, restart Caddy so it retries:
sudo systemctl restart caddy
sleep 15
sudo journalctl -u caddy --no-pager -n 10
Look for “certificate obtained successfully” in the logs.
If curl https://api.loglife.co fails with an SSL error from the server, it may be because the certificate hasn’t been issued yet. Check Caddy logs:
sudo journalctl -u caddy --no-pager -n 20
If certificates are still being obtained, wait a moment and retry. Caddy will retry automatically on failure.

Reverse proxy

The OpenClaw gateway is not running. Start it:
cd ~/openclaw
./openclaw.mjs gateway start
Verify it’s listening:
curl http://localhost:18789
The Bearer token doesn’t match. Check that the key in Vercel matches the key in OpenClaw’s config:
grep apiKey ~/.openclaw/openclaw.json
Update whichever side is out of sync. If you regenerated the key, update both Vercel and GitHub secrets.
The OpenClaw gateway may also require its own authentication token. You’ll see the basic auth prompt from Caddy first, then the gateway may require its own credentials. Check your gateway config:
grep -A2 '"auth"' ~/.openclaw/openclaw.json
The gateway token is separate from the Caddy basic auth password and from the LogLife API key.
The issue is between Vercel’s servers and your server. Check step by step:
# 1. Verify DNS resolves correctly
dig api.loglife.co +short

# 2. Verify HTTPS works externally
curl -I https://api.loglife.co

# 3. Verify the plugin responds
curl -H "Authorization: Bearer YOUR_KEY" \
  "https://api.loglife.co/loglife/sessions?phone=test"
If step 2 times out, ports 80/443 are blocked at the cloud provider level. If step 3 returns 401, the API key is wrong.