8.1 KiB
8.1 KiB
Jitsi & Nginx Deployment Configuration
Overview
This document covers the configuration required to deploy uPortal alongside a Docker-based Jitsi Meet instance behind Nginx.
Environment Variables (.env)
These are the variables used by uPortal for Jitsi integration. Copy them into your .env file:
| Variable | Required | Default | Purpose |
|---|---|---|---|
JITSI_SECRET |
Yes | — | HMAC-SHA256 shared secret for signing JWTs. Must match the secret configured in Jitsi's prosody (JWT_APP_SECRET). Generate with: openssl rand -hex 32 |
JITSI_APP_ID |
Yes | — | Jitsi App ID. Used as the iss (issuer) and aud (audience) in JWTs. Match this to JWT_APP_ID in Jitsi's prosody config. |
JITSI_DOMAIN |
No | meet.jit.si |
Your Jitsi Meet instance FQDN (e.g. meet.example.com). |
SITE_DOMAIN |
No | — | The public domain of the portal (e.g. portal.example.com). Required for absolute avatar URLs in JWT context — otherwise Jitsi cannot fetch avatars. |
TRUSTED_DOMAIINS |
No | — | Comma-separated domains that bypass the external-redirect warning. Add your Jitsi domain here to skip the interstitial page. |
Note on
TRUSTED_DOMAIINS: The variable name contains a typo (double "I") — this matches the codebase, so keep it as-is.
Minimal .env for Jitsi
JITSI_SECRET=your-64-char-hex-secret-here
JITSI_APP_ID=my_uportal_app
JITSI_DOMAIN=meet.example.com
SITE_DOMAIN=portal.example.com
TRUSTED_DOMAIINS=meet.example.com
Docker-Based Jitsi Meet Setup
1. Prerequisites
- Docker and Docker Compose installed
- A server with a public IP and domain names pointing to it
- Ports 80 and 443 accessible (or behind Nginx)
2. Clone Jitsi Meet Docker
git clone https://github.com/jitsi/docker-jitsi-meet.git
cd docker-jitsi-meet
cp env.example .env
3. Configure Jitsi .env
Edit the Jitsi .env file. The critical settings for JWT authentication:
# --- Domain / TLS ---
CONFIG=~/.jitsi-meet-cfg
HTTP_PORT=8000
HTTPS_PORT=8443
# --- JWT Authentication (REQUIRED for uPortal integration) ---
ENABLE_AUTH=1
AUTH_TYPE=jwt
JWT_APP_ID=my_uportal_app # Must match uPortal's JITSI_APP_ID
JWT_APP_SECRET=your-64-char-hex-secret-here # Must match uPortal's JITSI_SECRET
JWT_ACCEPTED_ISSUERS=my_uportal_app
JWT_ACCEPTED_AUDIENCES=my_uportal_app
JWT_ASAP_KEYSERVER=
JWT_ALLOW_EMPTY=false
# --- Optional: Disable guest access ---
# JWT_AUTH_MODULE=jwt
4. Start Jitsi Meet
docker compose up -d
This starts the full Jitsi stack: prosody (XMPP), jicofo (focus), jvb (video bridge), and web (nginx frontend).
Nginx Reverse Proxy Configuration
Sample /etc/nginx/sites-available/uportal
server {
listen 80;
server_name portal.example.com meet.example.com;
return 301 https://$server_name$request_uri;
}
# uPortal
server {
listen 443 ssl http2;
server_name portal.example.com;
ssl_certificate /etc/letsencrypt/live/portal.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/portal.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8080;
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;
}
location /static/ {
proxy_pass http://127.0.0.1:8080;
expires 7d;
add_header Cache-Control "public, immutable";
}
}
# Jitsi Meet
server {
listen 443 ssl http2;
server_name meet.example.com;
ssl_certificate /etc/letsencrypt/live/meet.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/meet.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8000; # Jitsi HTTP port
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;
# WebSocket support (required for Jitsi)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Large file uploads (recording, streaming)
client_max_body_size 10M;
client_body_buffer_size 128k;
}
# Long-polling for Jitsi
location ~ ^/(xmpp|http-bind) {
proxy_pass http://127.0.0.1:8000;
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 300s;
proxy_send_timeout 300s;
}
}
Key Points
- uPortal runs on
127.0.0.1:8080(usedocker compose run -p 127.0.0.1:8080:8080or systemd service) - Jitsi HTTP port is
8000(from Jitsi'sHTTP_PORT=8000), proxied on a different subdomain - WebSocket support is essential for Jitsi video/audio — the
UpgradeandConnectionheaders must be forwarded - Both services can share the same Nginx instance with different
server_nameblocks
Docker Compose for uPortal
The project includes docker-compose.yml and Dockerfile for containerized deployment:
version: '3.8'
services:
uportal:
build:
context: .
dockerfile: Dockerfile
container_name: uportal
ports:
- "127.0.0.1:8080:8080" # Bind to loopback behind Nginx
volumes:
- ./data:/app # Persist SQLite database locally
environment:
LOG_LEVEL: info
JITSI_SECRET: your-64-char-hex-secret-here
JITSI_APP_ID: my_uportal_app
JITSI_DOMAIN: meet.example.com
SITE_DOMAIN: portal.example.com
TRUSTED_DOMAIINS: meet.example.com
restart: unless-stopped
Bind to
127.0.0.1:8080(not0.0.0.0:8080) when running behind Nginx on the same host to avoid direct external access.
Architecture Diagram
Internet
│
├── portal.example.com:443 ──┐
│ Nginx (reverse proxy) │
│ ├── / → uPortal :8080 │
│ └── /static/ → uPortal │
│ │
└── meet.example.com:443 ────┤
Nginx (reverse proxy) │
├── / → Jitsi Web :8000 │
├── /xmpp → Jitsi │
└── /http-bind → Jitsi │
│
Docker Network │
├── uPortal container │
│ ├── uportal binary │
│ ├── uportal.db (SQLite) │
│ ├── templates/ │
│ └── static/ │
│ │
└── jitsi-docker stack │
├── prosody (XMPP) │
├── jicofo (focus) │
├── jvb (video bridge) │
└── web (nginx front) │
│
┌──────────────────────────────┘
│
JWT Signing: uPortal signs JWT with JITSI_SECRET
→ Redirects user to meet.example.com/room?jwt=...
→ Jitsi verifies JWT with matching JWT_APP_SECRET
Troubleshooting
| Symptom | Likely Cause | Fix |
|---|---|---|
| "Jitsi secret is not configured" | JITSI_SECRET not set in uPortal .env |
Set the variable |
| "Jitsi app id is not configured" | JITSI_APP_ID not set |
Set the variable |
| "Authentication failed" in Jitsi | JWT secret mismatch between uPortal and Jitsi | Verify JITSI_SECRET = JWT_APP_SECRET |
| "Invalid issuer" in Jitsi logs | JITSI_APP_ID ≠ JWT_APP_ID |
Make them match |
| Avatar not showing in Jitsi | SITE_DOMAIN not set, or avatar missing |
Set SITE_DOMAIN to the portal's public URL |
| External redirect warning page appears | Jitsi domain not in TRUSTED_DOMAIINS |
Add the domain |