Reverse Proxy Configuration
In production, PRISM sits behind a reverse proxy (nginx, Apache, or Caddy) that handles TLS termination, static assets, and request routing.
Your reverse proxy must strip the X-Prism-Bypass header from incoming requests. This header is used internally by PRISM to prevent render loops. If an external client sends it, they can bypass rendering entirely.
Nginx
:::danger Put every proxy_set_header in the same block
proxy_set_header directives are not merged across levels. A location
that defines even one of its own discards all of them from the enclosing
server block. Writing the bypass strip at server level and
proxy_set_header Connection "" inside location / therefore silently drops
the strip, and a client can forge X-Prism-Bypass.
Verified: with the directives split across levels a forged header arrives at the backend intact; with them together it arrives empty. :::
upstream prism {
server 127.0.0.1:4000;
keepalive 32;
}
server {
listen 443 ssl;
http2 on;
server_name example.com;
ssl_certificate /etc/ssl/certs/example.com.pem;
ssl_certificate_key /etc/ssl/private/example.com.key;
# Timeouts — allow time for Chrome rendering
proxy_read_timeout 30s;
proxy_connect_timeout 5s;
location / {
proxy_pass http://prism;
proxy_http_version 1.1;
# Every header this proxy sets must be listed here, in this block.
# Moving any of them to `server` level would take the rest with it.
proxy_set_header Connection "";
# CRITICAL: strip the bypass header so a client cannot forge it
proxy_set_header X-Prism-Bypass "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Serve static assets straight from the origin, bypassing rendering.
location ~* \.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|wasm|map)$ {
proxy_pass http://your-origin:3000;
# Repeated deliberately: this block has its own proxy_set_header, so it
# inherits nothing from above.
proxy_set_header X-Prism-Bypass "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Check the strip is working before trusting it:
curl -s -H 'X-Prism-Bypass: forged' https://example.com/ -o /dev/null -w '%{http_code}\n'
# then confirm the origin logged no X-Prism-Bypass value
Apache
Requires proxy, proxy_http, headers and ssl:
a2enmod proxy proxy_http headers ssl # Debian/Ubuntu
<VirtualHost *:443>
ServerName example.com
SSLEngine on
SSLCertificateFile /etc/ssl/certs/example.com.pem
SSLCertificateKeyFile /etc/ssl/private/example.com.key
# Never act as a forward proxy.
ProxyRequests Off
# CRITICAL: strip the bypass header so a client cannot forge it.
# `early` runs before the proxy hands the request on; without it the unset
# can be evaluated too late to matter on some configurations.
RequestHeader unset X-Prism-Bypass early
ProxyPreserveHost On
RequestHeader set X-Forwarded-Proto "https"
ProxyPass / http://127.0.0.1:4000/
ProxyPassReverse / http://127.0.0.1:4000/
# Allow time for Chrome rendering
ProxyTimeout 30
# Reuse upstream connections
<Proxy http://127.0.0.1:4000/>
ProxySet connectiontimeout=5 timeout=30 keepalive=On
</Proxy>
</VirtualHost>
mod_proxy appends the client address to X-Forwarded-For itself, so it does
not need setting; ProxyPreserveHost On passes the original Host.
Caddy
example.com {
# Strip bypass header
request_header -X-Prism-Bypass
reverse_proxy 127.0.0.1:4000 {
header_up X-Forwarded-Proto {scheme}
transport http {
keepalive 30s
keepalive_idle_conns 32
}
}
}
X-Prism-Variant for CDN Cache Keying
When viewport-aware rendering is enabled, PRISM returns an X-Prism-Variant header with the value mobile or desktop. If you have a CDN layer between nginx and clients, add this header to your Vary response or use it as a CDN cache key component.
In nginx, pass it through:
location / {
proxy_pass http://prism;
proxy_http_version 1.1;
proxy_set_header Connection "";
# Pass X-Prism-Variant to CDN for cache keying
add_header Vary "X-Prism-Variant" always;
}
See CDN Integration for CDN-specific configuration.
Trusted Proxies
When PRISM sits behind a reverse proxy, configure trusted_proxies so PRISM only accepts X-Forwarded-Proto from your proxy IPs:
[server]
trusted_proxies = ["127.0.0.1", "10.0.0.0/8", "172.16.0.0/12"]
When empty (the default), all proxies are trusted for backward compatibility.