Documentation rework.

This commit is contained in:
Juliusz Chroboczek
2025-08-13 15:41:56 +02:00
parent 5bbfd287e5
commit 22af4567e9
8 changed files with 986 additions and 699 deletions
-291
View File
@@ -1,291 +0,0 @@
# Installation instructions
## Build the `galene` binary
Do:
CGO_ENABLED=0 go build -ldflags='-s -w'
On Windows, do
set CGO_ENABLED=0
go build -ldflags="-s -w"
## Set up a group
Set up a group called *test* by creating a file `groups/test.json`:
mkdir groups
vi groups/test.json
You may use the following definition:
{
"users":{
"admin": {"password": "1234", "permissions": "op"}
},
"wildcard-user": {
"password": {"type": "wildcard"},
"permissions": "present"
}
}
See the README file for more details about defining groups.
## Optional: install libraries for background blur
Galene's client uses Google's MediaPipe library to implement background
blur. This library is optional, and if it is absent, Galene will
disable the menu entries for background blur.
Optionally install Google's MediaPipe library:
```
mkdir mediapipe
cd mediapipe
npm pack @mediapipe/tasks-vision
tar xzf mediapipe-tasks-vision-*.tgz
rm -f ../static/third-party/tasks-vision
mv package ../static/third-party/tasks-vision
cd ../static/third-party/tasks-vision
mkdir models
cd models
wget https://storage.googleapis.com/mediapipe-models/image_segmenter/selfie_segmenter/float16/latest/selfie_segmenter.tflite
cd ../../../../
```
## Test locally
./galene &
You should be able to access Galène at `https://localhost:8443`. Connect
to the group that you have just set up in two distinct browser windows,
then press *Ready* in one of the two; you should see a video in the other.
## Configure your server's firewall
If your server has a global IPv4 address and there is no firewall, there
is nothing to do.
If your server has a global IPv4 address, then the firewall must allow
traffic to and from:
* TCP port 8443 (or whatever is configured with the `-http` option); and
* TCP and UDP port 1194 (or whatever is configured with the `-turn` option).
For good performance, your firewall should allow incoming and outgoing
traffic from the UDP ports used for media transfer. By default, these are
all high-numbered (ephemeral) ports, but they can be restricted using one
of the following options:
* the `-udp-range port1-port2` option restricts the UDP ports to be in
the range from port1 to port2 inclusive; this should be a large range,
on the order of a few tens of thousands of ports;
* the `-udp-range port` option makes the server use just a single port,
and demultiplex the traffic in userspace.
If your server is behind NAT (which is not recommended), then the NAT must
forward, at the very least, port 8443 to your server. Ideally, you should
configure an external TURN server (see *ICE Servers* below) on a host that
is not behind NAT. If that is not possible, then you must use a NAT that
supports hairpinning, you must forward port 1194 in addition to port 8443,
and you will need to add add the option `-turn 203.0.113.1:1194` to
Galène's command line, where `203.0.113.1` is your NAT's external (global)
IPv4 address.
## Cross-compile for your server
This step is only required if your server runs a different OS or has
a different CPU than your build machine.
For a Linux server with an Intel or AMD CPU:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags='-s -w'
For a Raspberry Pi 1:
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=6 go build -ldflags='-s -w'
For a BeagleBone or a Raspberry Pi 2 or later:
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build -ldflags='-s -w'
For a 64-bit ARM board (Olimex Olinuxino-A64, Pine64, etc.) or server:
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags='-s -w'
For a 32-bit MIPS board with no hardware floating point (WNDR3800, etc.):
CGO_ENABLED=0 GOOS=linux GOARCH=mips GOMIPS=softfloat go build -ldflags='-s -w'
## Deploy to your server
Set up a user *galene* on your server, then copy the `galene` binary, and
the directories `static`, `data` and `groups`:
rsync -a galene static data groups galene@server.example.org:
If you don't have a TLS certificate, Galène will generate a self-signed
certificate automatically (and print a warning to the logs). If you have
a certificate, install it in the files `data/cert.pem` and `data/key.pem`:
ssh galene@server.example.org
sudo cp /etc/letsencrypt/live/server.example.org/fullchain.pem data/cert.pem
sudo cp /etc/letsencrypt/live/server.example.org/privkey.pem data/key.pem
sudo chown galene:galene data/*.pem
sudo chmod go-rw data/key.pem
Now arrange to run the binary on the server. If you never reboot your
server, it might be as simple as
ssh galene@server.example.org
ulimit -n 65536
nohup ./galene &
If you are using *runit*, use a script like the following:
#!/bin/sh
exec 2>&1
cd ~galene
ulimit -n 65536
exec setuidgid galene ./galene
If you are using *systemd*:
[Unit]
Description=Galene
After=network.target
[Service]
Type=simple
WorkingDirectory=/home/galene
User=galene
Group=galene
ExecStart=/home/galene/galene
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
# Running behind a reverse proxy
Galene is designed to be directly exposed to the Internet. In order to
run Galene behind a reverse proxy, you might need to make a number of
tweaks to your configuration.
First, you might need to inform Galene of the URL at which users connect
(the reverse proxy's URL) by adding an entry `proxyURL` to your
`data/config.json` file:
{
"proxyURL": "https://galene.example.org/"
}
Second, and depending on your proxy implementation, you might need to
request that the proxy pass WebSocket handshakes to the URL at `ws`; for
example, with Nginx, you will need to say something like the following:
location /ws {
proxy_pass ...;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
Finally, in order to avoid TLS termination issues, you may want to run
Galene over plain HTTP instead of HTTPS by using the command-line flag
`-insecure`.
Note that even if you're using a reverse proxy, clients will attempt to
establish direct UDP flows with Galene and direct TCP connections to
Galene's TURN server; see the section on "Configuring your firewall"
above.
# Connectivity issues and ICE Servers
Most connectivity issues are due to an incorrect ICE configuration.
ICE is the NAT and firewall traversal protocol used by WebRTC. ICE can
make use of two kinds of servers to help with NAT traversal: STUN servers,
that help punching holes in well-behaved NATs, and TURN servers, that
serve as relays for traffic. TURN is a superset of STUN: no STUN server
is necessary if one or more TURN servers are available.
Galène includes an IPv4-only TURN server, which is controlled by the
`-turn` command-line option. It has the following behaviour:
* if its value is set to the empty string `""`, then the built-in server
is disabled; in this case, the file `data/ice-servers.json` configures
an external TURN server;
* if its value is a colon followed with a port number, for example
`:1194`, then the TURN server will listen on all public IPv4 addresses
of the local host, over UDP and TCP; this is the recommended value if
the server is not behind NAT, and the firewall allows incoming
connections to port 1194;
* if the value of this option is a socket address, such as
`203.0.113.1:1194`, then the TURN server will listen on all addresses
of the local host but assume that the address seen by the clients is
the one given in the option; this is useful when running behind NAT
with port forwarding set up.
* the default value is `auto`, which behaves like `:1194` if there is no
`data/ice-servers.json` file, and like `""` otherwise.
If the server is not accessible from the Internet, e.g. because of NAT or
because it is behind a restrictive firewall, then you should configure
a TURN server that runs on a host that is accessible by both Galène and
the clients. Disable the built-in TURN server (`-turn ""` or the default
`-turn auto`), and provide a working ICE configuration in the file
`data/ice-servers.json`. In the case of a single STUN server, it should
look like this:
[
{
"urls": [
"stun:stun.example.org"
]
}
]
In the case of s single TURN server, the `ice-servers.json` file should
look like this:
[
{
"urls": [
"turn:turn.example.org:443",
"turn:turn.example.org:443?transport=tcp"
],
"username": "galene",
"credential": "secret"
}
]
It is more secure to use coturn's `use-auth-secret` option. If you do
that, then the `ice-servers.json` file should look like this:
[
{
"urls": [
"turn:turn.example.com:443",
"turn:turn.example.com:443?transport=tcp"
],
"username": "galene",
"credential": "secret",
"credentialType": "hmac-sha1"
}
]
For redundancy, you may set up multiple TURN servers, and ICE will use the
first one that works. If an `ice-servers.json` file is present and
Galène's built-in TURN server is enabled, then the external server will be
used in preference to the built-in server.
-408
View File
@@ -1,408 +0,0 @@
Galene is a videoconferencing server that is easy to deploy and requires
moderate server resources. It is described at <https://galene.org>.
# Installation
Quick start:
git clone https://github.com/jech/galene
cd galene
CGO_ENABLED=0 go build -ldflags='-s -w'
mkdir groups
echo '{"users": {"bob": {"password":"1234", "permissions":"op"}}}' > \
groups/example.json
./galene &
Point your browser at <https://localhost:8443/group/example/>, ignore the
unknown certificate warning, and log in with username "bob" and password
"1234".
See the file INSTALL in this directory for full installation instructions.
# Usage
## Locations
There is a landing page at the root of the server. It contains a form
for typing the name of a group, and a clickable list of public groups.
Groups are available under `/group/groupname/`. You may share this URL
with others, there is no need to go through the landing page.
Recordings can be accessed under `/recordings/groupname/`. This is only
available to the group operator.
Some statistics are available under `/stats.json`, with a human-readable
version at `/stats.html`. This is only available to the server administrator.
## Main interface
After logging in, the user is confronted with the main interface.
### Buttons
There are up to three buttons at the top. The *Enable*/*Disable* button
enables either or both the camera and the microphone (depending on the
options set in the side menu, see below). The *Mute* button mutes or
unmutes the microphone. The *Share Screen* button shares the screen or
a window.
### Side menu
There is a menu on the right of the user interface. This allows choosing
the camera and microphone and setting the video throughput. The
*Blackboard mode* checkbox increases resolution and sacrifices framerate
in favour of image quality. The *Play local file* dialog allows streaming
a video from a local file.
### User list
There is a user list on the left. Clicking on a user opens a menu with
actions that can be applied to that user. Clicking on ones own username
opens a menu with actions that are global to the group.
### Chat pane
Double-clicking on a message opens a contextual menu.
### Text box
Typing a string in the text box at the bottom of the chat pane sends
a broadcast message to all of the users in the group.
Typing a line starting with a slash `/` in the text box causes a command
to be sent to the server. Type `/help` to get the list of available
commands; the output depends on whether you are an operator or not.
# The global configuration file
The server may be configured in the JSON file `data/config.json`. This
file may look as follows:
{
"users":{"root": {"password":"secret", "permissions": "admin"}},
"canonicalHost": "galene.example.org"
}
or, better, with a hashed password:
{
"users": {
"root": {
"password":{"type":"bcrypt","key":"$2a$10$bTWW..."},
"permissions": "admin"
}
},
"canonicalHost": "galene.example.org"
}
The fields are as follows:
- `users` defines the users allowed to administer the server, and has the
same syntax as user definitions in groups (see below), except that the
only meaningful permission is `"admin"`;
- `writableGroups`: if true, then the API can modify group description
files; by default, group files are treated as read-only;
- `allowOrigin` is an array that contains the list of HTTP origins that
are allowed to access the server.
- `allowAdminOrigin` is like `allowOrigin`, but applies to the
administrative interface.
- `proxyURL`: if running behind a reverse proxy, this specifies the root
URL that will be visible outside the proxy.
- `canonicalHost`: the canonical name of the host running the server;
this will cause clients to be redirected if they use a different
hostname to access the server.
# Group definitions
Groups are defined by files in the `./groups` directory (this may be
configured by the `-groups` command-line option, try `./galene -help`).
The definition for the group called *groupname* is in the file
`groups/groupname.json`; it does not contain the group name, which makes
it easy to copy or link group definitions. You may use subdirectories:
a file `groups/teaching/networking.json` defines a group called
*teaching/networking*.
## Examples
A typical group definition file looks like this:
{
"users":{
"jch": {"password":"1234", "permissions": "op"}
},
"allow-recording": true,
"auto-subgroups": true
}
This defines a group with the operator username *jch* and password *1234*.
The `allow-recording` entry says that the operator is allowed to record
videos to disk, and the `auto-subgroups` entry says that subgroups will be
created automatically. This particular group does not allow password
login for ordinary users, and is suitable if you use invitations (see
*Stateful Tokens* below) for ordinary users.
In order to allow password login for ordinary users, add password entries
with the permission `present`:
{
"users":{
"jch": {"password": "1234", "permissions": "op"},
"john": {"password": "secret", "permissions": "present"}
}
}
If the group is to be publicly accessible, you may allow logins with any
username using the `wildcard-user` entry::
{
"users":{
"jch": {"password":"1234", "permissions": "op"}
},
"wildcard-user": {"password": "1234", "permissions": "present"},
"public": true
}
If you want to allow users to use any password, use a wildcard password:
{
"users":{
"jch": {"password":"1234", "permissions": "op"}
},
"wildcard-user":
{"password": {"type": "wildcard"}, "permissions": "present"},
"public": true
}
## Reference
Every group definition file contains a single JSON directory (a list of
entries between `{` and `}`). All fields are optional, but unless you
specify at least one user definition (`op`, `presenter`, or `other`),
nobody will be able to join the group. The following fields are allowed:
- `users`: is a dictionary that maps user names to dictionaries with
entries `password` and `permissions`; see below for a description of
possible permissions;
- `wildcard-user` is a dictionaries with entries `password` and `permissions`
that will be used for usernames with no matching entry in the `users`
dictionary;
- `authKeys`, `authServer` and `authPortal`: see *Authorisation* below;
- `public`: if true, then the group is listed on the landing page;
- `displayName`: a human-friendly version of the group name;
- `description`: a human-readable description of the group; this is
displayed on the landing page for public groups;
- `contact`: a human-readable contact for this group, such as an e-mail
address, ignored by the server;
- `comment`: a human-readable string, ignored by the server;
- `max-clients`: the maximum number of clients that may join the group at
a time;
- `max-history-age`: the time, in seconds, during which chat history is
kept (default 14400, i.e. 4 hours);
- `not-before` and `expires`: the times (in ISO 8601 or RFC 3339 format)
between which joining the group is allowed;
- `allow-recording`: if true, then recording is allowed in this group;
- `unrestricted-tokens`: if true, then ordinary users (without the "op"
privilege) are allowed to create tokens;
- `allow-anonymous`: if true, then users may connect with an empty username;
- `auto-subgroups`: if true, then subgroups of the form `group/subgroup`
are automatically created when first accessed;
- `autolock`: if true, the group will start locked and become locked
whenever there are no clients with operator privileges;
- `autokick`: if true, all clients will be kicked out whenever there are
no clients with operator privileges; this is not recommended, prefer
the `autolock` option instead;
- `redirect`: if set, then attempts to join the group will be redirected
to the given URL; most other fields are ignored in this case;
- `codecs`: this is a list of codecs allowed in this group. The default
is `["vp8", "opus"]`.
The value of the `permissions` entry in a user definition can either be an
array of individual permissions, as carried by the protocol, or one of
the following strings:
- `op`, a group operator with all rights except administering the group;
- `present`, an ordinary user with the right to publish audio and video
streams and send chat messages;
- `message`, a user with the right to send chat messages;
- `observe`, a user that receives media streams and chat messages, but
is not allowed to send them;
- `caption`, a user with the right to display captions (only);
- `admin`, a user with the right to administer the group (only).
Supported video codecs include:
- `"vp8"` (compatible with all supported browsers);
- `"vp9"` (better video quality, but incompatible with Safari; buggy in
Firefox);
- `"av1"` (even better video quality, only supported by some browsers,
recording is not supported, SVC is not supported);
- `"h264"` (incompatible with Debian and with some older Android devices,
SVC is not supported).
Supported audio codecs include `"opus"`, `"g722"`, `"pcmu"` and `"pcma"`.
Only Opus can be recorded to disk. There is no good reason to use
anything except Opus.
## Client Authorisation
Galene implements three authorisation methods: a simple username/password
authorisation scheme, a scheme using stateful tokens and a mechanism based
on cryptographic tokens that are generated by an external server. The
former two mechanism are intended to be used in standalone installations,
while the server-based mechanism is designed to allow easy integration
with an existing authorisation infrastructure (such as LDAP, OAuth2, or
even Unix passwords).
### Password authorisation
When password authorisation is used, authorised usernames and password are
defined directly in the group configuration file, in the `users` and
`wildcard-user` entries. The `users` entry is a dictionary that maps user
names to user descriptions; the `wildcard-user` is a user description
that is used with usernames that don't appear in `users`.
Every user description is a dictionary with fields `password` and
`permissions`. The `password` field may be a literal password string, or
a dictionary describing a hashed password or a wildcard. The
`permissions` field should be one of `op`, `present`, `message` or
`observe`. (An array of Galene's internal permissions is also allowed,
but this is not recommended, since internal permissions may vary from
version to version).
For example, the entry
"users": {"jch": {"password": "1234", "permissions": "op"}}
specifies that user "jch" may login as operator with password "1234", while
"wildcard-user": {"password": "1234", "permissions": "present"}
allows any username with password *1234*. Finally,
"wildcard-user":
{"password": {"type": "wildcard"}, "permissions": "present"}
allows any username with any password.
### Hashed passwords
If you don't wish to store cleartext passwords on the server, you may
generate hashed passwords with the `galenectl` utility. A user entry with
a hashed password looks like this:
"users": {
"jch": {
"password": {
"type": "pbkdf2",
"hash": "sha-256",
"key": "f591c35604e6aef572851d9c3543c812566b032b6dc083c81edd15cc24449913",
"salt": "92bff2ace56fe38f",
"iterations": 4096
},
"permissions": "op"
}
}
### Stateful tokens
Stateful tokens allow to temporarily grant access to a user. In order to
generate a stateful token, the group operator types
/invite user period
where `user` is the username granted to the temporary user, and `period`
is the time period for which the token will be valid (for example `2d`
meaning 2 days). The server replies with a link, valid the given time
period, that may be sent to the temporary user for example by e-mail.
Tokens may also be granted without imposing a specific username:
/invite '' 2d
Stateful tokens are revokable (use the `/revoke` command) and their
lifetime may be extended (use the `/reinvite` command).
### Authorisation servers
Galene is able to delegate authorisation decisions to an external
authorisation server. This makes it possible to integrate Galene with an
existing authentication and authorisation infrastructure, such as LDAP,
OAuth2 or even Unix passwords.
When an authorisation server is used, the group configuration file
specifies one or more public keys in JWK format (with the restriction that
the "alg" key must be specified). In addition, it may specify either an
authorisation server or an authorisation portal.
{
"authKeys": [{
"kty": "oct",
"alg": "HS256",
"k": "MYz3IfCq4Yq-UmPdNqWEOdPl4C_m9imHHs9uveDUJGQ",
}, {
"kty": "EC",
"alg": "ES256",
"crv": "P-256",
"x": "dElK9qBNyCpRXdvJsn4GdjrFzScSzpkz_I0JhKbYC88",
"y": "pBhVb37haKvwEoleoW3qxnT4y5bK35_RTP7_RmFKR6Q",
}]
"authServer": "https://auth.example.org",
}
If multiple keys are provided, then they will all be tried in turn, unless
the token includes the "kid" header field, in which case only the
specified key will be used.
If an authorisation server is specified, then the default client, after it
prompts for a password, will request a token from the authorisation server
and will join the group using token authentication. The password is never
communicated to the server.
If an authorisation portal is specified, then the default client will
redirect initial client connections to the authorisation portal. The
authorisation portal is expected to authorise the client and then redirect
it to Galene with the `username` and `token` query parameters set.
# Further information
Galène's web page is at <https://galene.org>.
Answers to common questions and issues are at <https://galene.org/faq.html>.
-- Juliusz Chroboczek <https://www.irif.fr/~jch/>
+45
View File
@@ -0,0 +1,45 @@
# The Galene videoconferencing system
Galene is a fully-features videoconferencing system that is easy to deploy
and requires very moderate server resources. It is described at
<https://galene.org>.
## Quick start
```sh
git clone https://github.com/jech/galene
cd galene
CGO_ENABLED=0 go build -ldflags='-s -w'
mkdir groups
echo '{"users": {"vimes": {"password":"sybil", "permissions":"op"}}}' > groups/night-watch.json
./galene &
```
Point your browser at <https://localhost:8443/group/night-watch/>, ignore
the unknown certificate warning, and log in with username *vimes* and
password *sybil*.
For full installation instructions, please see the file [galene-install.md][1]
in this directory.
## Documentation
* [galene-install.md][1]: full installation instructions
* [galene.md][2]: usage and administration;
* [galene-client.md][3]: writing clients;
* [galene-protocol.md][4]: the client protocol;
* [galene-api.md][4]: Galene's administrative API.
## Further information
Galène's web page is at <https://galene.org>.
Answers to common questions and issues are at <https://galene.org/faq.html>.
-- Juliusz Chroboczek <https://www.irif.fr/~jch/>
[1]: <galene-install.md>
[2]: <galene.md>
[3]: <galene-client.md>
[4]: <galene-protocol.md>
View File
+366
View File
@@ -0,0 +1,366 @@
# Galene installation instructions
## Basic installation
### Build the Galene binary
Say:
```sh
CGO_ENABLED=0 go build -ldflags='-s -w'
```
On Windows, say:
```dosbat
set CGO_ENABLED=0
go build -ldflags="-s -w"
```
If your server has a different architecture than the machine on which you
are building, set the `GOOS` and `GOARCH` environment variables. For
example, in order to compile for a 64-bit ARM system (a Raspberry Pi or an
Olimex board, for example), you would say:
```sh
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags='-s -w'
```
### Optional: install libraries for background blur
Galene's client uses Google's MediaPipe library to implement background
blur. This library is optional, and if it is absent, Galene will
disable the menu entries for background blur.
Optionally install Google's MediaPipe library:
```sh
mkdir mediapipe
cd mediapipe
npm pack @mediapipe/tasks-vision
tar xzf mediapipe-tasks-vision-*.tgz
rm -f ../static/third-party/tasks-vision
mv package ../static/third-party/tasks-vision
cd ../static/third-party/tasks-vision
mkdir models
cd models
wget https://storage.googleapis.com/mediapipe-models/image_segmenter/selfie_segmenter/float16/latest/selfie_segmenter.tflite
cd ../../../../
```
### Deploy to your server
The following instructions assume that your server is called
`galene.example.org` and that you have already created a dedicated user
called `galene`.
First, create an empty directory called `groups`:
```sh
mkdir groups
```
Now copy the `galene` binary, and the directories `static`, `data` and
`groups` to the server:
```sh
rsync -a galene static data groups galene@galene.example.org:
```
If you don't have a TLS certificate, Galène will generate a self-signed
certificate (and print a warning to the logs). If you have a certificate,
install it in the files `data/cert.pem` and `data/key.pem`:
```sh
ssh galene@galene.example.org
sudo cp /etc/letsencrypt/live/galene.example.org/fullchain.pem data/cert.pem
sudo cp /etc/letsencrypt/live/galene.example.org/privkey.pem data/key.pem
sudo chown galene:galene data/*.pem
chmod go-rw data/key.pem
```
Since certificates are regularly rotated, this should be done in a monthly
cron job (or a *SystemD* timer unit, if you're feeling particularly kinky).
### Run Galene on the server
Arrange to run the binary on the server. If you never reboot your server,
just do:
```sh
ssh galene@galene.example.org
ulimit -n 65536
nohup ./galene &
```
If you are using *runit*, use a script like the following:
```sh
#!/bin/sh
exec 2>&1
cd ~galene
ulimit -n 65536
exec setuidgid galene ./galene
```
If you are using *SystemD*, put the following in
`/etc/systemd/system/galene.service`:
```ini
[Unit]
Description=Galene
After=network.target
[Service]
Type=simple
WorkingDirectory=/home/galene
User=galene
Group=galene
ExecStart=/home/galene/galene
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
```
### Set up galenectl
There are two ways to administer a Galene instance: by manually editing
JSON files on the server, or by using the `galenectl` utility.
The `galenectl` utility is recommended, since it avoids issues with
concurrent modifications and is less error-prone than the alternative.
Build the `galenectl` utility, and copy it somewhere on your path:
```sh
cd galenectl
go build -ldflags='-s -w'
sudo cp galenectl /usr/local/bin
```
Now create an administrator password, and set up galenectl:
```sh
galenectl -admin-username admin initial-setup
```
This command creates two files: `galenectl.conf` and `config.json`. The
former is already at the right place, the latter must be copied to the
server's `data/` directory:
```sh
rsync config.json galene@galene.example.org:data/
```
### Group setup
Create a group:
```sh
galenectl create-group -group city-watch
```
If you didn't install a TLS certificate above, you will need to run
`galenectl` with the flag `-insecure`:
```sh
galenectl -insecure create-group -group city-watch
```
Create an "op", a user with group moderation privileges:
```sh
galenectl create-user -group city-watch -user vimes -permissions op
```
Set the new user's password:
```sh
galenectl set-password -group city-watch -user vimes
```
You should now be able to test your Galene installation by pointing a web
browser at <https://galene.example.org:8443/group/testing/>.
Create an ordinary user:
```sh
galenectl create-user -group city-watch -user fred
galenectl set-password -group city-watch -user fred
```
Check the results:
```sh
galenectl list-groups
galenectl list-users -l -group city-watch
```
Type `galenectl -help`, `galenectl create-group -help`, etc. for more
information.
## Advanced configuration
Galene is designed to be exposed directly to the internet. If your server
is behind a firewall or NAT router, some extra configuration is necessary.
### Running behind a firewall
If your server is behind a firewall but has a global IPv4 address (it is
not behind NAT), then, at the very minimum, the firewall must allow
incoming connections to:
* TCP port 8443 (or whatever is configured with the `-http` option); and
* TCP and UDP port 1194 (or whatever is configured with the `-turn` option).
For good performance, your firewall should allow incoming and outgoing
traffic from the UDP ports used for media transfer. By default, these are
all high-numbered (ephemeral) ports, but they can be restricted using one
of the following options:
* the `-udp-range port1-port2` option restricts the UDP ports to be in
the range from port1 to port2 inclusive; this should be a large range,
on the order of a few tens of thousands of ports;
* the `-udp-range port` option makes the server use just a single port,
and demultiplex the traffic in userspace.
At the time of writing, this mechanism is not quite complete, and you will
see Galene attempting to use other ports. Unless you see connection
failures, this is nothing to worry about.
### Running behind NAT
If your server is behind NAT, then currently the only option is to use
a STUN, or, preferably, TURN server on a separate host, one that is not
behind NAT. See Section "Connectivity issues and ICE servers" below.
Galene has some support for running behind NAT without a helpful server,
but this has not been exhaustively tested. Please see the section
"Connectivity issues and ICE server" below.
### Running behind a reverse proxy
Galene is designed to be directly exposed to the Internet. In order to
run Galene behind a reverse proxy, you might need to make a number of
tweaks to your configuration.
First, you might need to inform Galene of the URL at which users connect
(the reverse proxy's URL) by adding an entry `proxyURL` to your
`data/config.json` file:
```json
{
"proxyURL": "https://galene.example.org/"
}
```
Second, and depending on your proxy implementation, you might need to
request that the proxy pass WebSocket handshakes to the URL at `ws`; for
example, with Nginx, you will need to say something like the following:
```
location /ws {
proxy_pass ...;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
```
Finally, in order to avoid TLS termination issues, you may want to run
Galene over plain HTTP instead of HTTPS by using the command-line flag
`-insecure`.
Note that even if you're using a reverse proxy, clients will attempt to
establish direct UDP flows with Galene and direct TCP connections to
Galene's TURN server; see the section on "Configuring your firewall"
above.
## Connectivity issues and ICE servers
Most connectivity issues are due to an incorrect ICE configuration.
ICE is the NAT and firewall traversal protocol used by WebRTC. ICE can
make use of two kinds of servers to help with NAT traversal: STUN servers,
that help punching holes in well-behaved NATs, and TURN servers, that
serve as relays for traffic. TURN is a superset of STUN: no STUN server
is necessary if one or more TURN servers are available.
Galène includes an IPv4-only TURN server, which is controlled by the
`-turn` command-line option. It has the following behaviour:
* if its value is set to the empty string `""`, then the built-in server
is disabled; in this case, the file `data/ice-servers.json` configures
an external TURN server;
* if its value is a colon followed with a port number, for example
`:1194`, then the TURN server will listen on all public IPv4 addresses
of the local host, over UDP and TCP; this is the recommended value if
the server is not behind NAT, and the firewall allows incoming
connections to the TURN port.
* if the value of this option is a socket address, such as
`203.0.113.1:1194`, then the TURN server will listen on all addresses
of the local host but assume that the address seen by the clients is
the one given in the option; this may be useful when running behind NAT
with port forwarding set up.
* the default value is `auto`, which behaves like `:1194` if there is no
`data/ice-servers.json` file, and like `""` otherwise.
If the server is not accessible from the Internet, e.g. because of NAT or
because it is behind a restrictive firewall, then you should configure
a TURN server that runs on a host that is accessible by both Galène and
the clients. Disable the built-in TURN server (`-turn ""` or the default
`-turn auto`), and provide a working ICE configuration in the file
`data/ice-servers.json`. In the case of a single STUN server, it should
look like this:
```json
[
{
"urls": [
"stun:stun.example.org"
]
}
]
```
In the case of s single TURN server, the `ice-servers.json` file should
look like this:
```json
[
{
"urls": [
"turn:turn.example.org:443",
"turn:turn.example.org:443?transport=tcp"
],
"username": "galene",
"credential": "secret"
}
]
```
It is more secure to use coturn's `use-auth-secret` option. If you do
that, then the `ice-servers.json` file should look like this:
```json
[
{
"urls": [
"turn:turn.example.com:443",
"turn:turn.example.com:443?transport=tcp"
],
"username": "galene",
"credential": "secret",
"credentialType": "hmac-sha1"
}
]
```
For redundancy, you may set up multiple TURN servers, and ICE will use the
first one that works. If an `ice-servers.json` file is present and
Galène's built-in TURN server is enabled, then the external server will be
used in preference to the built-in server.
+575
View File
@@ -0,0 +1,575 @@
# Galene manual
Please see the file [galene-install.md][1] for installation instructions.
Please see the section "Server administration" below for detailed
administration instructions.
## Usage
Galene includes a web server that, by default, listens on port 8443.
Galene is therefore accessed on URLs such as:
https://galene.example.org:8443/
### The landing page
There is a landing page at the root of the server. The landing page
contains a list of all groups marked "public" in their configuration, as
well as a form that allows joining an arbitrary group.
Going through the landing page is not required: you are welcome to point
your browser directly at the desired group URL.
### The group pages
A group named e.g. *city-watch* has an associated page
`/group/city-watch/`. After login, it presents an interface consisting
of three panes:
- the left side pane contains the list of users who have joined the
group; every username doubles as a menu of group and user actions;
- the middle pane contains the chat messages published to the group;
- the main pane, on the right, contains the videos being streamed by
users in the group.
On mobile, only the latter pane is shown by default. An icon at the top
left opens the user list, and an icon in the main pane switches to the
chat.
### Buttons
There are up to three buttons at the top. The most important is The
*Enable*/*Disable* button, which switches on or off both the camera and
the microphone.
The *Mute* button mutes or unmutes the microphone; the microphone can be
muted remotely by the group moderator, but it cannot be unmuted remotely.
The *Share screen* button streams the contents of the screen or an
individual window.
### Side menu
There is a menu on the right of the user interface. It allows switching
off the camera (for audio-only sessions), choosing the camera and
microphone and setting the video throughput. The *Blackboard mode*
checkbox increases resolution and sacrifices framerate in favour of image
quality. The *Play local file* dialog streams a video from a local file.
### User list
There is a user list on the left, starting with the current user and
continuing with all users that have joined the current group.
The user list doubles as a set of menu. Clicking on the current user (the
first entry in the user list) opens the *group menu*, a menu with actions
that apply to the group as a whole. Clicking on a different user opens
a *user menu*, a menu that applies to that specific user.
### Chat pane
The center pane is a traditional chat interface, with an input form at the
bottom and the chat history above it. Chat history is never saved to
disk, and is erased after four hours (or whatever is specified in the
`"max-history-age"` field of the group definition).
Double-clicking on a message opens a contextual menu.
The chat form doubles as a command-line interface, which is especially
important for visually-impaired users, and more generally is often faster
than navigating the user interface. Commands start with a slash character
"`/`". The most important command is `/msg`, which sends a private
message to a given user. Type `/help` to display the list of available
commands.
### Inviting users
In order to generate an invitation link, choose the entry "Invite user" in
the group menu. This generates a link of the form
https://galene.example.org:8443/group/city-watch/?token=XXX
where the *XXX* part, known as the *token*, is a shared secret. Such
a link allows password-less login to the group, and may therefore be
shared e.g. over e-mail or instant messaging.
The invitiation functionality is usually restricted to the moderator;
however, groups may be configured with the `"unrestricted-tokens"` option,
which allows all users to generate tokens.
Tokens can be created, modified, and expires using the `/invite`,
`/reinvite` and `/revoke` commands.
nnnn
### File transfer
Galene includes a peer-to, end-to-end encrypted file transfer protocol.
In order to transfer a file, click on the receiver's entry in the user
list and choose "Send file".
### Group moderation
If a user has the *op* permission (short for *Operator*), then they have
access to a number of moderation tools.
For a moderator, the contextual menu that opens when clicking on an entry
in the user list is expanded with commands for muting a user, sending them
a warning, retrieving their IP address, or kicking them out from a group.
The group menu (opened by clicking on one's own entry in the user's list)
is extended with options to lock or to unlock a group (a locked group is
one that non-operator users cannot join).
All of the moderation commands are also available as command-line commands
(see above), which is helpful when moderating large groups.
# Server administration
## The global configuration file
The server may be configured in the JSON file `data/config.json`. This
file may look as follows:
```json
{
"users":{"vetinari": {"password":"lagniappe", "permissions": "admin"}},
"canonicalHost": "galene.example.org",
"writableGroups": true
}
```
or, better, with a hashed password:
```json
{
"users": {
"vetinari": {
"password":{"type":"bcrypt","key":"$2a$10$bTWW..."},
"permissions": "admin"
}
},
"canonicalHost": "galene.example.org",
"writableGroups": true
}
```
The file is initially set up using `galenectl initial-setup`, but may be
manually edited at any time (there is no need to restart the server). The
fields are as follows:
- `users` defines the users allowed to administer the server, and has the
same syntax as user definitions in groups (see below), except that the
only meaningful permission is `"admin"`;
- `writableGroups`: if true, then the API used by `galenectl` can be used
to modify group definitions; if unset or false, then only read-only
access is allowed;
- `allowOrigin` is an array that contains the list of HTTP origins that
are allowed to access the server;
- `allowAdminOrigin` is like `allowOrigin`, but applies to the
administrative API (the one used by `galenectl`);
- `proxyURL`: if running behind a reverse proxy, this specifies the root
URL that will be visible outside the proxy;
- `canonicalHost`: the canonical name of the host running the server;
clients that attempt to access the server using a different host name
will be redirected to the canonical one.
## Group definitions
Groups are described by JSON files in the `./groups/` directory. These
files are normally administered using the `galenectl` utility, but may
also be edited manually (there is no need to restart the server).
### Managing groups using `galenectl`
#### Creating, modifying, and suppressing groups
A group is created using `galenectl create-group`:
```sh
galenectl create-group -group city-watch
```
There are a number of options to customise the behaviour of the group, see
`galenectl create-group -help` for a full list. For example, in order to
create a group that allows unrestricted creation of tokens, say:
```sh
galenectl create-group -group city-watch -unrestricted-tokens
```
For more advanced configuration, `galenectl create-group` can be invoked
with the `-json` flag, in which case it takes a JSON template on standard
input. The syntax of a JSON template is just like that of a group
definition file (see below), except that it must not contain the fields
`users` and `wildcard-user`. For example, in order to create a redirect
(see the section "Group description reference" below):
```sh
echo '{"redirect": "https://galene.example.org:8443/group/city-watch/"}' | galenectl create-group -group amcw -json
```
Groups are modified using `galenectl update-group`:
```sh
galenectl update-group -group city-watch -unrestricted-tokens=false
```
If a JSON template is provided to `galenectl update-group`, then it is
merged with the existing group configuration. Entries may be suppressed
by setting them to `null` in the template:
```sh
echo '{"redirect": null}' | galenectl update-group -group amcw
```
A group is deleted using `galenectl delete-group`:
```sh
galenectl delete-group -group amcw
```
#### Creating, modifying, and suppressing users
A user entry is created with the `galenectl create-user` command :
```sh
galenectl create-user -group city-watch -user vimes -permissions op
```
If the `-permissions` flag is not specified, it defaults to `present`,
meaning that the user can participate in the chat and present videos to
the group. The other useful values are `message`, which allows a user
to participate in the chat only, and `observe`, which doesn't allow any
active participation.
A user is modified using `galenectl update-user`, and suppressed using
`galenectl delete-user`.
In order to be useful, a user entry needs to be assigned a password. This
is done with the `galenectl set-password` command:
```sh
galenectl set-password -group city-watch -user vimes
```
#### The fallback user
It is sometimes useful to allow multiple users to log-in using the same
password. This is achieved by defining the *wildcard* user:
```sh
galenectl create-user -group city-watch -wildcard
galenectl set-password -group city-watch -wildcard
```
For open groups, where any user can login with any password, the wildcard
user's password is set to the password of type `wildcard`:
```sh
galenectl set-password -group city-watch -wildcard -type wildcard
```
See the section "Client authorisation" below for more information about
password types.
#### Automatic subgroups
It is sometimes necessary to create large numbers of identical groups.
For example, the author has been using Galene to supervise computer
science practicals, where up to 40 students are working in groups of two.
While it is possible to automate the creation of groups, by accessing
Galene's API, by scripting calls to galenectl, or by directly generating
files under `groups/`, Galene provides a facility known as *automatic
subgroups* that can be used to generate groups on demand.
Automatic subgroups are enabled by setting the `"auto-subgroups"`
field in the group description:
```sh
galenectl create-group unseen-university -auto-subgroups
```
Whenever a user attempts to access a subgroup of `unseen-university`, for
example `unseen-university/hex`, the group is created in memory and
persists until it is empty and its chat history has expired. The main
group's operator can view the list of populated subgroups with the command
`/subgroups`.
#### Managing tokens
Tokens are normally managed using the `/invite`, `/reinvite` and `/expire`
commands in Galene's user interface, but they may also be managed using
the `galenectl` utility's `create-token`, `revoke-token`, `delete-token`
and `list-tokens` commands:
```sh
galenectl create-token -group city-watch
galenectl list-tokens -l -group city-watch
```
A token that is generated with the `-include-subgroups` flag applies to
the whole hierarchy rooted at the given group, including both ordinary
groups and automatically generated subgroups.
```sh
galenectl create-token -group city-watch -include-subgroups
```
Such a token can be attached to the root of the group hierarchy, and
therefore be valid for any group on the server:
```sh
galenectl create-token -group '' -include-subgroups
```
### Group description reference
The definition for the group called *groupname* is in the file
`groups/groupname.json`; it does not contain the group name, which makes
it easy to copy or link group definitions. You may use subdirectories:
a file `groups/teaching/networking.json` defines a group called
*teaching/networking*.
Every group definition file contains a single JSON dictionary. All fields
are optional. The following fields are allowed:
- `users`: is a dictionary that maps user names to user descriptions (see
below);
- `wildcard-user` is a user description that will be used for usernames
with no matching entry in the `users` dictionary;
- `authKeys`, `authServer` and `authPortal`: see *Authorisation* below;
- `public`: if true, then the group is listed on the landing page;
- `displayName`: a human-friendly version of the group name; this is
displayed at the top of the group page;
- `description`: a human-readable description of the group; this is
displayed on the landing page for public groups;
- `contact`: a human-readable contact for this group, such as an e-mail
address, ignored by the server;
- `comment`: a human-readable string, ignored by the server;
- `max-clients`: the maximum number of clients that may join the group at
a time;
- `max-history-age`: the time, in seconds, during which chat history is
kept (default 14400, i.e. 4 hours);
- `not-before` and `expires`: the times (in ISO 8601 or RFC 3339 format)
between which joining the group is allowed;
- `allow-recording`: if true, then recording is allowed in this group;
- `unrestricted-tokens`: if true, then ordinary users (without the "op"
privilege) are allowed to create tokens;
- `allow-anonymous`: if true, then users may connect with an empty username;
- `auto-subgroups`: if true, then subgroups of the form `group/subgroup`
are automatically created when first accessed;
- `autolock`: if true, the group will start locked and become locked
whenever there are no clients with operator privileges;
- `autokick`: if true, all clients will be kicked out whenever there are
no clients with operator privileges; this is not recommended, prefer
the `autolock` option instead;
- `redirect`: if set, then attempts to join the group will be redirected
to the given URL; most other fields are ignored in this case;
- `codecs`: this is a list of codecs allowed in this group, see below for
possible values. The default is `["vp8", "opus"]`.
A user definition is a dictionary with entries `password` and
`permission`. The value of the `password` field is either a plaintext
password, or a hashed password generated for example by the `galenectl
hash-password` command. The value of the `permissions` field can either
be an array of individual permissions (not recommended), or one of the
following strings:
- `op`, a group operator, with all rights except administering the group;
- `present`, an ordinary user with the right to publish audio and video
streams and send chat messages;
- `message`, a user with the right to send chat messages;
- `observe`, a user that receives media streams and chat messages, but
is not allowed to send them;
- `caption`, a user with the right to display captions (only);
- `admin`, a user with the right to administer the group (only).
The value of the `codecs` field is an array of codecs allowed in the
group. Supported video codecs include:
- `"vp8"` (compatible with all supported browsers, full functionality);
- `"vp9"` (better video quality, but incompatible with Safari; somewhat
buggy in Firefox; full functionality);
- `"av1"` (even better video quality, only supported by some browsers,
limited functionality: no recording, no SVC);
- `"h264"` (well supported by Apple devices, but incompatible with Debian
Linux and with some older Android devices, SVC is not supported; might
be covered by patents in some countries).
Supported audio codecs include `"opus"`, `"g722"`, `"pcmu"` and `"pcma"`.
Only Opus can be recorded to disk. There is no good reason to use
anything except Opus.
## Client Authorisation
Galene implements three authorisation methods: a username/password
authorisation scheme, a scheme using stateful tokens, and a mechanism
based on cryptographic tokens. The former two mechanism are intended to
be used in standalone installations, while the cryptographic mechanism is
designed to allow easy integration with an existing authorisation
infrastructure (such as LDAP, OAuth2, or even Unix passwords).
### Password authorisation
When password authorisation is used, authorised usernames and password are
defined directly in the group configuration file, in the `users` and
`wildcard-user` entries. The `users` entry is a dictionary that maps user
names to user descriptions; the `wildcard-user` is a user description
that is used with usernames that don't appear in `users`. These two
entries are usually managed by the `galenectl` utility.
Every user description is a dictionary with fields `password` and
`permissions`. The `password` field may be a literal password string, or
a dictionary describing a hashed password or a wildcard. The
`permissions` field should be one of `op`, `present`, `message` or
`observe`. (An array of Galene's internal permissions is also allowed,
but this is not recommended, since internal permissions may vary from
version to version).
For example, the entry
```json
{
"users": {"vimes": {"password": "sybil", "permissions": "op"}}
}
```
specifies that user "vimes" may login as operator with password "sybil", while
```json
{
"wildcard-user": {"password": "1234", "permissions": "present"}
}
````
allows any username with password *1234*. Finally,
```json
{
"wildcard-user":
{"password": {"type": "wildcard"}, "permissions": "present"}
}
```
allows any username with any password.
### Hashed passwords
For security reasons, passwords are usually hashed before being stored in
group descriptions (in fact, the `galenectl` utility does not even support
storing plaintext passwords). A hased password is represented as a JSON
dicttionary with a field `type` and a number of type-specific fields.
A user entry with a hashed password looks like this:
```json
"users": {
"vimes": {
"password": {
"type": "pbkdf2",
"hash": "sha-256",
"key": "f591c35604e6aef572851d9c3543c812566b032b6dc083c81edd15cc24449913",
"salt": "92bff2ace56fe38f",
"iterations": 4096
},
"permissions": "op"
}
}
```
Hashed passwords are normally generated transparently to the user by the
`galenectl set-password` command. When edition group description files
manually, hashed passwords can be generated with the `galenectl hash-password`
utility.
### Stateful tokens
Stateful tokens are created by the `/invite` command in the Galene user
interface or by the `galenectl create-token` command; see the section
*Managing tokens* above. They are stored in the file
`data/var/tokens.jsonl`, which, on most filesystems, can be safely backed
up without stopping the server.
### Cryptographic tokens
In many cases, it is useful to delegate authorisation decisions to a third
party, such as an LDAP or OAuth2 client. Galene implements delegation of
authorisation decisions using cryptographic tokens generated by a third
party known as an *authorisaton server*. Two authorisation servers are
available: an [LDAP client][2], and a [sample server written in Python][3].
When an authorisation server is used, the `"authKeys"` entry of the group
configuration file specifies one or more public keys in JWK format (with
the restriction that the "alg" key must be specified explicitly):
```json
{
"authKeys": [{
"kty": "oct",
"alg": "HS256",
"k": "MYz3IfCq4Yq-UmPdNqWEOdPl4C_m9imHHs9uveDUJGQ",
}, {
"kty": "EC",
"alg": "ES256",
"crv": "P-256",
"x": "dElK9qBNyCpRXdvJsn4GdjrFzScSzpkz_I0JhKbYC88",
"y": "pBhVb37haKvwEoleoW3qxnT4y5bK35_RTP7_RmFKR6Q",
}]
}
```
If multiple keys are provided, then they will all be tried in turn, unless
the token includes the "kid" header field, in which case only the
specified key will be used.
The group file should also specify either an authorisation server or an
authorisation portal. An authorisation server is specified using the
`"authServer"` key:
```json
{
"authServer": "https://auth.example.org",
}
```
If an authorisation server is specified, then the client, after it prompts
for a password, will request a token from the authorisation server and
join the group using token authentication. The password is never
communicated to the server.
Alternatively, the group file may specify an authorisation portal using
the `"authPortal"` key
If an authorisation portal is specified, then the default client will
redirect initial client connections to the authorisation portal. The
authorisation portal is expected to authorise the client and then redirect
it to Galene with the `username` and `token` query parameters set.
[1]: <galene-install.md>
[2]: <https://github.com/jech/galene-imap/>
[3]: <https://github.com/jech/galene-sample-auth-server/>