This guide explains how to set up NGINX with SSL/TLS for OpenTranscribe, enabling:
- Browser microphone recording (required for HTTPS - browsers block mic access over HTTP)
- Secure access from any device on your network
- Production deployments with custom domains
Modern browsers enforce strict security policies. The getUserMedia() API (used for microphone access) only works in:
localhostconnections (development exception)- HTTPS connections (production requirement)
If you try to use microphone recording over HTTP from another device or IP address, browsers will block it. This is documented in GitHub Issue #72.
For homelabs and small businesses, self-signed certificates are the fastest way to get HTTPS working.
# Navigate to OpenTranscribe directory
cd /path/to/OpenTranscribe
# Generate certificates with auto-detected IP addresses
./scripts/generate-ssl-cert.sh opentranscribe.local --auto-ip
# Or specify IP addresses manually
./scripts/generate-ssl-cert.sh opentranscribe.local --ip 192.168.1.100 --ip 10.0.0.50This creates:
nginx/ssl/server.crt- SSL certificatenginx/ssl/server.key- Private key
Edit your .env file and add/uncomment:
NGINX_SERVER_NAME=opentranscribe.localOption A: Router DNS (Recommended)
Add a DNS entry in your router pointing opentranscribe.local to your server's IP address.
Option B: Local Hosts File
On each client device, add to /etc/hosts (Linux/Mac) or C:\Windows\System32\drivers\etc\hosts (Windows):
192.168.1.100 opentranscribe.local
Replace 192.168.1.100 with your server's actual IP address.
Multi-Service Homelab Setup
If you run multiple services on the same server, you can add multiple hostnames pointing to the same IP:
192.168.1.100 opentranscribe.local
192.168.1.100 nextcloud.local
192.168.1.100 jellyfin.local
192.168.1.100 homeassistant.local
Each service's NGINX/reverse proxy uses the Host header to route traffic correctly. This is a standard homelab configuration that works reliably.
Pi-hole / AdGuard Home / Local DNS Server
If you use a local DNS server (Pi-hole, AdGuard Home, Unbound, etc.), add an A record:
- Domain:
opentranscribe.local - IP Address: Your server's IP (e.g.,
192.168.1.100)
./opentr.sh start devThe script automatically detects NGINX_SERVER_NAME and includes the NGINX overlay.
On each device that will access OpenTranscribe, you need to trust the self-signed certificate.
- Copy
nginx/ssl/server.crtto the client device - Double-click the
.crtfile - Click Install Certificate → Local Machine
- Select Place all certificates in the following store
- Browse and select Trusted Root Certification Authorities
- Complete the wizard and restart your browser
- Copy
nginx/ssl/server.crtto the Mac - Double-click to open in Keychain Access
- Find the certificate in the list, double-click it
- Expand Trust section
- Set When using this certificate to Always Trust
- Close the window and enter your password to confirm
- Open Chrome and go to
chrome://settings/certificates - Click Authorities tab → Import
- Select
nginx/ssl/server.crt - Check Trust this certificate for identifying websites
- Click OK and restart Chrome
- Open Firefox and go to
about:preferences#privacy - Scroll to Certificates → View Certificates
- Click Authorities tab → Import
- Select
nginx/ssl/server.crt - Check Trust this CA to identify websites
- Click OK and restart Firefox
- Email or AirDrop
server.crtto your iOS device - Open the file → "Profile Downloaded" notification appears
- Go to Settings → General → VPN & Device Management
- Tap the downloaded profile and install it
- Go to Settings → General → About → Certificate Trust Settings
- Enable full trust for the OpenTranscribe certificate
- Copy
server.crtto your Android device - Go to Settings → Security → Encryption & credentials
- Tap Install a certificate → CA certificate
- Select the
.crtfile and confirm installation
Open your browser and go to:
https://opentranscribe.local
You can now use microphone recording from any device on your network!
For production deployments with a public domain, use Let's Encrypt for free, trusted certificates.
- A domain name pointing to your server (e.g.,
transcribe.example.com) - Ports 80 and 443 accessible from the internet
# Ubuntu/Debian
sudo apt install certbot
# CentOS/RHEL
sudo dnf install certbot
# macOS
brew install certbotStop OpenTranscribe if running:
./opentr.sh stopGenerate certificates (standalone mode):
sudo certbot certonly --standalone -d transcribe.example.comOr with DNS validation (if ports 80/443 aren't available):
sudo certbot certonly --manual --preferred-challenges dns -d transcribe.example.com# Create nginx/ssl directory
mkdir -p nginx/ssl
# Link Let's Encrypt certificates
sudo ln -sf /etc/letsencrypt/live/transcribe.example.com/fullchain.pem nginx/ssl/server.crt
sudo ln -sf /etc/letsencrypt/live/transcribe.example.com/privkey.pem nginx/ssl/server.key
# Fix permissions for Docker
sudo chmod 644 /etc/letsencrypt/live/transcribe.example.com/fullchain.pem
sudo chmod 600 /etc/letsencrypt/live/transcribe.example.com/privkey.pemEdit .env:
NGINX_SERVER_NAME=transcribe.example.com
NGINX_CERT_FILE=/etc/letsencrypt/live/transcribe.example.com/fullchain.pem
NGINX_CERT_KEY=/etc/letsencrypt/live/transcribe.example.com/privkey.pem# Test renewal
sudo certbot renew --dry-run
# Add to crontab for automatic renewal
echo "0 0 1 * * certbot renew --quiet && docker compose restart nginx" | sudo tee -a /etc/crontab./opentr.sh start prod| Variable | Default | Description |
|---|---|---|
NGINX_SERVER_NAME |
(none) | Hostname for NGINX. Setting this enables the NGINX overlay. |
NGINX_HTTP_PORT |
80 |
HTTP port (redirects to HTTPS) |
NGINX_HTTPS_PORT |
443 |
HTTPS port |
NGINX_CERT_FILE |
./nginx/ssl/server.crt |
Path to SSL certificate |
NGINX_CERT_KEY |
./nginx/ssl/server.key |
Path to SSL private key |
OpenTranscribe/
├── docker-compose.nginx.yml # NGINX service definition
├── nginx/
│ ├── site.conf.template # NGINX configuration template
│ └── ssl/
│ ├── server.crt # SSL certificate
│ └── server.key # SSL private key
└── scripts/
└── generate-ssl-cert.sh # Certificate generation script
| Path | Destination | Description |
|---|---|---|
/ |
Frontend (port 8080) | Svelte SPA |
/api/ws |
Backend WebSocket | Real-time notifications |
/api/ |
Backend REST API | All API endpoints |
/flower/ |
Flower (port 5555) | Celery task monitoring |
/minio/ |
MinIO Console (port 9001) | S3 storage management |
/s3/ |
MinIO API (port 9000) | Direct S3 operations |
The script checks for certificates before starting. Generate them first:
./scripts/generate-ssl-cert.sh your-hostname.local --auto-ipThis is expected with self-signed certificates. You have two options:
- Trust the certificate on each device (recommended for homelab)
- Use Let's Encrypt for publicly trusted certificates (recommended for production)
Check if NGINX container is running:
docker compose ps nginx
docker compose logs nginx- Verify you're using HTTPS (not HTTP)
- Check browser console for errors
- Ensure the certificate is trusted on the device
- Try in an incognito/private window
For self-signed certificates:
./scripts/generate-ssl-cert.sh your-hostname.local --auto-ip
./opentr.sh restart-allFor Let's Encrypt:
sudo certbot renew
docker compose restart nginxTo customize the NGINX configuration:
- Edit
nginx/site.conf.template - Restart NGINX:
docker compose restart nginx
Common customizations:
- Add HTTP Basic Authentication for Flower/MinIO
- Adjust client body size limits
- Add custom headers
- Configure rate limiting
Example: Adding Basic Auth for Flower
location /flower/ {
proxy_pass http://flower:5555/flower/;
auth_basic "Flower Dashboard";
auth_basic_user_file /etc/nginx/.htpasswd;
}- Suitable for: Homelab, internal networks, development
- Not suitable for: Public-facing production deployments
- Warning: Users will see browser security warnings until they trust the certificate
- Suitable for: Production deployments with public domains
- Benefits: Free, automatically trusted by all browsers
- Requirement: Domain must be publicly accessible for validation
- Keep private keys secure (never commit to git)
- Use strong key sizes (2048-bit minimum, 4096-bit recommended)
- Renew certificates before expiration
- Monitor certificate expiration dates