Skip to content

Commit a6dd4c8

Browse files
Document config.json setup behind a reverse proxy
Explain the difference between port and serverUri, TLS options between the proxy and solid-server, required proxy headers (Host, WebSocket upgrade), multi-user mode, and add example NGINX and Apache configurations. Closes #819
1 parent e0ee057 commit a6dd4c8

2 files changed

Lines changed: 206 additions & 1 deletion

File tree

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ accidentally commit your certificates to `solid` while you're developing.
106106
If you would like to get rid of the browser warnings, import your fullchain.pem certificate into your 'Trusted Root Certificate' store.
107107

108108
### Running Solid behind a reverse proxy (such as NGINX)
109-
See [Running Solid behind a reverse proxy](https://github.com/solid/node-solid-server/wiki/Running-Solid-behind-a-reverse-proxy).
109+
See [Running Solid behind a reverse proxy](docs/reverse-proxy.md) for how to set `port` and `serverUri` in `config.json`, and for example NGINX and Apache configurations.
110110

111111
### Run multi-user server (intermediate)
112112

‎docs/reverse-proxy.md‎

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
# Running Solid behind a reverse proxy
2+
3+
A common way to deploy `solid-server` is behind a reverse proxy such as
4+
NGINX, Apache or HAProxy. The proxy listens on the public ports (80 and 443),
5+
and forwards requests to `solid-server`, which listens on a private port on
6+
the same machine (or another machine on your network).
7+
8+
```
9+
Browser ── https://example.com ──▶ reverse proxy (:443) ──▶ solid-server (localhost:8443)
10+
```
11+
12+
This page explains how to configure `config.json` for this setup, and what
13+
the proxy needs to pass through. For more proxy examples, see also the wiki
14+
page [Running Solid behind a reverse proxy](https://github.com/nodeSolidServer/node-solid-server/wiki/Running-Solid-behind-a-reverse-proxy).
15+
16+
## `port` vs. `serverUri`
17+
18+
These two options are easy to confuse:
19+
20+
| Option | Meaning | Example |
21+
|-------------|--------------------------------------------------------------|-------------------------|
22+
| `port` | The port `solid-server` listens on. Only the proxy uses it. | `"8443"` |
23+
| `serverUri` | The public URL of your server, exactly as users see it. | `"https://example.com"` |
24+
25+
`serverUri` must **not** contain the internal port. `solid-server` uses
26+
`serverUri` (its scheme, host and port) to build every URL it hands out:
27+
WebIDs, pod URLs, login and redirect URLs, and so on. If you set it to
28+
`https://example.com:8443`, all those URLs will point at a port that is not
29+
reachable from the outside.
30+
31+
So, if your proxy serves `https://example.com` on port 443 and forwards to
32+
`solid-server` on port 8443:
33+
34+
```json
35+
{
36+
"port": "8443",
37+
"serverUri": "https://example.com"
38+
}
39+
```
40+
41+
Only include a port in `serverUri` if your users actually connect on a
42+
non-standard port, for example `https://example.com:4443`.
43+
44+
## TLS between the proxy and `solid-server`
45+
46+
`solid-server` decides whether to serve HTTPS or plain HTTP based on whether
47+
`sslKey` and `sslCert` are set.
48+
49+
### Option A: HTTPS all the way (recommended)
50+
51+
Keep `sslKey` and `sslCert` in `config.json`, and have the proxy forward to
52+
`https://localhost:8443`. You can reuse the same certificate as the proxy.
53+
54+
```json
55+
{
56+
"port": "8443",
57+
"serverUri": "https://example.com",
58+
"sslKey": "/etc/letsencrypt/live/example.com/privkey.pem",
59+
"sslCert": "/etc/letsencrypt/live/example.com/fullchain.pem"
60+
}
61+
```
62+
63+
This is how most public deployments run, and it keeps session cookies marked
64+
`Secure`.
65+
66+
### Option B: TLS only at the proxy
67+
68+
If you leave out `sslKey` and `sslCert`, `solid-server` serves plain HTTP on
69+
`port`, and the proxy forwards to `http://localhost:8443`. `serverUri` must
70+
still be the public `https://` URL.
71+
72+
Note that `solid-server` only marks its session cookie as `Secure` when
73+
`sslKey` is set, so in this mode the cookie is sent without the `Secure`
74+
flag. Make sure `solid-server` is only reachable through the proxy (bind it
75+
to localhost or firewall the port).
76+
77+
## What the proxy must forward
78+
79+
Whatever proxy you use, it needs to:
80+
81+
- **Preserve the `Host` header.** `solid-server` uses the request's host name
82+
to work out which pod a request is for, especially in multi-user mode,
83+
where each pod is a subdomain like `alice.example.com`. In NGINX use
84+
`proxy_set_header Host $http_host;`, and in Apache use `ProxyPreserveHost On`.
85+
- **Support WebSocket upgrades.** Solid uses WebSockets for live update
86+
notifications. Pass the `Upgrade` and `Connection` headers through (see the
87+
example below), or start `solid-server` with `--no-live` if you don't need
88+
them.
89+
- **Allow long requests.** Some requests, like large uploads, can take a
90+
while. Raise the proxy's read timeout if needed.
91+
92+
Don't use `redirectHttpFrom` behind a proxy. Let the proxy handle redirecting
93+
port 80 to 443.
94+
95+
## Multi-user mode
96+
97+
With `"multiuser": true`, every account gets its own subdomain
98+
(`https://alice.example.com/`). Behind a proxy you need:
99+
100+
- a wildcard DNS record for `*.example.com`, as well as `example.com`
101+
- a TLS certificate that covers both `example.com` and `*.example.com`
102+
- a proxy configuration that accepts both, for example
103+
`server_name example.com *.example.com;` in NGINX
104+
105+
`serverUri` stays the root domain, `https://example.com`.
106+
107+
## Example: NGINX
108+
109+
`config.json`:
110+
111+
```json
112+
{
113+
"root": "/var/www/example.com/data",
114+
"port": "8443",
115+
"serverUri": "https://example.com",
116+
"webid": true,
117+
"multiuser": true,
118+
"sslKey": "/etc/letsencrypt/live/example.com/privkey.pem",
119+
"sslCert": "/etc/letsencrypt/live/example.com/fullchain.pem"
120+
}
121+
```
122+
123+
NGINX site configuration:
124+
125+
```nginx
126+
# Redirect all HTTP traffic to HTTPS
127+
server {
128+
listen 80;
129+
listen [::]:80;
130+
server_name example.com *.example.com;
131+
return 301 https://$host$request_uri;
132+
}
133+
134+
server {
135+
listen 443 ssl;
136+
listen [::]:443 ssl;
137+
server_name example.com *.example.com;
138+
server_tokens off;
139+
140+
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
141+
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
142+
143+
location / {
144+
# Use http:// here instead if you chose Option B above
145+
proxy_pass https://localhost:8443;
146+
proxy_http_version 1.1;
147+
proxy_redirect off;
148+
proxy_read_timeout 300;
149+
proxy_connect_timeout 300;
150+
151+
proxy_set_header Host $http_host;
152+
proxy_set_header X-Real-IP $remote_addr;
153+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
154+
proxy_set_header X-Forwarded-Proto $scheme;
155+
156+
# WebSockets (live updates)
157+
proxy_set_header Upgrade $http_upgrade;
158+
proxy_set_header Connection "upgrade";
159+
}
160+
}
161+
```
162+
163+
Start the server with:
164+
165+
```bash
166+
solid start --config-file /var/www/example.com/config.json
167+
```
168+
169+
## Example: Apache
170+
171+
With `mod_proxy`, `mod_proxy_http`, `mod_proxy_wstunnel`, `mod_ssl` and
172+
`mod_rewrite` enabled:
173+
174+
```apache
175+
<VirtualHost *:443>
176+
ServerName example.com
177+
ServerAlias *.example.com
178+
179+
SSLEngine on
180+
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
181+
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
182+
183+
# Needed when proxying to https://localhost
184+
SSLProxyEngine On
185+
SSLProxyCheckPeerName off
186+
187+
ProxyPreserveHost On
188+
RequestHeader set X-Forwarded-Proto "https"
189+
190+
# WebSockets (live updates)
191+
RewriteEngine On
192+
RewriteCond %{HTTP:Upgrade} =websocket [NC]
193+
RewriteRule ^/(.*) wss://localhost:8443/$1 [P,L]
194+
195+
ProxyPass / https://localhost:8443/
196+
ProxyPassReverse / https://localhost:8443/
197+
</VirtualHost>
198+
```
199+
200+
## WebID-TLS
201+
202+
If you use the WebID-TLS authentication method (`"auth": "tls"`), the client
203+
certificate is sent during the TLS handshake. A proxy that terminates TLS
204+
cannot pass it on, so WebID-TLS will not work behind a standard reverse
205+
proxy. The default authentication method, `oidc`, works fine.

0 commit comments

Comments
 (0)