streamline the examples to use 127.0.0.1:8000 as the address where vaultwarden listens on and also reword the intro a bit.

Stefan Melmuk
2025-07-09 14:53:15 +02:00
parent d0a595b50b
commit f92591d6b5

@@ -1,15 +1,19 @@
In this document, `<SERVER>` refers to the IP or domain where you access Vaultwarden. If both the reverse proxy and Vaultwarden are running on the same system, simply use `localhost`.
Below is a user-curated list of example configurations for different [reverse proxies](https://en.wikipedia.org/wiki/Reverse_proxy). We recommend using a reverse proxy to terminate TLS/SSL connections (preferably on port 443, the standard port for HTTPS) instead of using the HTTPS functionality built into Vaultwarden. See [Enabling HTTPS](https://github.com/dani-garcia/vaultwarden/wiki/Enabling-HTTPS) for more information about that.
By default, Vaultwarden listens on port 80 for web (REST API) traffic and [[WebSocket traffic|Enabling-WebSocket-notifications]].
The reverse proxy should be configured to terminate SSL/TLS connections (preferably on port 443, the standard port for HTTPS). The reverse proxy then passes incoming client requests to Vaultwarden on port 80 or the port on which you configured Vaultwarden to listen on, and upon receiving a response from Vaultwarden, passes that response back to the client.
In this document we assume that you run Vaultwarden on the same host as the reverse proxy. If you run Vaultwarden as a container the assumption would be that you have published `-p 127.0.0.1:8000:80` to the host, because Vaultwarden inside the container has been configured to listen on all IPv4 interfaces (`ROCKET_ADDRESS=0.0.0.0`) on port `80` (via `ROCKET_PORT`).
Note that when you put Vaultwarden behind a reverse proxy, the connections between the reverse proxy and Vaultwarden are typically assumed to be going through a secure private network, and thus do not need to be encrypted. The examples below assume you are running in this configuration, in which case you should not enable the HTTPS functionality built into Vaultwarden (i.e., you should not set the `ROCKET_TLS` environment variable). If you do, connections will fail since the reverse proxy is using HTTP to connect to Vaultwarden, but you're configuring Vaultwarden to expect HTTPS.
The examples also assume that you have not encrypted the connection between the reverse proxy and Vaultwarden, i.e. that you have not configured `ROCKET_TLS` and thus the reverse proxy can just connect via `http://127.0.0.1:8000` to Vaultwarden.
It's common to use [Docker Compose](https://docs.docker.com/compose/) to link containerized services together (e.g., Vaultwarden and a reverse proxy). See [[Using Docker Compose|Using-Docker-Compose]] for an example of this.
If you use [Docker Compose](https://docs.docker.com/compose/) to link containerized services together (e.g., Vaultwarden and a reverse proxy) you have to adapt the examples to take that into account (i.e. change `127.0.0.1:8000` to `service_name:80` where `service_name` typically would be `vaultwarden`). See [[Using Docker Compose|Using-Docker-Compose]] for an example of this.
> [!TIP]
Secure TLS protocol and cipher configurations for webservers can be generated using Mozilla's [SSL Configuration Generator](https://ssl-config.mozilla.org/). All supported browsers and the Mobile apps are known to work with the "Modern" configuration.
<details>
***
<details id="caddy2">
<summary>Caddy 2.x</summary><br/>
Caddy 2 will automatically enable HTTPS in most circumstances, check the [docs](https://caddyserver.com/docs/automatic-https#activation).
@@ -84,8 +88,8 @@ If you prefer, you can also directly specify a value instead of substituting an
# Proxy everything to Rocket
# if located at a sub-path the reverse_proxy line will look like:
# reverse_proxy /subpath/* <SERVER>:80
reverse_proxy <SERVER>:80 {
# reverse_proxy /vault/* 127.0.0.1:8000
reverse_proxy 127.0.0.1:8000 {
# Send the true remote IP to Rocket, so that Vaultwarden can put this in the
# log, so that fail2ban can ban the correct IP.
header_up X-Real-IP {remote_host}
@@ -97,11 +101,11 @@ If you prefer, you can also directly specify a value instead of substituting an
```
</details>
<details>
<details id="lighttpd">
<summary>lighttpd with sub-path (by FlakyPi)</summary><br/>
In this example Vaultwarden will be available via https://vaultwarden.example.tld/vault/<br/>
If you want to use any other sub-path, like `bitwarden` or `secret-vault` you should change `vault` in the example below to match.<br/>
In this example Vaultwarden will be available via https://shared.example.tld/vault/<br/>
If you want to use any other sub-path, like `vaultwarden` or `secret-vault` you should change `vault` in the example below to match.<br/>
```lighttpd
server.modules += (
@@ -110,23 +114,23 @@ server.modules += (
$SERVER["socket"] == ":443" {
ssl.engine = "enable"
ssl.pemfile = "/etc/letsencrypt/live/vaultwarden.example.tld/fullchain.pem"
ssl.privkey = "/etc/letsencrypt/live/vaultwarden.example.tld/privkey.pem"
ssl.pemfile = "/etc/letsencrypt/live/shared.example.tld/fullchain.pem"
ssl.privkey = "/etc/letsencrypt/live/shared.example.tld/privkey.pem"
}
# Redirect HTTP requests (port 80) to HTTPS (port 443)
$SERVER["socket"] == ":80" {
$HTTP["host"] =~ "vaultwarden.example.tld" {
url.redirect = ( "^/(.*)" => "https://vaultwarden.example.tld/$1" )
server.name = "vaultwarden.example.tld"
url.redirect = ( "^/(.*)" => "https://shared.example.tld/$1" )
server.name = "shared.example.tld"
}
}
server.modules += ( "mod_proxy" )
$HTTP["host"] == "vaultwarden.example.tld" {
$HTTP["host"] == "shared.example.tld" {
$HTTP["url"] =~ "/vault" {
proxy.server = ( "" => ("vaultwarden" => ( "host" => "<SERVER>", "port" => 8080 )))
proxy.server = ( "" => ("vaultwarden" => ( "host" => "127.0.0.1", "port" => 8000 )))
proxy.forwarded = ( "for" => 1 )
proxy.header = (
"https-remap" => "enable",
@@ -140,7 +144,7 @@ You'll have to set `IP_HEADER` to `X-Forwarded-For` instead of `X-Real-IP` in th
</details>
<details>
<details id="nginx">
<summary>Nginx (by <a href="https://github.com/BlackDex" target="_blank">@BlackDex</a>)</summary><br/>
```nginx
@@ -150,7 +154,7 @@ You'll have to set `IP_HEADER` to `X-Forwarded-For` instead of `X-Real-IP` in th
# Define the server IP and ports here.
upstream vaultwarden-default {
zone vaultwarden-default 64k;
server 127.0.0.1:8080;
server 127.0.0.1:8000;
keepalive 2;
}
@@ -227,11 +231,11 @@ If you run into 504 Gateway Timeout problems, tell nginx to wait longer for Vaul
</details>
<details>
<details id="nginx-with-subpath">
<summary>Nginx with sub-path (by <a href="https://github.com/BlackDex" target="_blank">@BlackDex</a>)</summary><br/>
In this example Vaultwarden will be available via https://shared.example.tld/vault/<br/>
If you want to use any other sub-path, like `bitwarden` or `secret-vault` you should change `/vault/` in the example below to match.<br/>
If you want to use any other sub-path, like `vaultwarden` or `secret-vault` you should change `/vault/` in the example below to match.<br/>
<br/>
For this to work you need to configure your `DOMAIN` variable to match so it should look like:
@@ -247,7 +251,7 @@ DOMAIN=https://shared.example.tld/vault/
# Define the server IP and ports here.
upstream vaultwarden-default {
zone vaultwarden-default 64k;
server 127.0.0.1:8080;
server 127.0.0.1:8000;
keepalive 2;
}
@@ -331,7 +335,7 @@ server {
```
</details>
<details>
<details id="nginx-nixos">
<summary>Nginx (NixOS) (by tklitschi, samdoshi)</summary><br/>
Example NixOS nginx config. For more Information about NixOS Deployment see [Deployment Wiki page](https://github.com/dani-garcia/vaultwarden/wiki/Deployment-examples).
@@ -345,7 +349,7 @@ Example NixOS nginx config. For more Information about NixOS Deployment see [Dep
acceptTerms = true;
email = "me@example.com";
};
certs."vaultwarden.example.com".group = "vaultwarden";
certs."vaultwarden.example.tld".group = "vaultwarden";
};
services.nginx = {
@@ -357,11 +361,11 @@ Example NixOS nginx config. For more Information about NixOS Deployment see [Dep
recommendedTlsSettings = true;
virtualHosts = {
"vaultwarden.example.com" = {
"vaultwarden.example.tld" = {
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://localhost:8080";
proxyPass = "http://127.0.0.1:8000";
proxyWebsockets = true;
};
};
@@ -372,7 +376,7 @@ Example NixOS nginx config. For more Information about NixOS Deployment see [Dep
```
</details>
<details>
<details id="nginx-proxy-protocol">
<summary>Nginx with proxy_protocol in front (by dionysius)</summary><br/>
In this example there is a downstream proxy communicating in [proxy_protocol in front of this nginx](https://docs.nginx.com/nginx/admin-guide/load-balancer/using-proxy-protocol/) (E.g. a [LXD proxy device with proxy_protocol enabled](https://linuxcontainers.org/lxd/docs/master/reference/devices_proxy/)). Nginx needs to correctly consume the protocol and headers to forward need to be set from the those. Lines marked with `# <---` have different contents than BlackDex's example.
@@ -406,7 +410,7 @@ real_ip_header proxy_protocol; # optional, if you want nginx to override remote_
# Define the server IP and ports here.
upstream vaultwarden-default {
zone vaultwarden-default 64k;
server 127.0.0.1:8080;
server 127.0.0.1:8000;
keepalive 2;
}
@@ -423,7 +427,7 @@ map $http_upgrade $connection_upgrade {
server {
listen 80 proxy_protocol; # <---
listen [::]:80 proxy_protocol; # <---
server_name vaultwarden.example.tld;
server_name shared.example.tld;
return 301 https://$host$request_uri;
}
@@ -432,12 +436,12 @@ server {
listen 443 ssl proxy_protocol; # <---
listen [::]:443 ssl proxy_protocol; # <---
http2 on;
server_name vaultwarden.example.tld;
server_name shared.example.tld;
# Specify SSL Config when needed
#ssl_certificate /path/to/certificate/letsencrypt/live/vaultwarden.example.tld/fullchain.pem;
#ssl_certificate_key /path/to/certificate/letsencrypt/live/vaultwarden.example.tld/privkey.pem;
#ssl_trusted_certificate /path/to/certificate/letsencrypt/live/vaultwarden.example.tld/fullchain.pem;
#ssl_certificate /path/to/certificate/letsencrypt/live/shared.example.tld/fullchain.pem;
#ssl_certificate_key /path/to/certificate/letsencrypt/live/shared.example.tld/privkey.pem;
#ssl_trusted_certificate /path/to/certificate/letsencrypt/live/shared.example.tld/fullchain.pem;
client_max_body_size 525M;
@@ -461,24 +465,24 @@ server {
```
</details>
<details>
<details id="apache">
<summary>Apache (by fbartels)</summary><br/>
Remember to enable `mod_proxy_wstunnel` and `mod_proxy_http`, for example with: `a2enmod proxy_wstunnel` and `a2enmod proxy_http`.
```apache
<VirtualHost *:443>
SSLEngine on
ServerName bitwarden.$hostname.$domainname
ServerName vaultwarden.example.tld
SSLCertificateFile ${SSLCERTIFICATE}
SSLCertificateKeyFile ${SSLKEY}
SSLCACertificateFile ${SSLCA}
${SSLCHAIN}
ErrorLog \${APACHE_LOG_DIR}/bitwarden-error.log
CustomLog \${APACHE_LOG_DIR}/bitwarden-access.log combined
ErrorLog \${APACHE_LOG_DIR}/vaultwarden-error.log
CustomLog \${APACHE_LOG_DIR}/vaultwarden-access.log combined
ProxyPass / http://<SERVER>:80/ upgrade=websocket
ProxyPass / http://127.0.0.1:8000/ upgrade=websocket
ProxyPreserveHost On
ProxyRequests Off
@@ -489,13 +493,13 @@ Remember to enable `mod_proxy_wstunnel` and `mod_proxy_http`, for example with:
```
</details>
<details>
<details id="apache-with-subpath">
<summary>Apache in a sub-location (by <a href=https://github.com/agentdr8 target=_blank>@agentdr8</a>)</summary><br/>
Modify your docker start-up to include the sub-location.
```
; Add the sub-location! Else this will not work!
DOMAIN=https://$hostname.$domainname/$sublocation/
DOMAIN=https://shared.example.tld/vault/
```
Ensure you have the websocket proxy module loaded somewhere in your apache config.
@@ -520,8 +524,8 @@ On some OS's you can use a2enmod, for example with: `a2enmod proxy_wstunnel` and
ErrorLog \${APACHE_LOG_DIR}/error.log
CustomLog \${APACHE_LOG_DIR}/access.log combined
<Location /$sublocation/> #adjust here if necessary
ProxyPass http://<SERVER>:<SERVER_PORT>/$sublocation upgrade=websocket
<Location /vault/> #adjust here if necessary
ProxyPass http://127.0.0.1:8000/vault/ upgrade=websocket
ProxyPreserveHost Off
RequestHeader set X-Real-IP %{REMOTE_ADDR}s
@@ -540,8 +544,8 @@ Copy the instructions above, except use the much simpler...
```apache
<VirtualHost *:443>
[ blah blah ]
<Location /$sublocation/> #adjust here if necessary
ProxyPass http://$server:$port/$sublocation/ upgrade=websocket
<Location /vault/> #adjust here if necessary
ProxyPass http://127.0.0.1:8000/vault/ upgrade=websocket
ProxyPreserveHost On
ProxyRequests Off # ... is the default, but as a safety-net
RequestHeader set X-Real-IP %{REMOTE_ADDR}s
@@ -557,12 +561,12 @@ Copy the instructions above, except use the much simpler...
labels:
- traefik.enable=true
- traefik.docker.network=traefik
- traefik.web.frontend.rule=Host:bitwarden.domain.tld
- traefik.web.frontend.rule=Host:vaultwarden.example.tld
- traefik.web.port=80
```
</details>
<details>
<details id="traefik">
<summary>Traefik v2 (docker-compose example by hwwilliams, gzfrozen)</summary><br/>
#### Traefik v1 labels migrated to Traefik v2
@@ -570,9 +574,9 @@ labels:
labels:
- traefik.enable=true
- traefik.docker.network=traefik
- traefik.http.routers.bitwarden.rule=Host(`bitwarden.domain.tld`)
- traefik.http.routers.bitwarden.service=bitwarden
- traefik.http.services.bitwarden.loadbalancer.server.port=80
- traefik.http.routers.vaultwarden.rule=Host(`vaultwarden.domain.tld`)
- traefik.http.routers.vaultwarden.service=vaultwarden
- traefik.http.services.vaultwarden.loadbalancer.server.port=80
```
#### Migrated labels plus HTTP to HTTPS redirect
@@ -585,19 +589,19 @@ labels:
- traefik.docker.network=traefik
- traefik.http.middlewares.redirect-https.redirectScheme.scheme=https
- traefik.http.middlewares.redirect-https.redirectScheme.permanent=true
- traefik.http.routers.bitwarden-https.rule=Host(`bitwarden.domain.tld`)
- traefik.http.routers.bitwarden-https.entrypoints=websecure
- traefik.http.routers.bitwarden-https.tls=true
- traefik.http.routers.bitwarden-https.service=bitwarden
- traefik.http.routers.bitwarden-http.rule=Host(`bitwarden.domain.tld`)
- traefik.http.routers.bitwarden-http.entrypoints=web
- traefik.http.routers.bitwarden-http.middlewares=redirect-https
- traefik.http.routers.bitwarden-http.service=bitwarden
- traefik.http.services.bitwarden.loadbalancer.server.port=80
- traefik.http.routers.vaultwarden-https.rule=Host(`vaultwarden.domain.tld`)
- traefik.http.routers.vaultwarden-https.entrypoints=websecure
- traefik.http.routers.vaultwarden-https.tls=true
- traefik.http.routers.vaultwarden-https.service=vaultwarden
- traefik.http.routers.vaultwarden-http.rule=Host(`vaultwarden.domain.tld`)
- traefik.http.routers.vaultwarden-http.entrypoints=web
- traefik.http.routers.vaultwarden-http.middlewares=redirect-https
- traefik.http.routers.vaultwarden-http.service=vaultwarden
- traefik.http.services.vaultwarden.loadbalancer.server.port=80
```
</details>
<details>
<details id="haproxy">
<summary>HAproxy (by <a href="https://github.com/BlackDex" target="_blank">@BlackDex</a>)</summary><br/>
Add these lines to your haproxy configuration.
@@ -618,10 +622,11 @@ backend vaultwarden_http
# Set the Source IP in the `X-Real-IP` header
http-request set-header X-Real-IP %[src]
# Send the traffic to the local instance
server vwhttp 0.0.0.0:8080 alpn http/1.1
server vwhttp 127.0.0.1:8000 alpn http/1.1
```
</details>
<details>
<details id="haproxy-kubernetes-ingress">
<summary>HAproxy Kubernetes Ingress(by <a href="https://github.com/devinslick" target="_blank">@devinslick</a>)</summary><br/>
Controller installation details can be found here: https://www.haproxy.com/documentation/kubernetes-ingress/community/installation/on-prem/
@@ -659,7 +664,8 @@ spec:
number: 80
```
</details>
<details>
<details id="istio">
<summary>Istio k8s (by <a href="https://github.com/asenyaev" target="_blank">@asenyaev</a>)</summary><br/>
```gateway+vs
@@ -712,7 +718,7 @@ spec:
```
</details>
<details>
<details id="cloudflare-tunnel">
<summary>CloudFlare Tunnel (by <a href="https://github.com/calvin-li-developer" target="_blank">@calvin-li-developer</a>)</summary><br/>
`docker-compose.yml`:
@@ -726,7 +732,7 @@ services:
image: vaultwarden/server:latest
restart: unless-stopped
environment:
DOMAIN: "https://vaultwarden.example.com" # Your domain; vaultwarden needs to know it's https to work properly with attachments
DOMAIN: "https://vaultwarden.example.tld" # Your domain; vaultwarden needs to know it's https to work properly with attachments
volumes:
- ./vw-data:/data
networks:
@@ -768,10 +774,10 @@ originRequest:
noTLSVerify: true
ingress:
- hostname: vault.example.com # change to your domain
- hostname: vaultwarden.example.tld # change to your domain
service: http_status:404
path: admin
- hostname: vault.example.com # change to your domain
- hostname: vaultwarden.example.tld # change to your domain
service: http://vaultwarden
- service: http_status:404
```
@@ -783,13 +789,12 @@ ingress:
</details>
<details>
<summary>Pound</summary><br/>
<summary id="pound">Pound</summary><br/>
```
Alive 15
ListenHTTP
Address 127.0.0.1
Port 80
xHTTP 3
HeadRemove "X-Forwarded-For"
@@ -800,7 +805,6 @@ ListenHTTP
End
ListenHTTPS
Address 127.0.0.1
Port 443
Cert "/path/to/certificate/letsencrypt/live/vaultwarden.example.tld/fullchain.pem"
xHTTP 3
@@ -813,8 +817,8 @@ End
Service
Host "vaultwarden.example.tld"
BackEnd
Address <SERVER>
Port 80
Address 127.0.0.1
Port 8000
End
End
```