Kokkoja: first public assembly
Assembled from the development repository by tools/make_release.sh. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
commit
95c80d04c9
39 files changed
+9905
No files matched your search
@@ -0,0 +1,69 @@
|
||||
# The Kokkoja server
|
||||
|
||||
A Kokkoja *server* is one machine that does two things for a group of
|
||||
users: it runs the relay, which passes the participants' encrypted
|
||||
messages, and it serves the client as a web site, so that a guest can
|
||||
join by opening a link with nothing installed. Neither stores anything.
|
||||
The first one is Andy's VPS at `kokkoja.andykopra.com`.
|
||||
|
||||
| On the server | What it is |
|
||||
|----------------------------|-------------------------------------------------|
|
||||
| `/opt/kokkoja/relay/` | the relay's code (`relay/` in this repository) |
|
||||
| `/opt/kokkoja/venv/` | Python with the `websockets` library |
|
||||
| `/var/www/kokkoja/` | the client (`client/`) and its `config.json` |
|
||||
| `kokkoja-relay.service` | the relay, run as the system user `kokkoja`, on 127.0.0.1:8770 |
|
||||
| nginx site `kokkoja` | `https://<site>/` serves the client; `wss://<site>/relay` reaches the relay |
|
||||
|
||||
The client's `config.json` on the site says
|
||||
`{"relay": "wss://kokkoja.andykopra.com/relay", "storage": "browser",
|
||||
"site": "https://kokkoja.andykopra.com/"}`: the notebooks of anyone using
|
||||
the site are kept in their browser. A host with the local program uses
|
||||
the server with `python3 kokkoja.py --relay wss://kokkoja.andykopra.com/relay`;
|
||||
the invitation is then a link to the site.
|
||||
|
||||
## Setting up or updating
|
||||
|
||||
From the project directory on a development machine:
|
||||
|
||||
deploy/deploy.sh
|
||||
|
||||
copies the relay, the client and the files in this directory to the
|
||||
server and runs `setup_vps.sh` there, which makes or updates everything
|
||||
in the table and restarts the relay. It can be run again at any time.
|
||||
`KOKKOJA_SERVER` names another ssh destination than
|
||||
`root@vps313847.iceservers.net`.
|
||||
|
||||
Steps a person does, once:
|
||||
|
||||
1. DNS: an A record `kokkoja.andykopra.com` pointing at the VPS
|
||||
(82.221.141.89), in cPanel's Zone Editor, since andykopra.com is on
|
||||
the orangewebsite.com nameservers. Check with
|
||||
`host kokkoja.andykopra.com buffy.ns.orangewebsite.com`.
|
||||
|
||||
2. TLS, after the name resolves and `deploy.sh` has run once:
|
||||
|
||||
ssh root@vps313847.iceservers.net certbot --nginx -d kokkoja.andykopra.com
|
||||
|
||||
certbot adds the TLS listener to the nginx site and turns the plain
|
||||
HTTP block into a redirect. Afterwards `setup_vps.sh` leaves the
|
||||
installed nginx site alone, so a later change to `nginx-site.conf`
|
||||
must be carried over by hand.
|
||||
|
||||
3. The VPS sentinel sees a new service, a new user, a new nginx site and
|
||||
a new listening socket. After deploying, as root on the VPS:
|
||||
|
||||
vps-sentinel --accept
|
||||
|
||||
Checks: `https://kokkoja.andykopra.com/config.json` shows the
|
||||
configuration above; `systemctl status kokkoja-relay` is active;
|
||||
`journalctl -u kokkoja-relay -n 20` shows it listening.
|
||||
|
||||
## Security
|
||||
|
||||
The relay sees only ciphertext and room ids and keeps nothing. It runs
|
||||
as a user of its own under systemd's sandboxing (read-only system, no
|
||||
home directories, no new privileges). The site sends a Content Security
|
||||
Policy that lets the client load nothing from anywhere else and forbids
|
||||
framing. What the site cannot protect against is itself: whoever
|
||||
controls the server could serve a changed client to browser-only
|
||||
guests. Participants running the local program are not exposed to that.
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
# Deploy the Kokkoja server: copy the relay, the client and the server
|
||||
# files to the VPS, then run deploy/setup_vps.sh there. Run from the
|
||||
# project directory on a development machine.
|
||||
#
|
||||
# deploy/deploy.sh
|
||||
#
|
||||
# KOKKOJA_SERVER names the ssh destination (default root@vps313847.iceservers.net).
|
||||
# The site's config.json is written here: the relay and site addresses
|
||||
# below are the server's public names.
|
||||
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")/.."
|
||||
server=${KOKKOJA_SERVER:-root@vps313847.iceservers.net}
|
||||
site=https://kokkoja.andykopra.com/
|
||||
relay=wss://kokkoja.andykopra.com/relay
|
||||
|
||||
staging=$(mktemp -d)
|
||||
trap 'rm -rf "$staging"' EXIT
|
||||
mkdir -p "$staging/relay" "$staging/client" "$staging/deploy"
|
||||
cp relay/kokkoja_relay.py relay/requirements.txt "$staging/relay/"
|
||||
rsync -a --exclude '__pycache__' client/ "$staging/client/"
|
||||
printf '{"relay": "%s", "storage": "browser", "site": "%s"}\n' "$relay" "$site" > "$staging/client/config.json"
|
||||
cp deploy/kokkoja-relay.service deploy/nginx-site.conf deploy/setup_vps.sh "$staging/deploy/"
|
||||
|
||||
ssh "$server" 'mkdir -p /opt/kokkoja/incoming'
|
||||
rsync -a --delete "$staging/" "$server:/opt/kokkoja/incoming/"
|
||||
ssh "$server" 'bash /opt/kokkoja/incoming/deploy/setup_vps.sh'
|
||||
@@ -0,0 +1,29 @@
|
||||
# The Kokkoja relay as a system service. Installed by deploy/setup_vps.sh
|
||||
# as /etc/systemd/system/kokkoja-relay.service.
|
||||
#
|
||||
# The relay listens on this computer only; nginx terminates TLS and
|
||||
# forwards wss://<site>/relay/... to it (deploy/nginx-site.conf).
|
||||
|
||||
[Unit]
|
||||
Description=Kokkoja relay
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
User=kokkoja
|
||||
Group=kokkoja
|
||||
ExecStart=/opt/kokkoja/venv/bin/python /opt/kokkoja/relay/kokkoja_relay.py --host 127.0.0.1 --port 8770
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
# The relay needs nothing on the system but its own code.
|
||||
NoNewPrivileges=yes
|
||||
ProtectSystem=strict
|
||||
ProtectHome=yes
|
||||
PrivateTmp=yes
|
||||
PrivateDevices=yes
|
||||
ProtectKernelTunables=yes
|
||||
ProtectControlGroups=yes
|
||||
RestrictAddressFamilies=AF_INET AF_INET6
|
||||
MemoryDenyWriteExecute=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,39 @@
|
||||
# nginx server block for a Kokkoja web site: the client's files at
|
||||
# https://kokkoja.andykopra.com/ and the relay at wss://kokkoja.andykopra.com/relay.
|
||||
# Installed by deploy/setup_vps.sh as /etc/nginx/sites-available/kokkoja.
|
||||
#
|
||||
# This is the plain HTTP form. certbot --nginx -d kokkoja.andykopra.com
|
||||
# adds the TLS listener and turns this block into a redirect.
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name kokkoja.andykopra.com;
|
||||
|
||||
root /var/www/kokkoja;
|
||||
index index.html;
|
||||
|
||||
# The relay. The client connects to <relay address>/room/<room id>,
|
||||
# so /relay/room/<id> here becomes /room/<id> at the relay.
|
||||
location /relay/ {
|
||||
proxy_pass http://127.0.0.1:8770/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
# The relay pings every 20 seconds; a quiet lesson must not be cut off.
|
||||
proxy_read_timeout 1h;
|
||||
proxy_send_timeout 1h;
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
# The client is a few small files that change with every deployment:
|
||||
# browsers ask whether they have changed rather than keeping old ones.
|
||||
add_header Cache-Control "no-cache" always;
|
||||
# The client loads nothing from anywhere else, and may not be framed.
|
||||
add_header Content-Security-Policy "default-src 'self'; connect-src 'self' wss://kokkoja.andykopra.com; img-src 'self' blob: data:; style-src 'self' 'unsafe-inline'; base-uri 'none'; frame-ancestors 'none'; form-action 'none'" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header Referrer-Policy "no-referrer" always;
|
||||
}
|
||||
Executable
+63
@@ -0,0 +1,63 @@
|
||||
#!/bin/bash
|
||||
# Set up, or bring up to date, the Kokkoja server on this machine. Run as
|
||||
# root ON THE SERVER, after deploy/deploy.sh has copied the files to
|
||||
# /opt/kokkoja/incoming. Safe to run again: every step checks first.
|
||||
#
|
||||
# What it makes:
|
||||
# /opt/kokkoja/relay/ the relay's code
|
||||
# /opt/kokkoja/venv/ Python with the websockets library
|
||||
# /var/www/kokkoja/ the client, with config.json
|
||||
# kokkoja-relay.service the relay, as the system user "kokkoja"
|
||||
# nginx site "kokkoja" the web site and the relay behind TLS
|
||||
#
|
||||
# TLS is the one step left to a person, once the name resolves to this
|
||||
# machine (see deploy/README.md):
|
||||
# certbot --nginx -d kokkoja.andykopra.com
|
||||
|
||||
set -euo pipefail
|
||||
incoming=/opt/kokkoja/incoming
|
||||
test -d "$incoming" || { echo "nothing in $incoming: run deploy/deploy.sh first" >&2; exit 1; }
|
||||
|
||||
if ! id kokkoja >/dev/null 2>&1; then
|
||||
useradd --system --no-create-home --shell /usr/sbin/nologin kokkoja
|
||||
fi
|
||||
|
||||
# Python with the websockets library, in a virtual environment of its own.
|
||||
if ! python3 -c 'import ensurepip' >/dev/null 2>&1; then
|
||||
apt-get install -y python3-venv
|
||||
fi
|
||||
if [ ! -x /opt/kokkoja/venv/bin/python ]; then
|
||||
python3 -m venv /opt/kokkoja/venv
|
||||
fi
|
||||
/opt/kokkoja/venv/bin/pip install --quiet --upgrade pip
|
||||
/opt/kokkoja/venv/bin/pip install --quiet -r "$incoming/relay/requirements.txt"
|
||||
|
||||
# The relay's code, and the client.
|
||||
rm -rf /opt/kokkoja/relay
|
||||
cp -r "$incoming/relay" /opt/kokkoja/relay
|
||||
chmod -R a+rX /opt/kokkoja/relay
|
||||
mkdir -p /var/www/kokkoja
|
||||
rsync -a --delete "$incoming/client/" /var/www/kokkoja/
|
||||
chmod -R a+rX /var/www/kokkoja
|
||||
|
||||
# The service.
|
||||
install -m 644 "$incoming/deploy/kokkoja-relay.service" /etc/systemd/system/kokkoja-relay.service
|
||||
systemctl daemon-reload
|
||||
systemctl enable --quiet kokkoja-relay.service
|
||||
systemctl restart kokkoja-relay.service
|
||||
|
||||
# The nginx site. Once certbot has edited the installed copy, it is not
|
||||
# replaced: certbot's additions would be lost.
|
||||
if [ ! -e /etc/nginx/sites-available/kokkoja ]; then
|
||||
install -m 644 "$incoming/deploy/nginx-site.conf" /etc/nginx/sites-available/kokkoja
|
||||
elif ! grep -q "managed by Certbot" /etc/nginx/sites-available/kokkoja; then
|
||||
install -m 644 "$incoming/deploy/nginx-site.conf" /etc/nginx/sites-available/kokkoja
|
||||
else
|
||||
echo "nginx site left as certbot made it; compare with deploy/nginx-site.conf by hand"
|
||||
fi
|
||||
ln -sf ../sites-available/kokkoja /etc/nginx/sites-enabled/kokkoja
|
||||
nginx -t
|
||||
systemctl reload nginx
|
||||
|
||||
systemctl --no-pager --lines=3 status kokkoja-relay.service || true
|
||||
echo "Kokkoja server is set up."
|
||||
Reference in new issue
Block a user