jitsi changed
This commit is contained in:
85
README.md
Normal file
85
README.md
Normal file
@@ -0,0 +1,85 @@
|
||||
# PoliticTalk Jitsi Setup
|
||||
|
||||
This folder is the local source of truth for the PoliticTalk Jitsi setup used by:
|
||||
|
||||
```text
|
||||
https://politictalk.parallelglobe.io
|
||||
```
|
||||
|
||||
The VPS still runs the actual Jitsi services. Changes should be made here first, committed to Git, pulled on the VPS, then deployed into the system Jitsi paths with the deploy script.
|
||||
|
||||
## Structure
|
||||
|
||||
```text
|
||||
jitsi/
|
||||
config/
|
||||
politictalk.parallelglobe.io-config.js
|
||||
assets/
|
||||
public/politictalk/
|
||||
branding.json
|
||||
pgLogo.svg
|
||||
nginx/
|
||||
politictalk.parallelglobe.io.conf
|
||||
scripts/
|
||||
deploy-vps.sh
|
||||
templates/
|
||||
```
|
||||
|
||||
## Current Meeting Policy
|
||||
|
||||
- Meetings start in audio-only mode.
|
||||
- Participants join with microphone muted.
|
||||
- Participants join with camera off.
|
||||
- Camera/prejoin camera controls are hidden.
|
||||
- Toolbar is limited to microphone, chat, raise hand, fullscreen, noise suppression, participants pane, and hangup.
|
||||
- Chat and polls are enabled.
|
||||
- Invite/share controls are disabled.
|
||||
- Room names are not stored in recent rooms.
|
||||
- E2EE support is enabled in the Jitsi config.
|
||||
- The logo and dynamic branding point to PoliticTalk public assets.
|
||||
|
||||
## VPS Paths
|
||||
|
||||
The deploy script copies local files into these VPS paths:
|
||||
|
||||
```text
|
||||
jitsi/config/politictalk.parallelglobe.io-config.js
|
||||
-> /etc/jitsi/meet/politictalk.parallelglobe.io-config.js
|
||||
|
||||
jitsi/assets/public/politictalk/*
|
||||
-> /etc/jitsi/meet/public/politictalk/
|
||||
|
||||
jitsi/nginx/politictalk.parallelglobe.io.conf
|
||||
-> /etc/nginx/sites-available/politictalk.parallelglobe.io.conf
|
||||
```
|
||||
|
||||
By default, the deploy script does not replace nginx config unless `DEPLOY_NGINX=1` is set.
|
||||
|
||||
## Deploy On VPS
|
||||
|
||||
After pulling the latest repo changes on the VPS:
|
||||
|
||||
```bash
|
||||
cd /path/to/pg/jitsi
|
||||
sudo ./scripts/deploy-vps.sh
|
||||
```
|
||||
|
||||
To also deploy the nginx vhost:
|
||||
|
||||
```bash
|
||||
cd /path/to/pg/jitsi
|
||||
sudo DEPLOY_NGINX=1 ./scripts/deploy-vps.sh
|
||||
```
|
||||
|
||||
For current `config.js`, branding, and asset changes, an nginx reload is enough. Future JWT/auth changes may require restarting Prosody and Jicofo.
|
||||
|
||||
## Future Auth Work
|
||||
|
||||
The future authenticated flow should be:
|
||||
|
||||
```text
|
||||
PgPlatform -> PgApi verifies event/user -> PgApi creates short-lived Jitsi JWT
|
||||
-> PgPlatform prejoin/iframe -> Jitsi validates JWT on VPS
|
||||
```
|
||||
|
||||
Do not commit real secrets here. JWT secrets, Prosody passwords, and private keys should stay in VPS-only environment/config files.
|
||||
16
assets/public/politictalk/branding.json
Normal file
16
assets/public/politictalk/branding.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"inviteDomain": "politictalk.parallelglobe.io",
|
||||
"backgroundColor": "#101820",
|
||||
"logoClickUrl": "https://parallelglobe.io/",
|
||||
"logoImageUrl": "/_api/public/politictalk/pgLogo.svg",
|
||||
"premeetingBackground": "url(/_api/public/politictalk/pg_bg.png)",
|
||||
"customTheme": {
|
||||
"palette": {
|
||||
"ui01": "#101820",
|
||||
"ui02": "#172432",
|
||||
"surface02": "#1D2C3A",
|
||||
"action01": "#2F80ED",
|
||||
"action01Hover": "#1C6DD0"
|
||||
}
|
||||
}
|
||||
}
|
||||
2319
assets/public/politictalk/pgLogo.svg
Normal file
2319
assets/public/politictalk/pgLogo.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 641 KiB |
BIN
assets/public/politictalk/pg_bg.png
Normal file
BIN
assets/public/politictalk/pg_bg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 255 KiB |
1937
config/politictalk.parallelglobe.io-config.js
Normal file
1937
config/politictalk.parallelglobe.io-config.js
Normal file
File diff suppressed because it is too large
Load Diff
244
nginx/politictalk.parallelglobe.io.conf
Normal file
244
nginx/politictalk.parallelglobe.io.conf
Normal file
@@ -0,0 +1,244 @@
|
||||
server_names_hash_bucket_size 64;
|
||||
|
||||
types {
|
||||
# nginx's default mime.types doesn't include a mapping for wasm or wav.
|
||||
application/wasm wasm;
|
||||
audio/wav wav;
|
||||
}
|
||||
upstream prosody {
|
||||
zone upstreams 64K;
|
||||
server 127.0.0.1:5280;
|
||||
keepalive 2;
|
||||
}
|
||||
upstream jvb1 {
|
||||
zone upstreams 64K;
|
||||
server 127.0.0.1:9090;
|
||||
keepalive 2;
|
||||
}
|
||||
map $arg_vnode $prosody_node {
|
||||
default prosody;
|
||||
v1 v1;
|
||||
v2 v2;
|
||||
v3 v3;
|
||||
v4 v4;
|
||||
v5 v5;
|
||||
v6 v6;
|
||||
v7 v7;
|
||||
v8 v8;
|
||||
}
|
||||
# Matches any URI or Referer with some matches and redacts the whole
|
||||
# query string. log_format and map must be at the http context level.
|
||||
map $request_uri $loggable_uri {
|
||||
~^(?P<path>[^?]*)\?.*(?:jwt|token)= "${path}?[params_redacted]";
|
||||
default $request_uri;
|
||||
}
|
||||
|
||||
map $http_referer $loggable_referer {
|
||||
~^(?P<url>[^?]*)\?.*(?:jwt|token)= "${url}?[params_redacted]";
|
||||
default $http_referer;
|
||||
}
|
||||
|
||||
log_format jitsi_log '$remote_addr - $remote_user [$time_local] '
|
||||
'"$request_method $loggable_uri $server_protocol" '
|
||||
'$status $body_bytes_sent "$loggable_referer" "$http_user_agent"';
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name politictalk.parallelglobe.io;
|
||||
|
||||
location ^~ /.well-known/acme-challenge/ {
|
||||
default_type "text/plain";
|
||||
root /usr/share/jitsi-meet;
|
||||
}
|
||||
location = /.well-known/acme-challenge/ {
|
||||
return 404;
|
||||
}
|
||||
location / {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
}
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
server_name politictalk.parallelglobe.io;
|
||||
|
||||
# Mozilla Guideline v5.4, nginx 1.17.7, OpenSSL 1.1.1d, intermediate configuration
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
|
||||
ssl_prefer_server_ciphers off;
|
||||
|
||||
ssl_session_timeout 1d;
|
||||
ssl_session_cache shared:SSL:10m; # about 40000 sessions
|
||||
ssl_session_tickets off;
|
||||
|
||||
add_header Strict-Transport-Security "max-age=63072000" always;
|
||||
set $prefix "";
|
||||
set $custom_index "";
|
||||
set $config_js_location /etc/jitsi/meet/politictalk.parallelglobe.io-config.js;
|
||||
|
||||
ssl_certificate /etc/jitsi/meet/politictalk.parallelglobe.io.crt;
|
||||
ssl_certificate_key /etc/jitsi/meet/politictalk.parallelglobe.io.key;
|
||||
|
||||
root /usr/share/jitsi-meet;
|
||||
|
||||
access_log /var/log/nginx/access.log jitsi_log;
|
||||
|
||||
# ssi on with javascript for multidomain variables in config.js
|
||||
ssi on;
|
||||
ssi_types application/x-javascript application/javascript;
|
||||
|
||||
index index.html index.htm;
|
||||
error_page 404 /static/404.html;
|
||||
|
||||
gzip on;
|
||||
gzip_types text/plain text/css application/javascript application/json image/x-icon application/octet-stream application/wasm;
|
||||
gzip_vary on;
|
||||
gzip_proxied no-cache no-store private expired auth;
|
||||
gzip_min_length 512;
|
||||
|
||||
include /etc/jitsi/meet/jaas/*.conf;
|
||||
|
||||
location = /config.js {
|
||||
alias $config_js_location;
|
||||
}
|
||||
|
||||
location = /external_api.js {
|
||||
alias /usr/share/jitsi-meet/libs/external_api.min.js;
|
||||
}
|
||||
|
||||
location = /_api/room-info {
|
||||
proxy_pass http://prosody/room-info?prefix=$prefix&$args;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
proxy_set_header Host $http_host;
|
||||
}
|
||||
|
||||
location ~ ^/_api/public/(.*)$ {
|
||||
autoindex off;
|
||||
alias /etc/jitsi/meet/public/$1;
|
||||
}
|
||||
|
||||
# ensure all static content can always be found first
|
||||
location ~ ^/(libs|css|static|images|fonts|lang|sounds|.well-known)/(.*)$
|
||||
{
|
||||
add_header 'Access-Control-Allow-Origin' '*';
|
||||
alias /usr/share/jitsi-meet/$1/$2;
|
||||
|
||||
# cache all versioned files
|
||||
if ($arg_v) {
|
||||
expires 1y;
|
||||
}
|
||||
}
|
||||
|
||||
# BOSH
|
||||
location = /http-bind {
|
||||
proxy_pass http://$prosody_node/http-bind?prefix=$prefix&$args;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header Connection "";
|
||||
}
|
||||
|
||||
# xmpp websockets
|
||||
location = /xmpp-websocket {
|
||||
proxy_pass http://$prosody_node/xmpp-websocket?prefix=$prefix&$args;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $http_host;
|
||||
tcp_nodelay on;
|
||||
}
|
||||
|
||||
# colibri (JVB) websockets for jvb1
|
||||
location ~ ^/colibri-ws/default-id/(.*) {
|
||||
proxy_pass http://jvb1/colibri-ws/default-id/$1$is_args$args;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
tcp_nodelay on;
|
||||
}
|
||||
|
||||
# load test minimal client, uncomment when used
|
||||
#location ~ ^/_load-test/([^/?&:'"]+)$ {
|
||||
# rewrite ^/_load-test/(.*)$ /load-test/index.html break;
|
||||
#}
|
||||
#location ~ ^/_load-test/libs/(.*)$ {
|
||||
# add_header 'Access-Control-Allow-Origin' '*';
|
||||
# alias /usr/share/jitsi-meet/load-test/libs/$1;
|
||||
#}
|
||||
|
||||
location = /_unlock {
|
||||
add_header 'Access-Control-Allow-Origin' '*';
|
||||
add_header Strict-Transport-Security 'max-age=63072000; includeSubDomains';
|
||||
add_header "Cache-Control" "no-cache, no-store";
|
||||
}
|
||||
|
||||
location ~ ^/conference-request/v1(\/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:8888/conference-request/v1$1;
|
||||
add_header "Cache-Control" "no-cache, no-store";
|
||||
add_header 'Access-Control-Allow-Origin' '*';
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Content-Type';
|
||||
}
|
||||
location ~ ^/([^/?&:'"]+)/conference-request/v1(\/.*)?$ {
|
||||
rewrite ^/([^/?&:'"]+)/conference-request/v1(\/.*)?$ /conference-request/v1$2;
|
||||
}
|
||||
|
||||
location ~ ^/([^/?&:'"]+)$ {
|
||||
set $roomname "$1";
|
||||
try_files $uri @root_path;
|
||||
}
|
||||
|
||||
location @root_path {
|
||||
rewrite ^/(.*)$ /$custom_index break;
|
||||
}
|
||||
|
||||
location ~ ^/([^/?&:'"]+)/config.js$
|
||||
{
|
||||
set $subdomain "$1.";
|
||||
set $subdir "$1/";
|
||||
|
||||
alias $config_js_location;
|
||||
}
|
||||
|
||||
# Matches /(TENANT)/pwa-worker.js or /(TENANT)/manifest.json to rewrite to / and look for file
|
||||
location ~ ^/([^/?&:'"]+)/(pwa-worker.js|manifest.json)$ {
|
||||
set $subdomain "$1.";
|
||||
set $subdir "$1/";
|
||||
rewrite ^/([^/?&:'"]+)/(pwa-worker.js|manifest.json)$ /$2;
|
||||
}
|
||||
|
||||
# BOSH for subdomains
|
||||
location ~ ^/([^/?&:'"]+)/http-bind {
|
||||
set $subdomain "$1.";
|
||||
set $subdir "$1/";
|
||||
set $prefix "$1";
|
||||
|
||||
rewrite ^/(.*)$ /http-bind;
|
||||
}
|
||||
|
||||
# websockets for subdomains
|
||||
location ~ ^/([^/?&:'"]+)/xmpp-websocket {
|
||||
set $subdomain "$1.";
|
||||
set $subdir "$1/";
|
||||
set $prefix "$1";
|
||||
|
||||
rewrite ^/(.*)$ /xmpp-websocket;
|
||||
}
|
||||
|
||||
location ~ ^/([^/?&:'"]+)/_api/room-info {
|
||||
set $subdomain "$1.";
|
||||
set $subdir "$1/";
|
||||
set $prefix "$1";
|
||||
|
||||
rewrite ^/(.*)$ /_api/room-info;
|
||||
}
|
||||
|
||||
# Anything that didn't match above, and isn't a real file, assume it's a room name and redirect to /
|
||||
location ~ ^/([^/?&:'"]+)/(.*)$ {
|
||||
set $subdomain "$1.";
|
||||
set $subdir "$1/";
|
||||
rewrite ^/([^/?&:'"]+)/(.*)$ /$2;
|
||||
}
|
||||
}
|
||||
67
scripts/deploy-vps.sh
Executable file
67
scripts/deploy-vps.sh
Executable file
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
DOMAIN="${DOMAIN:-politictalk.parallelglobe.io}"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
JITSI_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
BACKUP_ROOT="${BACKUP_ROOT:-/root/jitsi-backups}"
|
||||
STAMP="$(date +%Y%m%d-%H%M%S)"
|
||||
BACKUP_DIR="$BACKUP_ROOT/$STAMP"
|
||||
|
||||
CONFIG_SRC="$JITSI_DIR/config/$DOMAIN-config.js"
|
||||
ASSETS_SRC="$JITSI_DIR/assets/public/politictalk"
|
||||
NGINX_SRC="$JITSI_DIR/nginx/$DOMAIN.conf"
|
||||
|
||||
CONFIG_DEST="/etc/jitsi/meet/$DOMAIN-config.js"
|
||||
ASSETS_DEST="/etc/jitsi/meet/public/politictalk"
|
||||
NGINX_DEST="/etc/nginx/sites-available/$DOMAIN.conf"
|
||||
|
||||
if [[ "$(id -u)" -ne 0 ]]; then
|
||||
echo "Run this script with sudo on the VPS."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$CONFIG_SRC" ]]; then
|
||||
echo "Missing config source: $CONFIG_SRC"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -d "$ASSETS_SRC" ]]; then
|
||||
echo "Missing assets source: $ASSETS_SRC"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
install -d -m 0755 "$BACKUP_DIR"
|
||||
|
||||
if [[ -f "$CONFIG_DEST" ]]; then
|
||||
cp -a "$CONFIG_DEST" "$BACKUP_DIR/"
|
||||
fi
|
||||
|
||||
if [[ -d "$ASSETS_DEST" ]]; then
|
||||
install -d -m 0755 "$BACKUP_DIR/public"
|
||||
cp -a "$ASSETS_DEST" "$BACKUP_DIR/public/"
|
||||
fi
|
||||
|
||||
if [[ "${DEPLOY_NGINX:-0}" == "1" && -f "$NGINX_DEST" ]]; then
|
||||
cp -a "$NGINX_DEST" "$BACKUP_DIR/"
|
||||
fi
|
||||
|
||||
install -d -m 0755 "$ASSETS_DEST"
|
||||
install -m 0644 "$CONFIG_SRC" "$CONFIG_DEST"
|
||||
find "$ASSETS_SRC" -maxdepth 1 -type f -print0 | while IFS= read -r -d '' file; do
|
||||
install -m 0644 "$file" "$ASSETS_DEST/"
|
||||
done
|
||||
|
||||
if [[ "${DEPLOY_NGINX:-0}" == "1" ]]; then
|
||||
if [[ ! -f "$NGINX_SRC" ]]; then
|
||||
echo "Missing nginx source: $NGINX_SRC"
|
||||
exit 1
|
||||
fi
|
||||
install -m 0644 "$NGINX_SRC" "$NGINX_DEST"
|
||||
nginx -t
|
||||
fi
|
||||
|
||||
systemctl reload nginx
|
||||
|
||||
echo "Deployed PoliticTalk Jitsi files."
|
||||
echo "Backup: $BACKUP_DIR"
|
||||
33
templates/auth-roadmap.md
Normal file
33
templates/auth-roadmap.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# PoliticTalk Jitsi Auth Roadmap
|
||||
|
||||
These notes are intentionally not deployed yet. They describe the local files and app changes we should add when we connect PgApi authentication to Jitsi.
|
||||
|
||||
## Target Flow
|
||||
|
||||
```text
|
||||
PgPlatform calendar event
|
||||
-> PgPlatform PoliticTalk prejoin page
|
||||
-> PgApi verifies logged-in user, event ownership/invite/access, and event time window
|
||||
-> PgApi returns a short-lived Jitsi JWT
|
||||
-> PgPlatform embeds or opens Jitsi with that JWT
|
||||
-> Jitsi VPS validates JWT through Prosody token auth
|
||||
```
|
||||
|
||||
## Local Files To Add Later
|
||||
|
||||
```text
|
||||
jitsi/templates/prosody-token-auth.cfg.lua.example
|
||||
jitsi/templates/jicofo-token-auth.conf.example
|
||||
jitsi/templates/jitsi-token-auth.env.example
|
||||
```
|
||||
|
||||
Only templates should be committed. Real JWT secrets must stay in VPS-only files.
|
||||
|
||||
## Platform Changes To Add Later
|
||||
|
||||
- PgApi endpoint to issue Jitsi JWTs for valid PoliticTalk event access.
|
||||
- JWT claims for room, user display name, email/id, moderator flag, expiry, and feature permissions.
|
||||
- PgPlatform prejoin route that shows event title and immutable platform user name.
|
||||
- PgPlatform embedded Jitsi room using the IFrame API.
|
||||
- Moderator-only controls for audio moderation and poll permissions.
|
||||
- Event end-time enforcement through JWT expiry and/or iframe hangup.
|
||||
8
templates/deploy.env.example
Normal file
8
templates/deploy.env.example
Normal file
@@ -0,0 +1,8 @@
|
||||
# Optional variables for jitsi/scripts/deploy-vps.sh.
|
||||
# Copy this to a VPS-only location if needed. Do not commit real secrets.
|
||||
|
||||
DOMAIN=politictalk.parallelglobe.io
|
||||
BACKUP_ROOT=/root/jitsi-backups
|
||||
|
||||
# Set to 1 only when intentionally replacing the nginx vhost config.
|
||||
DEPLOY_NGINX=0
|
||||
Reference in New Issue
Block a user