Set up Caddy as an HTTPS reverse proxy for validator RPC endpoints
Configure Caddy as an automatic HTTPS reverse proxy in front of the Integralayer validator's RPC endpoints, providing TLS termination, CORS headers, and WebSocket support.
[Internet]
│
▼ HTTPS (:443)
[Caddy]
├── /rpc → localhost:8545 (EVM JSON-RPC)
├── /ws → localhost:8546 (EVM WebSocket)
├── /cometbft → localhost:26657 (CometBFT RPC)
├── /cometbft/* → localhost:26657
├── /rest → localhost:1317 (Cosmos REST API)
└── /rest/* → localhost:1317
Caddy automatically provisions and renews TLS certificates via Let's Encrypt. No manual certificate management is needed.
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
docker pull caddy:2
If using Docker, mount the Caddyfile and data volumes:
docker run -d --name caddy \
--network host \
-v /etc/caddy/Caddyfile:/etc/caddy/Caddyfile \
-v caddy_data:/data \
-v caddy_config:/config \
caddy:2
Caddy needs ports 80 (HTTP, for ACME challenge) and 443 (HTTPS):
sudo ufw allow 80/tcp comment "Caddy HTTP (ACME challenge)"
sudo ufw allow 443/tcp comment "Caddy HTTPS"
Important: Once Caddy is proxying the RPC endpoints over HTTPS, you can close the direct RPC ports (8545, 8546, 26657, 1317) from public access if they were previously open. Keep them listening on localhost only.
Use the template at templates/caddy/Caddyfile or create /etc/caddy/Caddyfile with the following configuration:
yourdomain.com {
# ── EVM JSON-RPC (HTTP) ──────────────────────────────
handle /rpc {
reverse_proxy localhost:8545
}
# ── EVM WebSocket ────────────────────────────────────
handle /ws {
reverse_proxy localhost:8546 {
# Strip Origin header — required for EVM WebSocket to accept connections
header_up -Origin
}
}
# ── CometBFT RPC ────────────────────────────────────
handle /cometbft {
reverse_proxy localhost:26657
}
handle /cometbft/* {
uri strip_prefix /cometbft
reverse_proxy localhost:26657
}
# ── Cosmos REST API ──────────────────────────────────
handle /rest {
reverse_proxy localhost:1317
}
handle /rest/* {
uri strip_prefix /rest
reverse_proxy localhost:1317
}
# ── CORS Headers ────────────────────────────────────
header {
Access-Control-Allow-Origin *
Access-Control-Allow-Methods "GET, POST, OPTIONS"
Access-Control-Allow-Headers "Content-Type, Authorization"
Access-Control-Max-Age 3600
}
# ── Logging ──────────────────────────────────────────
log {
output file /var/log/caddy/access.log {
roll_size 100mb
roll_keep 5
roll_keep_for 720h
}
format json
}
}
Replace yourdomain.com with your actual domain (e.g., adamboudj.integralayer.com).
header_up -Origin: The EVM WebSocket endpoint rejects connections with an Origin header that does not match localhost. Stripping the header allows browser-based dApps to connect.uri strip_prefix: Removes the path prefix before forwarding to the backend. For example, /cometbft/status becomes /status when forwarded to port 26657.*: Allows any origin. For production, restrict to specific domains if your endpoints are not intended to be fully public.# Start and enable Caddy
sudo systemctl start caddy
sudo systemctl enable caddy
# Check status
sudo systemctl status caddy
Caddy will automatically:
# Systemd logs
journalctl -u caddy -f --no-hostname
# Access logs (if configured)
tail -f /var/log/caddy/access.log | jq .
curl -s https://yourdomain.com/rpc \
-X POST \
-H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}' | jq .
Expected response:
{
"jsonrpc": "2.0",
"id": 1,
"result": "0x6669"
}
(0x6669 = 26217 in hex for mainnet, 0x666a = 26218 for testnet)
# Install wscat if needed: npm install -g wscat
wscat -c wss://yourdomain.com/ws
Once connected, send:
{"jsonrpc":"2.0","method":"eth_subscribe","params":["newHeads"],"id":1}
You should receive new block headers in real time.
# Node status
curl -s https://yourdomain.com/cometbft/status | jq '.result.sync_info.latest_block_height'
# Net info
curl -s https://yourdomain.com/cometbft/net_info | jq '.result.n_peers'
# Latest block
curl -s https://yourdomain.com/rest/cosmos/base/tendermint/v1beta1/blocks/latest | jq '.block.header.height'
# Validator set
curl -s https://yourdomain.com/rest/cosmos/staking/v1beta1/validators | jq '.validators | length'
Caddy automatically provisions TLS certificates from Let's Encrypt using the ACME protocol. Requirements:
The /ws endpoint requires special handling:
header_up -Origin directive strips the Origin header, which the EVM WebSocket server uses to validate connectionsConnection: Upgrade and Upgrade: websocket headers)For public-facing endpoints, consider adding rate limiting to prevent abuse:
yourdomain.com {
# Rate limit: 100 requests per second per IP
rate_limit {
zone dynamic_zone {
key {remote_host}
events 100
window 1s
}
}
# ... rest of config
}
Note: The
rate_limitdirective requires the Caddy rate-limit plugin. Install it withxcaddy build --with github.com/mholt/caddy-ratelimitor use the Docker image that includes it. Seereferences/security-hardening.mdfor DDoS protection strategies.
If endpoints are not meant to be fully public, restrict CORS to known origins:
header {
Access-Control-Allow-Origin "https://app.yourdomain.com"
Access-Control-Allow-Methods "GET, POST, OPTIONS"
Access-Control-Allow-Headers "Content-Type, Authorization"
}
Once Caddy is handling all external traffic, restrict backend ports to localhost only:
In ~/.intgd/config/config.toml:
[rpc]
laddr = "tcp://127.0.0.1:26657"
In ~/.intgd/config/app.toml:
[json-rpc]
address = "127.0.0.1:8545"
ws-address = "127.0.0.1:8546"
[api]
address = "tcp://127.0.0.1:1317"
Then remove the public firewall rules for those ports:
sudo ufw delete allow 8545/tcp
sudo ufw delete allow 8546/tcp
sudo ufw delete allow 26657/tcp
sudo ufw delete allow 1317/tcp
| Setting | Value |
|---------|-------|
| Network Name | Integralayer |
| RPC URL | https://yourdomain.com/rpc |
| Chain ID | 26217 (mainnet) or 26218 (testnet) |
| Currency Symbol | IRL |
| Block Explorer URL | https://explorer.integralayer.com |
journalctl -u caddy for ACME errors.header_up -Origin is in the /ws handler. Check that the EVM WebSocket is running on port 8546 (curl http://localhost:8546).ss -tlnp | grep <port>.Access-Control-Allow-Origin response header.xcaddy or use an alternative rate-limiting approach.references/security-hardening.md -- Rate limiting and DDoS protectionreferences/network-config.md -- Port reference and backend configurationtemplates/caddy/Caddyfile -- Template CaddyfileSearch for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer