Skip to content

TLS and your reverse proxy

The recommended setup is to run the install behind a reverse proxy or load balancer you already have, and let it terminate TLS. That’s what veltro install does by default (--tls off): the gateway serves plain HTTP on VELTRO_HTTP_PORT and your proxy sends every request to it. If you don’t have a proxy, the installer can run one for you; see the bundled TLS front end below.

Install with the address people will type, over https, and stop before anything starts:

Terminal window
veltro install --products <products> --public-url https://soc.example.com --skip-up

--public-url is saved as PUBLIC_BASE_URL in .env. Identity issues sessions and request assertions for that origin, and the products build their links from it, so it must be exactly the URL your proxy serves, with no path. To change it later, run veltro install again with the new --public-url.

The gateway listens on port 80 on every interface by default, which is also the port a proxy on the same host usually holds. Bind the gateway to loopback in .env before the first start:

.env
VELTRO_HTTP_PORT=127.0.0.1:8088
Terminal window
veltro up

When the proxy runs somewhere else, leave the port where you want it and firewall it so only the proxy can reach it. Either way, plain HTTP should never leave the host or the private network.

The whole install is one site on one origin: Home and Settings at /, the products at /vectorflow, /sigmatic/ and /warden/, and MCP at /mcp. Send all of it to the gateway, with no path rewriting. Your proxy must:

  • keep the Host header the client sent;
  • set X-Forwarded-For, which the gateway appends to;
  • set X-Forwarded-Proto: https. The gateway passes https on to the products and says http otherwise. Identity doesn’t trust the header: its cookies are Secure because PUBLIC_BASE_URL starts with https://;
  • pass WebSocket upgrades (Upgrade and Connection), because Sigmatic’s and Warden’s live updates use them;
  • stream responses without buffering, and allow long reads: event streams and the VectorFlow agent’s long poll stay open, and the gateway allows 24 hours;
  • accept request bodies up to 64 MB, the size of the log shipper batches on /api/logs/ and the agent batches on /api/agent/.
soc.example.com {
reverse_proxy 127.0.0.1:8088
}

That’s all Caddy needs. It gets a certificate for the name, keeps Host, sets the X-Forwarded-* headers, passes WebSockets, flushes event streams straight away, and sets no request body limit unless you add one.

# In the http block:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name soc.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name soc.example.com;
ssl_certificate /etc/ssl/soc.example.com/fullchain.pem;
ssl_certificate_key /etc/ssl/soc.example.com/privkey.pem;
client_max_body_size 64m;
location / {
proxy_pass http://127.0.0.1:8088;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_buffering off;
proxy_read_timeout 24h;
proxy_send_timeout 24h;
}
}

nginx’s defaults would break the install without these lines: it replaces Host with the upstream address, drops WebSocket upgrades, buffers event streams, closes idle reads after 60 seconds and refuses bodies over 1 MB.

Terminal window
curl -I https://soc.example.com/api/health/ready

A 200 means the proxy reaches the gateway and identity is ready. Then sign in at https://soc.example.com/login.

With Sigmatic installed, log shippers can use the same proxy: Sigmatic’s ingest API is at /api/logs/ on the public URL. The separate ingest listener on port 8001 stays private; see Install Sigmatic.

For an install with no proxy in front, --tls adds the tls compose profile (compose/tls.yml): Caddy 2.9.1-alpine in front of the gateway (veltro-nginx:80). The installer generates its Caddyfile from veltro.toml, so you choose a mode instead of editing configuration by hand.

Mode Behaviour
internal Caddy’s own CA, for a LAN. The root to trust is at tls/caddy-data/caddy/pki/authorities/local/root.crt
custom Mount your own tls/fullchain.pem and tls/privkey.pem
off No front end. Run behind your own proxy, as above (the default)
Terminal window
veltro install --products <products> --public-url https://example.com --tls custom
veltro up --tls custom # or: make up TLS=custom

The bundled Caddy doesn’t get certificates from Let’s Encrypt or any other ACME CA. For a publicly trusted certificate, either run your own proxy or put the certificate in tls/ and use custom; renewing it is up to you. An install made with the old --tls auto stops before it changes anything until you move it to one of those. See Bundled Let’s Encrypt TLS was removed.

Caddy serves HTTPS on the port in --public-url (443 when there isn’t one) and HTTP on VELTRO_TLS_HTTP_PORT (80). The host publishes the same HTTPS port unless you set VELTRO_HTTPS_PORT, for example behind NAT. The URL can’t use 80, 2019 or 8443. The installer moves the gateway to loopback (127.0.0.1:8088 by default) so Caddy is the only public listener. VELTRO_TLS_MODE records the selected mode. On a --tls internal install, veltro status and veltro demo seed trust the install’s own root, so they work on the host without extra setup.

With Sigmatic installed, the front end also serves Sigmatic’s log ingest over TLS on VELTRO_TLS_INGEST_PORT (8443); see Install Sigmatic.