I was QA-testing Ferron 3, and here is the (rough) configuration for Jitsi Meet:
# Ferron 3 configuration for Jitsi Meet
# Migrated from NGINX configuration
# Global configuration
{
log /var/log/ferron/access.log {
access_log_rotate_size 10485760
access_log_rotate_keep 7
}
error_log /var/log/ferron/error.log {
error_log_rotate_size 10485760
error_log_rotate_keep 7
}
}
# HTTP host block
kubuntu.home {
# Map for prosody node selection based on vnode query parameter
map request.uri.query.vnode prosody_node {
default "http://127.0.0.1:5280"
}
# Use manual TLS with existing certificates
tls {
provider manual
cert "/etc/jitsi/meet/kubuntu.home.crt"
key "/etc/jitsi/meet/kubuntu.home.key"
}
# Document root for static files
root /usr/share/jitsi-meet
# Enable compression
compressed
#dynamic_compressed
# Custom MIME types
mime_type ".wasm" "application/wasm"
mime_type ".wav" "audio/wav"
# Index files
index index.html index.htm
# Allow symlinks (needed for config.js and external_api.js)
disable_symlinks false
# Custom error page
error_page 404 /static/404.html
# Security headers
header Strict-Transport-Security "max-age=63072000" always
# CORS headers for static content
header +Access-Control-Allow-Origin "*"
# API endpoint for room info
location /_api/room-info {
proxy "http://127.0.0.1:5280/room-info" {
request_header Host "{{request.host}}"
request_header X-Forwarded-For "{{remote.ip}}"
}
}
# BOSH endpoint
location /http-bind {
proxy "http://127.0.0.1:5280/http-bind" {
request_header Host "{{request.host}}"
request_header X-Forwarded-For "{{remote.ip}}"
request_header Connection ""
}
}
# XMPP WebSocket endpoint
location /xmpp-websocket {
proxy "http://127.0.0.1:5280/xmpp-websocket" {
request_header Host "{{request.host}}"
request_header X-Forwarded-For "{{remote.ip}}"
request_header Upgrade "{{request.header.upgrade}}"
request_header Connection "upgrade"
}
}
# Conference request endpoint
location /conference-request/v1 {
proxy "http://127.0.0.1:8888/conference-request/v1"
}
# Tenant/subdomain support - rewrite rules
# Config.js for tenants
rewrite "^/([^/?&:'\"]+)/config.js$" "/config.js" {
last
}
# BOSH for tenants
rewrite "^/([^/?&:'\"]+)/http-bind$" "/http-bind" {
last
}
# XMPP WebSocket for tenants
rewrite "^/([^/?&:'\"]+)/xmpp-websocket$" "/xmpp-websocket" {
last
}
# Room info API for tenants
rewrite "^/([^/?&:'\"]+)/_api/room-info$" "/_api/room-info" {
last
}
# PWA worker and manifest for tenants
rewrite "^/([^/?&:'\"]+)/(pwa-worker.js|manifest.json)$" "/$2" {
last
}
# Conference request for tenants
rewrite "^/([^/?&:'\"]+)/conference-request/v1(.*)$" "/conference-request/v1$2" {
last
}
# Room names (single-segment paths) - serve index.html when no real file matches
rewrite "^/([^/?&:'\"]+)$" "/" {
last
file false
}
# Catch-all for tenant paths - only apply when URL does NOT correspond to a real file
rewrite "^/([^/?&:'\"]+)/(.*)$" "/$2" {
last
file false
}
}
Note: Ferron 3 doesn’t support SSI, but the stock Jitsi frontend uses SSI. You may need to convert the frontend to “compile” SSI directives. This is what I used:
var ssi = require("ssi");
// Define input and output directories
var inputDirectory = "./jitsi-meet.bak";
var outputDirectory = "./jitsi-meet.fix";
// Match files to process (e.g., all .shtml files)
var matcher = "/**/*.html";
var includes = new ssi(inputDirectory, outputDirectory, matcher);
// Compile all matches
includes.compile();
And then copy the compiled HTML files in place of original HTML + SSI files.