Files
open-webui-docs/docs/tutorials/tab-nginx/LetsEncrypt.md
2025-11-23 20:14:50 +01:00

300 lines
9.2 KiB
Markdown

### Let's Encrypt
Let's Encrypt provides free SSL certificates trusted by most browsers, ideal for securing your production environment. 🔐
This guide uses a two-phase approach:
1. **Phase 1:** Temporarily run Nginx to prove you own the domain and get a certificate from Let's Encrypt.
2. **Phase 2:** Reconfigure Nginx to use the new certificate for a secure HTTPS connection.
#### Prerequisites
* A **domain name** (e.g., `my-webui.com`) with a **DNS `A` record** pointing to your server's public IP address.
* **Docker** and **Docker Compose** installed on your server.
* Basic understanding of running commands in a terminal.
:::info
**Heads up\!** Let's Encrypt **cannot** issue certificates for an IP address. You **must** use a domain name.
:::
-----
### Step 1: Initial Setup for Certificate Validation
First, we'll set up the necessary files and a temporary Nginx configuration that allows Let's Encrypt's servers to verify your domain.
1. **Make sure you followed the [Prerequisites](#prerequisites) above.**
2. **Create the Directory Structure**
From your project's root directory, run this command to create folders for your Nginx configuration and Let's Encrypt certificates:
```bash
mkdir -p nginx/conf.d ssl/certbot/conf ssl/certbot/www
```
3. **Create a Temporary Nginx Configuration**
Create the file `nginx/conf.d/open-webui.conf`. This initial config only listens on port 80 and serves the validation files for Certbot.
⚠️ **Remember to replace `<YOUR_DOMAIN_NAME>`** with your actual domain.
```nginx
# nginx/conf.d/open-webui.conf
server {
listen 80;
listen [::]:80;
server_name <YOUR_DOMAIN_NAME>;
# Route for Let's Encrypt validation challenges
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
# All other requests will be ignored for now
location / {
return 404;
}
}
```
4. **Update Your `docker-compose.yml`**
Add the `nginx` service to your `docker-compose.yml` and ensure your `open-webui` service is configured to use the shared Docker network.
```yaml
services:
nginx:
image: nginx:alpine
restart: always
ports:
# Expose HTTP and HTTPS ports to the host machine
- "80:80"
- "443:443"
volumes:
# Mount Nginx configs and SSL certificate data
- ./nginx/conf.d:/etc/nginx/conf.d
- ./ssl/certbot/conf:/etc/letsencrypt
- ./ssl/certbot/www:/var/www/certbot
depends_on:
- open-webui
networks:
- open-webui-network
open-webui:
# Your existing open-webui configuration...
# ...
# Ensure it's on the same network
networks:
- open-webui-network
# Expose the port internally to the Docker network.
# You do NOT need to publish it to the host (e.g., no `ports` section is needed here).
expose:
- 8080
networks:
open-webui-network:
driver: bridge
```
-----
### Step 2: Obtain the SSL Certificate
Now we'll run a script that uses Docker to fetch the certificate.
1. **Create the Certificate Request Script**
Create an executable script named `enable_letsencrypt.sh` in your project root.
⚠️ **Remember to replace `<YOUR_DOMAIN_NAME>` and `<YOUR_EMAIL_ADDRESS>`** with your actual information.
```bash
#!/bin/bash
# enable_letsencrypt.sh
DOMAIN="<YOUR_DOMAIN_NAME>"
EMAIL="<YOUR_EMAIL_ADDRESS>"
echo "### Obtaining SSL certificate for $DOMAIN ###"
# Start Nginx to serve the challenge
docker compose up -d nginx
# Run Certbot in a container to get the certificate
docker run --rm \
-v "./ssl/certbot/conf:/etc/letsencrypt" \
-v "./ssl/certbot/www:/var/www/certbot" \
certbot/certbot certonly \
--webroot \
--webroot-path=/var/www/certbot \
--email "$EMAIL" \
--agree-tos \
--no-eff-email \
--force-renewal \
-d "$DOMAIN"
if [[ $? != 0 ]]; then
echo "Error: Failed to obtain SSL certificate."
docker compose stop nginx
exit 1
fi
# Stop Nginx before we apply the final config
docker compose stop nginx
echo "### Certificate obtained successfully! ###"
```
2. **Make the Script Executable**
```bash
chmod +x enable_letsencrypt.sh
```
3. **Run the Script**
Execute the script. It will automatically start Nginx, request the certificate, and then stop Nginx.
```bash
./enable_letsencrypt.sh
```
-----
### Important: Caching Configuration
When using NGINX with Open WebUI, proper caching is crucial for performance while ensuring authentication remains secure. The configuration below includes:
- **Cached**: Static assets (CSS, JS, fonts, images) for better performance
- **Not Cached**: Authentication endpoints, API calls, SSO/OAuth callbacks, and session data
- **Result**: Faster page loads without breaking login functionality
The configuration below implements these rules automatically.
### Step 3: Finalize Nginx Configuration for HTTPS
With the certificate saved in your `ssl` directory, you can now update the Nginx configuration to enable HTTPS.
1. **Update the Nginx Configuration for SSL**
**Replace the entire contents** of `nginx/conf.d/open-webui.conf` with the final configuration below.
⚠️ **Replace all 4 instances of `<YOUR_DOMAIN_NAME>`** with your domain.
```nginx
# nginx/conf.d/open-webui.conf
# Redirect all HTTP traffic to HTTPS
server {
listen 80;
listen [::]:80;
server_name <YOUR_DOMAIN_NAME>;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name <YOUR_DOMAIN_NAME>;
ssl_certificate /etc/letsencrypt/live/<YOUR_DOMAIN_NAME>/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/<YOUR_DOMAIN_NAME>/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-RSA-AES128-GCM-SHA256';
ssl_prefer_server_ciphers off;
location ~* ^/(auth|api|oauth|admin|signin|signup|signout|login|logout|sso)/ {
proxy_pass http://open-webui:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
proxy_read_timeout 10m;
proxy_buffering off;
client_max_body_size 20M;
proxy_no_cache 1;
proxy_cache_bypass 1;
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0" always;
add_header Pragma "no-cache" always;
expires -1;
}
location ~* \.(css|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$ {
proxy_pass http://open-webui:8080;
proxy_http_version 1.1;
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;
# Cache static assets for 7 days
expires 7d;
add_header Cache-Control "public, immutable";
}
location / {
proxy_pass http://open-webui:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
proxy_read_timeout 10m;
proxy_buffering off;
client_max_body_size 20M;
add_header Cache-Control "public, max-age=300, must-revalidate";
}
}
```
2. **Launch All Services**
Start both Nginx and Open WebUI with the final, secure configuration.
```bash
docker compose up -d
```
-----
### Step 4: Access Your Secure WebUI
You can now access your Open WebUI instance securely via HTTPS.
➡️ **`https://<YOUR_DOMAIN_NAME>`**
-----
### (Optional) Step 5: Setting Up Automatic Renewal
Let's Encrypt certificates expire every 90 days. You should set up a `cron` job to renew them automatically.
1. Open the crontab editor:
```bash
sudo crontab -e
```
2. Add the following line to run a renewal check every day at 3:30 AM. It will only renew if the certificate is close to expiring.
```cron
30 3 * * * /usr/bin/docker run --rm -v "<absolute_path>/ssl/certbot/conf:/etc/letsencrypt" -v "<absolute_path>/ssl/certbot/www:/var/www/certbot" certbot/certbot renew --quiet --webroot --webroot-path=/var/www/certbot --deploy-hook "/usr/bin/docker compose -f <absolute_path>/docker-compose.yml restart nginx"
```