diff --git a/.forgejo/workflows/ci.yaml b/.forgejo/workflows/ci.yaml index 3f1db22a..26097f39 100644 --- a/.forgejo/workflows/ci.yaml +++ b/.forgejo/workflows/ci.yaml @@ -15,13 +15,6 @@ jobs: - uses: actions/checkout@v4 - run: nix build .#checks.x86_64-linux.pre-commit -L - check-website: - runs-on: native - steps: - - uses: actions/checkout@v4 - - run: cd website && nix-build -A tests - - run: cd website && nix-build -A build - check-peertube: runs-on: native steps: diff --git a/matrix/.gitignore b/matrix/.gitignore deleted file mode 100644 index c234679c..00000000 --- a/matrix/.gitignore +++ /dev/null @@ -1,34 +0,0 @@ -# Eerst: GEEN PDF/PS IN GIT! -*.pdf -*.ps - -# ---> LyX -# Ignore LyX backup and autosave files -# http://www.lyx.org/ -*.lyx~ -*.lyx# - -# ---> Vim -# Swap -[._]*.s[a-v][a-z] -!*.svg # comment out if you don't need vector files -[._]*.sw[a-p] -[._]s[a-rt-v][a-z] -[._]ss[a-gi-z] -[._]sw[a-p] - -# Session -Session.vim -Sessionx.vim - -# Temporary -.netrwhist -*~ -# Auto-generated tag files -tags -# Persistent undo -[._]*.un~ - -# En geen vaults -/ansible/group_vars/matrix/vault.yaml - diff --git a/matrix/README.md b/matrix/README.md deleted file mode 100644 index e0ba681f..00000000 --- a/matrix/README.md +++ /dev/null @@ -1,124 +0,0 @@ ---- -gitea: none -include_toc: true ---- - -# A complete Matrix installation - -This documentation describes how to build a complete Matrix environment with -all bells and whistles. Not just the Synapse server, but (almost) every bit -you want. - -The main focus will be on the server itself, Synapse, but there's a lot more -than just that. - - -This documentation isn't ready yet, and if you find errors or room for improvement, -please let me know. You can do that via Matrix, obviously (`@hans:woefdram.nl`), via -e-mail (`docs@fediversity.eu`), or make a Pull Request. - - -## Overview - -A complete Matrix environment consists of many parts. Other than the Matrix -server itself (Synapse) there are all kinds of other things that we need: - -* [Synapse](https://element-hq.github.io/synapse/latest/) -* Webclient ([Element Web](https://github.com/element-hq/element-web)) -* [Element Call](https://github.com/element-hq/element-call) for audio/video -conferencing -* Management with [Synapse-Admin](https://github.com/Awesome-Technologies/synapse-admin) -* Moderation with [Draupnir](https://github.com/the-draupnir-project/Draupnir) -* [Consent -tracking](https://element-hq.github.io/synapse/latest/consent_tracking.html) -* Authentication via -[OpenID](https://element-hq.github.io/synapse/latest/openid.html) (later) -* Several [bridges](https://matrix.org/ecosystem/bridges/) (later) - - -# Overview - -This documentation aims to describe the installation of a complete Matrix -platform, with all bells and whistles. Several components are involved and -finishing the installation of one can be necessary for the installation of the -next. - -Before you start, make sure you take a look at the [checklist](checklist.md). - -These are the components we're going to use: - - -## Synapse - -This is the core component: the Matrix server itself, you should probably -install this first. - -Because not every usecase is the same, we'll describe two different -architectures: - -** [Monolithic](synapse) - -This is the default way of installing Synapse, this is suitable for scenarios -with not too many users, and, importantly, users do not join many very crowded -rooms. - -** [Worker-based](synapse/workers) - -For servers that get a bigger load, for example those that host users that use -many big rooms, we'll describe how to process that higher load by distributing -it over workers. - - -## PostgreSQL - -This is the database Synapse uses. This should be the first thing you install -after Synapse, and once you're done, reconfigure the default Synapse install -to use PostgreSQL. - -If you have already added stuff to the SQLite database that Synapse installs -by default that you don't want to lose: [here's how to migrate from SQLite to -PostgreSQL](https://element-hq.github.io/synapse/latest/postgres.html#porting-from-sqlite). - - -## nginx - -We need a webserver for several things, see how to [configure nginx](nginx) -here. - -If you install this, make sure to check which certificates you need, fix the -DNS entries and probably keep TTL for for those entries very low until after -the installation, when you know everything's working. - - -## Element Call - -Element Call is the new way to have audio and video conferences, both -one-on-one and with groups. This does not use Jitsi and keeps E2EE intact. See -how to [setup and configure it](element-call). - - -# Element Web - -This is the fully-fledged web client, which is very [easy to set -up](element-web). - - -# TURN - -We may need a TURN server, and we'll use -[coturn](coturn) for that. - -It's apparently also possible to use the built-in TURN server in Livekit, -which we'll use if we use [Element Call](element-call). It's either/or, so make -sure you pick the right approach. - -You could possibly use both coturn and LiveKit, if you insist on being able to -use both legacy and Element Call functionality. This is not documented here -yet. - - -# Draupnir - -With Draupnir you can do moderation. It requires a few changes to both Synapse -and nginx, here's how to [install and configure Draupnir](draupnir). - diff --git a/matrix/checklist.md b/matrix/checklist.md deleted file mode 100644 index da10d48f..00000000 --- a/matrix/checklist.md +++ /dev/null @@ -1,97 +0,0 @@ -# Checklist - -Before you dive in and start installing, you should do a little planning -ahead. Ask yourself what you expect from your server. - -Is it a small server, just for yourself and some friends and family, or for -your hundreds of colleagues at work? Is it for private use, or do you need -decent moderation tools? Do you need audio and videoconferencing or not? - - -# Requirements - -It's difficult to specify hardware requirements upfront, because they don't -really depend on the number of users you have, but on their behaviour. A -server with users who don't engage in busy rooms like -[#matrix:matrix.org](https://matrix.to/#/#matrix:matrix.org) doesn't need more -than 2 CPU cores, 8GB of RAM and 50GB of diskspace. - -A server with users who do join very busy rooms, can easily eat 4 cores and -16GB of RAM. Or more. Or even much more. If you have a public server, where -unknown people can register new accounts, you'll probably need a bit more -oompf (and [moderation](draupnir)). - -During its life, the server may need more resources, if users change -their behaviour. Or less. There's no one-size-fits-all approach. - -If you have no idea, you should probably start with 2 cores, 8GB RAM and some -50GB diskspace, and follow the [monolithic setup](synapse). - -If you expect a higher load (you might get there sooner than you think), you -should probably follow the [worker-based setup](synapse/workers), because -changing the architecture from monolithic to worker-based once the server is -already in use, is a tricky task. - -Here's a ballpark figure. Remember, your mileage will probably vary. And -remember, just adding RAM and CPU doesn't automatically scale: you'll need to -tune [PostgreSQL](postgresql/README.md#tuning) and your workers as well so -that your hardware is optimally used. - -| Scenario | Architecture | CPU | RAM | Diskspace (GB) | -| :------------------------------------ | :-----------------------------: | :----: | :----: | :------------: | -| Personal, not many very busy rooms | [monolithic](synapse) | 2 | 8GB | 50 | -| Private, users join very busy rooms | [worker-based](synapse/workers) | 4 | 16GB | 100 | -| Public, many users in very busy rooms | [worker-based](synapse/workers) | 8 | 32GB | 250 | - - -# DNS and certificates - -You'll need to configure several things in DNS, and you're going to need a -couple of TLS-certificates. Best to configure those DNS entries first, so that -you can quickly generate the certificates once you're there. - -It's usually a good idea to keep the TTL of all these records very low while -installing and configuring, so that you can quickly change records without -having to wait for the TTL to expire. Setting a TTL of 300 (5 minutes) should -be fine. Once everything is in place and working, you should probably increase -it to a more production ready value, like 3600 (1 hour) or more. - -What do you need? Well, first of all you need a domain. In this documentation -we'll use `example.com`, you'll need to substitute that with your own domain. - -Under the top of that domain, you'll need to host 2 files under -`/.well-known`, so you'll need a webserver there, using a valid -TLS-certificate. This doesn't have to be the same machine as the one you're -installing Synapse on. In fact, it usually isn't. - -Assuming you're hosting Matrix on the machine `matrix.example.com`, you need -at least an `A` record in DNS, and -if you have IPv6 support, which you -should- an `AAAA` record too. **YOU CAN NOT USE A CNAME FOR THIS RECORD!** -You'll need a valid TLS-certificate for `matrix.example.com` too. - -You'll probably want the webclient too, so that users aren't forced to use an -app on their phone or install the desktop client on their PC. You should never -run the web client on the same name as the server, that opens you up for all -kinds of Cross-Site-Scripting attack. We'll assume you use -`element.example.com` for the web client. You need a DNS entry for that. This -can be a CNAME, but make sure you have a TLS-certificate with the correct name -on it. - -If you install a [TURN-server](coturn), either for legacy calls or for [Element -Call](element-call) (or both), you need a DNS entry for that too, and -again- a -TLS-certificate. We'll use `turn.example.com` for this. - -If you install Element Call (and why shouldn't you?), you need a DNS entry plus -certificate for that, let's assume you use `call.example.com` for that. This -can be a CNAME again. Element Call uses [LiveKit](element-call#livekit) for the -actual processing of audio and video, and that needs its own DNS entry and certificate -too. We'll use `livekit.example.com`. - -| FQDN | Use | Comment | -| :-------------------- | :--------------------- | :--------------------------------------- | -| `example.com` | Hosting `.well-known` | This is the `server_name` | -| `matrix.example.com` | Synapse server | This is the `base_url`, can't be `CNAME` | -| `element.example.com` | Webclient | | -| `turn.example.com` | TURN / Element Call | Highly recommended | -| `call.example.com` | Element Call | Optional | -| `livekit.example.com` | LiveKit SFU | Optional, needed for Element Call | diff --git a/matrix/coturn/README.md b/matrix/coturn/README.md deleted file mode 100644 index 4468f0da..00000000 --- a/matrix/coturn/README.md +++ /dev/null @@ -1,181 +0,0 @@ ---- -gitea: none -include_toc: true ---- - -# TURN server - -You need a TURN server to connect participants that are behind a NAT firewall. -Because IPv6 doesn't really need TURN, and Chrome can get confused if it has -to use TURN over IPv6, we'll stick to a strict IPv4-only configuration. - -Also, because VoIP traffic is only UDP, we won't do TCP. - -TURN-functionality can be offered by coturn and LiveKit alike: coturn is used -for legacy calls (only one-on-one, supported in Element Android), whereas -Element Call (supported by ElementX, Desktop and Web) uses LiveKit. - -In our documentation we'll enable both, which is probably not the optimal -solution, but at least it results in a system that supports old and new -clients. - -Here we'll describe coturn, the dedicated ICE/STUN/TURN server that needs to -be configured in Synapse, [LiveKit](../element-call#livekit) has its own page. - -# Installation - -Installation is short: - -``` -apt install coturn -``` - -For sake of maintainability we'll move the only configuration file into its -own directoy: - -``` -mkdir /etc/coturn -mv /etc/turnserver.conf /etc/coturn -``` - -We need to tell systemd to start it with the configuration file on the new -place. Edit the service file with: - -``` -systemctl edit coturn -``` - -Contrary to what the comment suggests, only the parts you add will override -the content that's already there. We have to "clean" the `ExecStart` first, -before we assign a new line to it, so this is the bit we add: - -``` -[Service] -ExecStart= -ExecStart=/usr/bin/turnserver -c /etc/coturn/turnserver.conf --pidfile=/etc/coturn/run/turnserver.pid -``` - -Create the directory `/etc/coturn/run` and chgrp it to `turnserver`, so that -coturn can write its pid there: `/run/turnserver.pid` can't be written because -coturn doesn't run as root. - -This prepares us for the next step: configuring the whole thing. - - -# DNS and certificate {#dnscert} - -As stated before, we only use IPv4, so a CNAME to our machine that also does -IPv6 is a bad idea. Fix a new entry in DNS for TURN only, we'll use -`turn.example.com` here. - -Make sure this entry only has an A record, no AAAA. - -Get a certificate for this name: - -``` -certbot certonly --nginx -d turn.example.com -``` - -This assumes you've already setup and started nginx (see [nginx](../nginx)). - -{#fixssl} -The certificate files reside under `/etc/letsencrypt/live`, but coturn and -LiveKit don't run as root, and can't read them. Therefore we create the directory -`/etc/coturn/ssl` where we copy the files to. This script should be run after -each certificate renewal: - -``` -#!/bin/bash - -# This script is hooked after a renewal of the certificate, so that the -# certificate files are copied and chowned, and made readable by coturn: - -cd /etc/coturn/ssl -cp /etc/letsencrypt/live/turn.example.com/{fullchain,privkey}.pem . -chown turnserver:turnserver *.pem - -# Make sure you only start/restart the servers that you need! -systemctl try-reload-or-restart coturn livekit-server - -``` - -Run this automatically after every renewal by adding this line to -`/etc/letsencrypt/renewal/turn.example.com.conf`: - -``` -renew_hook = /etc/coturn/fixssl -``` - -Yes, it's a bit primitive and could (should?) be polished. But for now: it -works. This will copy and chown the certificate files and restart coturn -and/or LiveKit, depending on if they're running or not. - - -# Configuration {#configuration} - -Synapse's documentation gives a reasonable [default -config](https://element-hq.github.io/synapse/latest/setup/turn/coturn.html). - -We'll need a shared secret that Synapse can use to control coturn, so let's -create that first: - -``` -pwgen -s 64 1 -``` - -Now that we have this, we can configure our configuration file under -`/etc/coturn/turnserver.conf`. - -``` -# We don't use the default ports, because LiveKit uses those -listening-port=3480 -tls-listening-port=5351 - -# We don't need more than 10000 connections: -min-port=40000 -max-port=49999 - -use-auth-secret -static-auth-secret= - -realm=turn.example.com -user-quota=12 -total-quota=1200 - -# Of course: substitute correct IPv4 address: -listening-ip=111.222.111.222 - -# VoIP traffic is only UDP -no-tcp-relay - -# coturn doesn't run as root, so the certificate has -# to be copied/chowned here. -cert=/etc/coturn/ssl/fullchain.pem -pkey=/etc/coturn/ssl/privkey.pem - -denied-peer-ip=0.0.0.0-255.255.255.255 -denied-peer-ip=127.0.0.0-0.255.255.255 -denied-peer-ip=10.0.0.0-10.255.255.255 -denied-peer-ip=172.16.0.0-172.31.255.255 -denied-peer-ip=192.168.0.0-192.168.255.255 -denied-peer-ip=100.64.0.0-100.127.255.255 -denied-peer-ip=192.0.0.0-192.0.0.255 -denied-peer-ip=169.254.0.0-169.254.255.255 -denied-peer-ip=192.88.99.0-192.88.99.255 -denied-peer-ip=198.18.0.0-198.19.255.255 -denied-peer-ip=192.0.2.0-192.0.2.255 -denied-peer-ip=198.51.100.0-198.51.100.255 -denied-peer-ip=203.0.113.0-203.0.113.255 - -# We do only IPv4 -allocation-default-address-family="ipv4" - -# No weak TLS -no-tlsv1 -no-tlsv1_1 -``` - -All other options in the configuration file are either commented out, or -defaults. - -Make sure you've opened the correct ports in the [firewall](../firewall). diff --git a/matrix/coturn/turnserver.conf b/matrix/coturn/turnserver.conf deleted file mode 100644 index cfff14d6..00000000 --- a/matrix/coturn/turnserver.conf +++ /dev/null @@ -1,119 +0,0 @@ -# Coturn TURN SERVER configuration file - -# Only IPv4, IPv6 can confuse some software -listening-ip=111.222.111.222 - -# Listening port for TURN (UDP and TCP): -listening-port=3480 - -# Listening port for TURN TLS (UDP and TCP): -tls-listening-port=5351 - -# Lower and upper bounds of the UDP relay endpoints: -# (default values are 49152 and 65535) -# -min-port=40000 -max-port=49999 - -use-auth-secret -static-auth-secret= - -realm=turn.example.com - - -# Per-user allocation quota. -# default value is 0 (no quota, unlimited number of sessions per user). -# This option can also be set through the database, for a particular realm. -user-quota=12 - -# Total allocation quota. -# default value is 0 (no quota). -# This option can also be set through the database, for a particular realm. -total-quota=1200 - -# Uncomment if no TCP relay endpoints are allowed. -# By default TCP relay endpoints are enabled (like in RFC 6062). -# -no-tcp-relay - -# Certificate file. -# Use an absolute path or path relative to the -# configuration file. -# Use PEM file format. -cert=/etc/coturn/ssl/fullchain.pem - -# Private key file. -# Use an absolute path or path relative to the -# configuration file. -# Use PEM file format. -pkey=/etc/coturn/ssl/privkey.pem - -# Option to redirect all log output into system log (syslog). -# -syslog - -# Option to allow or ban specific ip addresses or ranges of ip addresses. -# If an ip address is specified as both allowed and denied, then the ip address is -# considered to be allowed. This is useful when you wish to ban a range of ip -# addresses, except for a few specific ips within that range. -# -# This can be used when you do not want users of the turn server to be able to access -# machines reachable by the turn server, but would otherwise be unreachable from the -# internet (e.g. when the turn server is sitting behind a NAT) -# -denied-peer-ip=0.0.0.0-255.255.255.255 -denied-peer-ip=127.0.0.0-0.255.255.255 -denied-peer-ip=10.0.0.0-10.255.255.255 -denied-peer-ip=172.16.0.0-172.31.255.255 -denied-peer-ip=192.168.0.0-192.168.255.255 -denied-peer-ip=100.64.0.0-100.127.255.255 -denied-peer-ip=192.0.0.0-192.0.0.255 -denied-peer-ip=169.254.0.0-169.254.255.255 -denied-peer-ip=192.88.99.0-192.88.99.255 -denied-peer-ip=198.18.0.0-198.19.255.255 -denied-peer-ip=192.0.2.0-192.0.2.255 -denied-peer-ip=198.51.100.0-198.51.100.255 -denied-peer-ip=203.0.113.0-203.0.113.255 - - -# TURN server allocates address family according TURN client requested address family. -# If address family not requested explicitly by the client, then it falls back to this default. -# The standard RFC explicitly define that this default must be IPv4, -# so use other option values with care! -# Possible values: "ipv4" or "ipv6" or "keep" -# "keep" sets the allocation default address family according to -# the TURN client allocation request connection address family. -allocation-default-address-family="ipv4" - -# Turn OFF the CLI support. -# By default it is always ON. -# See also options cli-ip and cli-port. -# -no-cli - -# Do not allow an TLS/DTLS version of protocol -# -no-tlsv1 -no-tlsv1_1 - -# Disable RFC5780 (NAT behavior discovery). -# -# Strongly encouraged to use this option to decrease gain factor in STUN -# binding responses. -# -no-rfc5780 - -# Disable handling old STUN Binding requests and disable MAPPED-ADDRESS -# attribute in binding response (use only the XOR-MAPPED-ADDRESS). -# -# Strongly encouraged to use this option to decrease gain factor in STUN -# binding responses. -# -no-stun-backward-compatibility - -# Only send RESPONSE-ORIGIN attribute in binding response if RFC5780 is enabled. -# -# Strongly encouraged to use this option to decrease gain factor in STUN -# binding responses. -# -response-origin-only-with-rfc5780 diff --git a/matrix/draupnir/README.md b/matrix/draupnir/README.md deleted file mode 100644 index bc4710c1..00000000 --- a/matrix/draupnir/README.md +++ /dev/null @@ -1,130 +0,0 @@ ---- -gitea: none -include_toc: true ---- - -# Draupnir - -Draupnir is the way to do moderation. It can exchange banlists with other -servers, and drop reports that people send into its moderation room so that -moderators can act upon them. - -Start by creating a room where moderators can give Draupnir commands. This -room should not be encrypted. Then create a user for Draupnir, this user -should ideally be an admin user. - -Once you've created the user, log in as this user, maybe set an avatar, join -the room you've created and then copy the access token. This token is used by -the Draupnir software to login. - -After that, close the window or client, but -do not logout. If you logout, the token will be invalidated. - -Make sure you have the right npm, Node.js, yarn and what-have-you ([see -Draupnir's documentation](https://the-draupnir-project.github.io/draupnir-documentation/bot/setup_debian)) -and prepare the software: - -``` -mkdir /opt -cd /opt -git clone https://github.com/the-draupnir-project/Draupnir.git -cd Draupnir -git fetch --tags -mkdir datastorage -yarn global add corepack -useradd -m draupnir -chown -R draupnir:draupnir -``` - -Now, "compile" the stuff as user draupnir: - -``` -sudo -u draupnir bash -c "install yarn" -sudo -u draupnir bash -c "yarn build" -``` - -When this is completed successfully, it's time to configure Draupnir. - - -# Configuration - -Under `config` you'll find the default configuration file, `default.yaml`. -Copy it to `production.yaml` and change what you must. - -| Option | Value | Meaning | -| :---- | :---- | :---- | -| `homeserverUrl` | `http://localhost:8008` | Where to communicate with Synapse when using network port| -| `homeserverUrl` | `http://unix:/run/matrix-synapse/incoming_main.sock` | Where to communicate with Synapse when using UNIX sockets (see [Workers](../synapse/workers.md)) | -| `rawHomeserverUrl` | `https://matrix.example.com` | Same as `server_name` | -| `accessToken` | access token | Copy from login session or create in [Synapse Admin](../synapse-admin)) | -| `password` | password | Password for the account | -| `dataPath` | `/opt/Draupnir/datastorage` | Storage | -| `managementRoom` | room ID | Room where moderators command Draupnir | - -This should give a working bot. - -There are a few other bits that you probably want to change. Draupnir can -direct reports to the management room, this is what you should change to -activate that: - -``` -web: - enabled: true - port: 8082 - address: ::1 - abuseReporting: - enabled: true - -pollReports: true -displayReports: true -``` - -For this to work (for reports to reach Draupnir) you'll need to configure -nginx to forward requests for reports to Draupnir: - -``` -location ~ ^/_matrix/client/(r0|v3)/rooms/([^/]*)/report/(.*)$ { - # The r0 endpoint is deprecated but still used by many clients. - # As of this writing, the v3 endpoint is the up-to-date version. - - # Alias the regexps, to ensure that they're not rewritten. - set $room_id $2; - set $event_id $3; - proxy_pass http://[::1]:8082/api/1/report/$room_id/$event_id; -} - -# Reports that need to reach Synapse (not sure if this is used) -location /_synapse/admin/v1/event_reports { - proxy_pass http://localhost:8008; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header Host $host; - client_max_body_size 50M; - proxy_http_version 1.1; - -location ~ ^/_synapse/admin/v1/rooms/([^/]*)/context/(.*)$ { - set $room_id $2; - set $event_id $3; - proxy_pass http://localhost:8008/_synapse/admin/v1/rooms/$room_id/context/$event_id; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header Host $host; - client_max_body_size 50M; - proxy_http_version 1.1; -} -``` - -# Rate limiting - -Normal users are rate limited, to prevent them from flooding the server. Draupnir -is meant to stop those events, but if it it itself rate limited, it won't work -all that well. - -How rate limiting is configured server-wide is documented in [Synapse's -documentation](https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html?highlight=ratelimiting#ratelimiting). -Overriding is, unfortunately, not something you can easily configure in the -configuration files. You'll have to do that in the database itself: - -``` -INSERT INTO ratelimit_override VALUES ('@draupnir:example.com', 0, 0); -``` diff --git a/matrix/element-call/README.md b/matrix/element-call/README.md deleted file mode 100644 index 2d42d72f..00000000 --- a/matrix/element-call/README.md +++ /dev/null @@ -1,375 +0,0 @@ ---- -gitea: none -include_toc: true ---- - -# Overview - -Element Call consists of a few parts, you don't have to host all of them -yourself. In this document, we're going to host everything ourselves, so -here's what you need. - -* **lk-jwt**. This authenticates Synapse users to LiveKit. -* **LiveKit**. This is the "SFU", which actually handles the audio and video, and does TURN. -* **Element Call widget**. This is basically the webapplication, the user interface. - -As mentioned in the [checklist](../checklist.md) you need to define these -three entries in DNS and get certificates for them: - -* `turn.example.com` -* `livekit.example.com` -* `call.example.com` - -You may already have DNS and TLS for `turn.example.com`, as it is also used -for [coturn](../coturn). - -For more inspiraten, check https://sspaeth.de/2024/11/sfu/ - - -# LiveKit {#livekit} - -The actual SFU, Selective Forwarding Unit, is LiveKit; this is the part that -handles the audio and video feeds and also does TURN (this TURN-functionality -does not support the legacy calls, you'll need [coturn](coturn) for that). - -Downloading and installing is easy: download the [binary from -Github](https://github.com/livekit/livekit/releases/download/v1.8.0/livekit_1.8.0_linux_amd64.tar.gz) - to /usr/local/bin, chown it to root:root and you're done. - -The quickest way to do precisely that, is to run the script: - -``` -curl -sSL https://get.livekit.io | bash -``` - -You can do this as a normal user, it will use sudo to do its job. - -While you're at it, you might consider installing the cli tool as well, you -can use it -for example- to generate tokens so you can [test LiveKit's -connectivity](https://livekit.io/connection-test): - -``` -curl -sSL https://get.livekit.io/cli | bash -``` - -Configuring LiveKit is [documented -here](https://docs.livekit.io/home/self-hosting/deployment/). We're going to -run LiveKit under authorization of user `turnserver`, the same users we use -for [coturn](coturn). This user is created when installing coturn, so if you -haven't installed that, you should create the user yourself: - -``` -adduser --system turnserver -``` - -## Configure {#keysecret} - -Start by creating a key and secret: - -``` -livekit-server generate-keys -``` - -This key and secret have to be fed to lk-jwt-service too, [see here](#jwtconfig). -Create the directory for LiveKit's configuration: - -``` -mkdir /etc/livekit -chown root:turnserver /etc/livekit -chmod 750 /etc/livekit -``` - -Create a configuration file for livekit, `/etc/livekit/livekit.yaml`: - -``` -port: 7880 -bind_addresses: - - ::1 -rtc: - tcp_port: 7881 - port_range_start: 50000 - port_range_end: 60000 - use_external_ip: true - enable_loopback_candidate: false -turn: - enabled: true - domain: livekit.example.com - cert_file: /etc/coturn/ssl/fullchain.pem - key_file: /etc/coturn/ssl/privkey.pem - tls_port: 5349 - udp_port: 3478 - external_tls: true -keys: - # KEY: SECRET were generated by "livekit-server generate-keys" - : -``` - -Being a bit paranoid: make sure LiveKit can only read this file, not write it: - -``` -chown root:turnserver /etc/livekit/livekit.yaml -chmod 640 /etc/livekit/livekit.yaml -``` - -Port `7880` is forwarded by nginx: authentication is also done there, and that -bit has to be forwarded to `lk-jwt-service` on port `8080`. Therefore, we -listen only on localhost. - -The TURN ports are the normal, default ones. If you also use coturn, make sure -it doesn't use the same ports as LiveKit. Also, make sure you open the correct -ports in the [firewall](../firewall). - - -## TLS certificate - -The TLS-certificate files are not in the usual place under -`/etc/letsencrypt/live`, see [DNS and -certificate](../coturn/README.md#dnscert) under coturn why that is. - -As stated before, we use the same user as for coturn. Because this user does -not have the permission to read private keys under `/etc/letsencrypt`, we copy -those files to a place where it can read them. For coturn we copy them to -`/etc/coturn/ssl`, and if you use coturn and have this directory, LiveKit can -read them there too. - -If you don't have coturn installed, you should create a directory under -`/etc/livekit` and copy the files to there. Modify the `livekit.yaml` file and -the [script to copy the files](../coturn/README.md#fixssl) to use that -directory. Don't forget to update the `renew_hook` in Letsencrypt if you do. - -The LiveKit API listens on localhost, IPv6, port 7880. Traffic to this port is -forwarded from port 443 by nginx, which handles TLS, so it shouldn't be reachable -from the outside world. - -See [LiveKit's config documentation](https://github.com/livekit/livekit/blob/master/config-sample.yaml) -for more options. - - -## Systemd - -Now define a systemd servicefile, like this: - -``` -[Unit] -Description=LiveKit Server -After=network.target -Documentation=https://docs.livekit.io - -[Service] -User=turnserver -Group=turnserver -LimitNOFILE=500000 -Restart=on-failure -WorkingDirectory=/etc/livekit -ExecStart=/usr/local/bin/livekit-server --config /etc/livekit/livekit.yaml - -[Install] -WantedBy=multi-user.target -``` - -Enable and start it. - -Clients don't know about LiveKit yet, you'll have to give them the information -via the `.well-known/matrix/client`: add this bit to it to point them at the -SFU: - -``` -"org.matrix.msc4143.rtc_foci": [ - { - "type": "livekit", - "livekit_service_url": "https://livekit.example.com" - } - ] -``` - -Make sure it is served as `application/json`, just like the other .well-known -files. - - -# lk-jwt-service {#lkjwt} - -lk-jwt-service is a small Go program that handles authorization tokens for use with LiveKit. -You'll need a Go compiler, but the one Debian provides is too old (at the time -of writing this, at least), so we'll install the latest one manually. Check -[the Go website](https://go.dev/dl/) to see which version is the latest, at -the time of writing it's 1.23.3, so we'll install that: - -``` -wget https://go.dev/dl/go1.23.3.linux-amd64.tar.gz -tar xvfz go1.23.3.linux-amd64.tar.gz -cd go/bin -export PATH=`pwd`:$PATH -cd -``` - -This means you now have the latest Go compiler in your path, but it's not -installed system-wide. If you want that, copy the whole `go` directory to -`/usr/local` and add `/usr/local/go/bin` to everybody's $PATH. - -Get the latest lk-jwt-service source code and comile it (preferably *NOT* as root): - -``` -git clone https://github.com/element-hq/lk-jwt-service.git -cd lk-jwt-service -go build -o lk-jwt-service -``` - -Now, compile: - -``` -cd lk-jwt-service -go build -o lk-jwt-service -``` - -Copy and chown the binary to `/usr/local/sbin` (yes: as root): - -``` -cp ~user/lk-jwt-service/lk-jwt-service /usr/local/sbin -chown root:root /usr/local/sbin/lk-jwt-service -``` - - -## Systemd - -Create a service file for systemd, something like this: - -``` -# This thing does authorization for Element Call - -[Unit] -Description=LiveKit JWT Service -After=network.target - -[Service] -Restart=always -User=www-data -Group=www-data -WorkingDirectory=/etc/lk-jwt-service -EnvironmentFile=/etc/lk-jwt-service/config -ExecStart=/usr/local/sbin/lk-jwt-service - -[Install] -WantedBy=multi-user.target -``` - -## Configuration {#jwtconfig} - -We read the options from `/etc/lk-jwt-service/config`, -which we make read-only for group `www-data` and non-accessible by anyone -else. - -``` -mkdir /etc/lk-jwt-service -vi /etc/lk-jwt-service/config -chgrp -R root:www-data /etc/lk-jwt-service -chmod 750 /etc/lk-jwt-service -``` - -This is what you should put into that config file, -`/etc/lk-jwt-service/config`. The `LIVEKIT_SECRET` and `LIVEKIT_KEY` are the -ones you created while [configuring LiveKit](#keysecret). - -``` -LIVEKIT_URL=wss://livekit.example.com -LIVEKIT_SECRET=xxx -LIVEKIT_KEY=xxx -LK_JWT_PORT=8080 -``` - -Change the permission accordingly: - -``` -chown root:www-data /etc/lk-jwt-service/config -chmod 640 /etc/lk-jwt-service/config -``` - -Now enable and start this thing: - -``` -systemctl enable --now lk-jwt-service -``` - - -# Element Call widget {#widget} - -This is a Node.js thingy, so start by installing yarn. Unfortunately both npm -and `yarnpkg` in Debian are antique, so we need to update them after installation. -Install Node.js and upgrade everything. Do not do this as root, we'll only -need to "compile" Element Call once. - -See [the Node.js -website](https://nodejs.org/en/download/package-manager/current) for -instructions. - - -``` -curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash -``` - -Exit and login again to set some environment variables (yes, the installation -changes .bashrc). Then install and upgrade: - -``` -nvm install 23 -sudo apt install yarnpkg -/usr/share/nodejs/yarn/bin/yarn set version stable -/usr/share/nodejs/yarn/bin/yarn install -``` - -Yes, this whole Node.js, yarn and npm thing is a mess. Better documentation -could be written, but for now this will have to do. - -Now clone the Element Call repository and "compile" stuff (again: not as -root): - -``` -git clone https://github.com/element-hq/element-call.git -cd element-call -/usr/share/nodejs/yarn/bin/yarn -/usr/share/nodejs/yarn/bin/yarn build -``` - -If it successfully compiles (warnings are more or less ok, errors aren't), you will -find the whole shebang under "dist". Copy that to `/var/www/element-call` and point -nginx to it ([see nginx](../nginx#callwidget)). - - -## Configuring - -It needs a tiny bit of configuring. The default configuration under `config/config.sample.json` -is a good place to start, copy it to `/etc/element-call` and change where -necessary: - -``` -{ - "default_server_config": { - "m.homeserver": { - "base_url": "https://matrix.example.com", - "server_name": "example.com" - } - }, - - "livekit": { - "livekit_service_url": "https://livekit.example.com" - }, - - "features": { - "feature_use_device_session_member_events": true - }, - - "eula": "https://www.example.com/online-EULA.pdf" -} -``` - -Now tell the clients about this widget. Create -`.well-known/element/element.json`, which is opened by Element Web, Element Desktop -and ElementX to find the Element Call widget. It should look this: - -``` -{ - "call": { - "widget_url": "https://call.example.com" - } -} -``` - diff --git a/matrix/element-call/element.json b/matrix/element-call/element.json deleted file mode 100644 index 78857259..00000000 --- a/matrix/element-call/element.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "call": - { - "widget_url": "https://call.example.com" - } -} diff --git a/matrix/element-web/README.md b/matrix/element-web/README.md deleted file mode 100644 index f3dbfeed..00000000 --- a/matrix/element-web/README.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -gitea: none -include_toc: true ---- - -# Element-web - -Element-web is the webinterface, Element in a browser. You'll find the source -and [documentation on installing and -configuring](https://github.com/element-hq/element-web/blob/develop/docs/install.md) -on Github. - -You should never run Element-web on the same FQDN as your Synapse-server, -because of XSS problems. So start by defining a new FQDN for where you will -publish Element-web, and get a certificate for that (don't forget to -[automatically reload nginx after the certificate renewal](../nginx/README.md#certrenew)). - -We'll use `element.example.com` here. - - -# Installing on Debian {#debian} - -Installing it on Debian is very easy indeed: - -``` -wget -O /usr/share/keyrings/element-io-archive-keyring.gpg https://packages.element.io/debian/element-io-archive-keyring.gpg -echo "deb [signed-by=/usr/share/keyrings/element-io-archive-keyring.gpg] https://packages.element.io/debian/ default main" | - tee /etc/apt/sources.list.d/element-io.list -apt update -apt install element-web -``` - - -# Configuration {#configuration} - -Configuring is done in `config.json`, which needs to go into `/etc/element-web` -in a Debian install. See the [documentation on -Github](https://github.com/element-hq/element-web/blob/develop/docs/config.md). - -The most important thing to change is the `default_server_config`. Make sure -it's something like this: - -``` -"default_server_config": { - "m.homeserver": { - "base_url": "https://matrix.example.com", - "server_name": "example.com" - } -}, -``` - -Of course, substitute the correct domain and server name. - - -# Browser notes {#browsernotes} - -Element-web runs in the browser, on JavaScript. Yours truly found out that -running [JShelter](https://jshelter.org/) throws a spanner in the works, so -you'll have to disable it for the URL you publish Element-web. - -Also, Element-web is rather dependent on the version of your browser, so make -sure you keep yours up-to-date. Debian users, who run "Firefox ESR" should -know support for that is on a best effort basis, you might want to consider -using the "real" Firefox. [Debian packages are -available](https://support.mozilla.org/en-US/kb/install-firefox-linux#w_install-firefox-deb-package-for-debian-based-distributions-recommended). - -Element Web uses "workers", that are not installed in private windows. One -thing that won't work in a private window, is downloading (i.e. displaying) -images. If you don't see avatars and get "failed to download" messages, check -if you're running Element Web in a private window. diff --git a/matrix/firewall/README.md b/matrix/firewall/README.md deleted file mode 100644 index 9e1ba33b..00000000 --- a/matrix/firewall/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# Firewall - -Several ports need to be opened in the firewall, this is a list of all ports -that are needed by the components we describe in this document. - -Those for nginx are necessary for Synapse to work, the ones for coturn and -LiveKit only need to be opened if you run those servers. - - -| Port(s) / range | IP version | Protocol | Application | -| :-------------: | :--------: | :------: | :--------------------- | -| 80, 443 | IPv4/IPv6 | TCP | nginx, reverse proxy | -| 8443 | IPv4/IPv6 | TCP | nginx, federation | -| 3478 | IPv4 | UDP | LiveKit TURN | -| 5349 | IPv4 | TCP | LiveKit TURN TLS | -| 7881 | IPv4/IPv6 | TCP | LiveKit RTC | -| 50000-60000 | IPv4/IPv6 | TCP/UDP | LiveKit RTC | -| 3480 | IPv4 | TCP/UDP | coturn TURN | -| 5351 | IPv4 | TCP/UDP | coturn TURN TLS | -| 40000-49999 | IPv4 | TCP/UDP | coturn RTC | - - -The ports necessary for TURN depend very much on the specific configuration of -[coturn](../coturn#configuration) and/or [LiveKit](../element-call#livekit). - diff --git a/matrix/nginx/README.md b/matrix/nginx/README.md deleted file mode 100644 index ceef1634..00000000 --- a/matrix/nginx/README.md +++ /dev/null @@ -1,365 +0,0 @@ ---- -gitea: none -include_toc: true ---- - -# Reverse proxy with nginx - -Clients connecting from the Internet to our Matrix environment will usually -use SSL/TLS to encrypt whatever they want to send. This is one thing that -nginx does better than Synapse. - -Furthermore, granting or denying access to specific endpoints is much easier -in nginx. - -Synapse listens only on localhost, so nginx has to pass connections on from -the wild west that is the Internet to our server listening on the inside. - - -# Installing - -Installing nginx and the [Let's Encrypt](https://letsencrypt.org/) plugin is -easy: - -``` -apt install nginx python3-certbot-nginx -``` - -Get your certificate for the base domain (which is probably not the machine on which -we're going to run Synapse): - -``` -certbot certonly --nginx --agree-tos -m system@example.com --non-interactive -d example.com -``` - -Get one for the machine on which we are going to run Synapse too: - -``` -certbot certonly --nginx --agree-tos -m system@example.com --non-interactive -d matrix.example.com -``` - -Substitute the correct e-mailaddress and FQDN, or course. - - -## Automatic renewal {#certrenew} - -Certificates have a limited lifetime, and need to be updated every once in a -while. This should be done automatically by Certbot, see if `systemctl -list-timers` lists `certbot.timer`. - -However, renewing the certificate means you'll have to restart the software -that's using it. We have 2 or 3 pieces of software that use certificates: -[coturn](../coturn) and/or [LiveKit](../element-call#livekit), and [nginx](../nginx). - -Coturn/LiveKit are special with regards to the certificate, see their -respective pages. For nginx it's pretty easy: tell Letsencrypt to restart it -after a renewal. - -You do this by adding this line to the `[renewalparams]` in -`/etc/letsencrypt/renewal/.conf`: - -``` -renew_hook = systemctl try-reload-or-restart nginx -``` - - -# Configuration of domain name {#configdomain} - -Let's start with the configuration on the webserver that runs on the domain -name itself, in this case `example.com`. - -Almost all traffic should be encrypted, so a redirect from http to https seems -like a good idea. - -However, `.well-known/matrix/client` has to be available via http and https, -so that should *NOT* be redirected to https. Some clients don't understand the -redirect and will therefore not find the server if you redirect everything. - -Under the `server_name` (the "domain name", the part after the username) you -will need a configuration like this: - -``` -server { - listen 80; - listen [::]:80; - listen 443 ssl; - listen [::]:443 ssl; - - ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; - include /etc/letsencrypt/options-ssl-nginx.conf; - ssl_dhparam /etc/ssl/dhparams.pem; - - server_name example.com; - - location /.well-known/matrix/client { - return 200 '{ - "m.homeserver": {"base_url": "https://matrix.example.com"}, - }'; - default_type application/json; - } - - location /.well-known/matrix/server { - return 200 '{"m.server": "matrix.example.com"}'; - default_type application/json; - } - - location / { - if ($scheme = http) { - return 301 https://$host$request_uri; - } - } - - access_log /var/log/nginx/example_com-access.log; - error_log /var/log/nginx/example_com-error.log; - -} -``` - -This defines a server that listens on both http and https. It hands out two -.well-known entries over both http and https, and every other request over -http is forwarded to https. - -Be sure to substitute the correct values for `server_name`, `base_url` and the -certificate files (and [renew the certificate](#renewcert)). - -See this [full configuration example](domain.conf) with some extra stuff. - - -# Configuration of the reverse proxy - -For the actual proxy in front of Synapse, this is what you need: forward ports -443 and 8448 to Synapse, listening on localhost, and add a few headers so -Synapse know's who's on the other side of the line. - -``` -server { - listen 443 ssl; - listen [::]:443 ssl; - - # For the federation port - listen 8448 ssl default_server; - listen [::]:8448 ssl default_server; - - ssl_certificate /etc/letsencrypt/live/matrix.example.com/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/matrix.example.com/privkey.pem; - include /etc/letsencrypt/options-ssl-nginx.conf; - ssl_dhparam /etc/ssl/dhparams.pem; - - server_name matrix.example.com; - - location ~ ^(/_matrix|/_synapse/client) { - proxy_pass http://localhost:8008; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header Host $host; - client_max_body_size 50M; - proxy_http_version 1.1; - } - -} -``` - -Again, substitute the correct values. Don't forget to open the relevant ports -in the firewall. Ports 80 and 443 may already be open, 8448 is probably not. - -This is a very, very basic configuration; just enough to give us a working -service. See this [complete example](revproxy.conf) which also includes -[Draupnir](../draupnir) and a protected admin endpoint. - -# Element Web - -You can host the webclient on a different machine, but we'll run it on the -same one in this documentation. You do need a different FQDN however, you -can't host it under the same name as Synapse, such as: -``` -https://matrix.example.com/element-web -``` -So you'll need to create an entry in DNS and get a TLS-certificate for it (as -mentioned in the [checklist](../checklist.md)). - -Other than that, configuration is quite simple. We'll listen on both http and -https, and redirect http to https: - -``` -server { - listen 80; - listen [::]:80; - listen 443 ssl http2; - listen [::]:443 ssl http2; - - ssl_certificate /etc/letsencrypt/live/element.example.com/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/element.example.com/privkey.pem; - include /etc/letsencrypt/options-ssl-nginx.conf; - ssl_dhparam /etc/ssl/dhparams.pem; - - server_name element.example.com; - - location / { - if ($scheme = http) { - return 301 https://$host$request_uri; - } - add_header X-Frame-Options SAMEORIGIN; - add_header X-Content-Type-Options nosniff; - add_header X-XSS-Protection "1; mode=block"; - add_header Content-Security-Policy "frame-ancestors 'self'"; - } - - root /usr/share/element-web; - index index.html; - - access_log /var/log/nginx/elementweb-access.log; - error_log /var/log/nginx/elementweb-error.log; -} -``` - -This assumes Element Web is installed under `/usr/share/element-web`, as done -by the Debian package provided by Element.io. - -# Synapse-admin {#synapse-admin} - -If you also [install Synapse-Admin](../synapse-admin), you'll want to create -another vhost, something like this: - -``` -server { - listen 443 ssl; - listen [::]:443 ssl; - - ssl_certificate /etc/letsencrypt/live/admin.example.com/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/admin.example.com/privkey.pem; - include /etc/letsencrypt/options-ssl-nginx.conf; - ssl_dhparam /etc/ssl/dhparams.pem; - - server_name admin.example.com; - - root /var/www/synapse-admin; - - access_log /var/log/nginx/admin-access.log; - error_log /var/log/nginx/admin-error.log; -} -``` - -You'll need an SSL certificate for this, of course. But you'll also need to -give it access to the `/_synapse/admin` endpoint in Synapse. - -You don't want this endpoint to be available for just anybody on the Internet, -so restrict access to the IP-addresses from which you expect to use -Synapse-Admin. - -In `/etc/nginx/sites-available/synapse` you want to add this bit: - -``` -location ~ ^/_synapse/admin { - allow 127.0.0.1; - allow ::1; - allow 111.222.111.222; - allow dead:beef::/64; - deny all; - - proxy_pass http://localhost:8008; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header Host $host; - client_max_body_size 50M; - proxy_http_version 1.1; -} -``` - -This means access to `/_synapse/admin` is only allowed for the addresses -mentioned, but will be forwarded to Synapse in exactly the same way as -"normal" requests. - - -# LiveKit {#livekit} - -If you run an SFU for Element Call, you need a virtual host for LiveKit. Make -sure you install, configure and run [Element Call LiveKit](../element-call#livekit). -Then create a virtual host much like this: - -``` -server { - listen 443 ssl; - listen [::]:443 ssl; - - ssl_certificate /etc/letsencrypt/live/livekit.example.com/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/livekit.example.com/privkey.pem; - include /etc/letsencrypt/options-ssl-nginx.conf; - ssl_dhparam /etc/ssl/dhparams.pem; - - server_name livekit.example.com; - - # This is lk-jwt-service - location ~ ^(/sfu/get|/healthz) { - proxy_pass http://[::1]:8080; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-Server $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } - - location / { - proxy_pass http://[::1]:7880; - proxy_set_header Connection "upgrade"; - proxy_set_header Upgrade $http_upgrade; - - proxy_set_header Host $host; - proxy_set_header X-Forwarded-Server $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } - - access_log /var/log/nginx/livekit-access.log; - error_log /var/log/nginx/livekit-error.log; -} -``` - - -# Element Call widget {#callwidget} - -If you self-host the [Element Call widget](../element-call#widget), this -should be the configuration to publish that: - -``` -server { - listen 443 ssl; - listen [::]:443 ssl; - - ssl_certificate /etc/letsencrypt/live/call.example.com/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/call.example.com/privkey.pem; - include /etc/letsencrypt/options-ssl-nginx.conf; - ssl_dhparam /etc/ssl/dhparams.pem; - - server_name call.example.com; - - root /var/www/element-call; - - location /assets { - add_header Cache-Control "public, immutable, max-age=31536000"; - } - - location /apple-app-site-association { - default_type application/json; - } - - location /^config.json$ { - alias public/config.json; - default_type application/json; - } - - location / { - try_files $uri /$uri /index.html; - add_header Cache-Control "public, max-age=30, stale-while-revalidate=30"; - } - - access_log /var/log/nginx/call-access.log; - error_log /var/log/nginx/call-error.log; -} -``` - - -# Firewall - -For normal use, at least ports 80 and 443 must be openend, see [Firewall](../firewall). diff --git a/matrix/nginx/conf/call.conf b/matrix/nginx/conf/call.conf deleted file mode 100644 index 2c75bc26..00000000 --- a/matrix/nginx/conf/call.conf +++ /dev/null @@ -1,34 +0,0 @@ -server { - listen 443 ssl; - listen [::]:443 ssl; - - ssl_certificate /etc/letsencrypt/live/call.example.com/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/call.example.com/privkey.pem; - include /etc/letsencrypt/options-ssl-nginx.conf; - ssl_dhparam /etc/ssl/dhparams.pem; - - server_name call.example.com; - - root /var/www/element-call; - - location /assets { - add_header Cache-Control "public, immutable, max-age=31536000"; - } - - location /apple-app-site-association { - default_type application/json; - } - - location /^config.json$ { - alias public/config.json; - default_type application/json; - } - - location / { - try_files $uri /$uri /index.html; - add_header Cache-Control "public, max-age=30, stale-while-revalidate=30"; - } - - access_log /var/log/nginx/call-access.log; - error_log /var/log/nginx/call-error.log; -} diff --git a/matrix/nginx/conf/domain.conf b/matrix/nginx/conf/domain.conf deleted file mode 100644 index ba83bd9f..00000000 --- a/matrix/nginx/conf/domain.conf +++ /dev/null @@ -1,61 +0,0 @@ -server { - listen 80; - listen [::]:80; - listen 443 ssl; - listen [::]:443 ssl; - - ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; - include /etc/letsencrypt/options-ssl-nginx.conf; - ssl_dhparam /etc/ssl/dhparams.pem; - - server_name example.com; - - location /.well-known/matrix/client { - return 200 '{ - "m.homeserver": {"base_url": "https://matrix.example.com"}, - "org.matrix.msc3575.proxy": {"url": "https://matrix.example.com"}, - "org.matrix.msc4143.rtc_foci":[ - {"type": "livekit", - "livekit_service_url": "https://livekit.example.com"} - ] - }'; - default_type application/json; - add_header 'Access-Control-Allow-Origin' '*'; - } - - location /.well-known/matrix/server { - return 200 '{"m.server": "matrix.example.com"}'; - default_type application/json; - } - - location /.well-known/matrix/support { - return 200 '{ "contacts": - [ - { "email_address": "admin@example.com", - "matrix_id": "@admin:example.com", - "role": "m.role.admin" }, - { "email_address": "security@example.com", - "matrix_id": "@john:example.com", - "role": "m.role.security" } - ], - "support_page": "https://www.example.com/matrix-support" - }'; - default_type application/json; - } - - - location /.well-known/element/element.json { - return 200 '{"call": {"widget_url": "https://call.example.com"}}'; - default_type application/json; - } - - location / { - if ($scheme = http) { - return 301 https://$host$request_uri; - } - } - - access_log /var/log/nginx/example-access.log; - error_log /var/log/nginx/example-error.log; -} diff --git a/matrix/nginx/conf/elementweb.conf b/matrix/nginx/conf/elementweb.conf deleted file mode 100644 index e89cd831..00000000 --- a/matrix/nginx/conf/elementweb.conf +++ /dev/null @@ -1,29 +0,0 @@ -server { - listen 80; - listen [::]:80; - listen 443 ssl http2; - listen [::]:443 ssl http2; - - ssl_certificate /etc/letsencrypt/live/element.example.com/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/element.example.com/privkey.pem; - include /etc/letsencrypt/options-ssl-nginx.conf; - ssl_dhparam /etc/ssl/dhparams.pem; - - server_name element.example.com; - - location / { - if ($scheme = http) { - return 301 https://$host$request_uri; - } - add_header X-Frame-Options SAMEORIGIN; - add_header X-Content-Type-Options nosniff; - add_header X-XSS-Protection "1; mode=block"; - add_header Content-Security-Policy "frame-ancestors 'self'"; - } - - root /usr/share/element-web; - index index.html; - - access_log /var/log/nginx/elementweb-access.log; - error_log /var/log/nginx/elementweb-error.log; -} diff --git a/matrix/nginx/conf/livekit.conf b/matrix/nginx/conf/livekit.conf deleted file mode 100644 index 9f0b3b15..00000000 --- a/matrix/nginx/conf/livekit.conf +++ /dev/null @@ -1,37 +0,0 @@ -server { - listen 443 ssl; - listen [::]:443 ssl; - - ssl_certificate /etc/letsencrypt/live/livekit.example.com/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/livekit.example.com/privkey.pem; - include /etc/letsencrypt/options-ssl-nginx.conf; - ssl_dhparam /etc/ssl/dhparams.pem; - - server_name livekit.example.com; - - # This is lk-jwt-service - location ~ ^(/sfu/get|/healthz) { - proxy_pass http://[::1]:8080; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-Server $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } - - location / { - proxy_pass http://[::1]:7880; - proxy_set_header Connection "upgrade"; - proxy_set_header Upgrade $http_upgrade; - #add_header Access-Control-Allow-Origin "*" always; - - proxy_set_header Host $host; - proxy_set_header X-Forwarded-Server $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } - - access_log /var/log/nginx/livekit-access.log; - error_log /var/log/nginx/livekit-error.log; -} diff --git a/matrix/nginx/conf/revproxy.conf b/matrix/nginx/conf/revproxy.conf deleted file mode 100644 index 277a436d..00000000 --- a/matrix/nginx/conf/revproxy.conf +++ /dev/null @@ -1,85 +0,0 @@ -server { - listen 443 ssl; - listen [::]:443 ssl; - - # For the federation port - listen 8448 ssl; - listen [::]:8448 ssl; - - ssl_certificate /etc/letsencrypt/live/matrix.example.com/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/matrix.example.com/privkey.pem; - include /etc/letsencrypt/options-ssl-nginx.conf; - ssl_dhparam /etc/ssl/dhparams.pem; - - server_name matrix.example.com; - - # Abuse reports get forwarded to Draupnir, listening on port 8082 - location ~ ^/_matrix/client/(r0|v3)/rooms/([^/]*)/report/(.*)$ { - # The r0 endpoint is deprecated but still used by many clients. - # As of this writing, the v3 endpoint is the up-to-date version. - - # Alias the regexps, to ensure that they're not rewritten. - set $room_id $2; - set $event_id $3; - proxy_pass http://[::1]:8082/api/1/report/$room_id/$event_id; - } - - # Reports that need to reach Synapse (not really sure if this is used) - location /_synapse/admin/v1/event_reports { - proxy_pass http://localhost:8008; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header Host $host; - client_max_body_size 50M; - proxy_http_version 1.1; - } - location ~ ^/_synapse/admin/v1/rooms/([^/]*)/context/(.*)$ { - set $room_id $2; - set $event_id $3; - proxy_pass http://localhost:8008/_synapse/admin/v1/rooms/$room_id/context/$event_id; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header Host $host; - client_max_body_size 50M; - proxy_http_version 1.1; - } - - # If you want the server version to be public: - location ~ ^/_synapse/admin/v1/server_version$ { - proxy_pass http://localhost:8008; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header Host $host; - client_max_body_size 50M; - proxy_http_version 1.1; - } - - # The rest of the admin endpoint shouldn't be public - location ~ ^/_synapse/admin { - allow 127.0.0.1; - allow ::1; - allow 111.222.111.222; - allow dead:beef::/48; - deny all; - - proxy_pass http://localhost:8008; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header Host $host; - client_max_body_size 50M; - proxy_http_version 1.1; - } - - location ~ ^(/_matrix|/_synapse/client) { - proxy_pass http://localhost:8008; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header Host $host; - client_max_body_size 50M; - proxy_http_version 1.1; - } - - access_log /var/log/nginx/matrix-access.log; - error_log /var/log/nginx/matrix-error.log; -} - diff --git a/matrix/nginx/conf/synapse-admin.conf b/matrix/nginx/conf/synapse-admin.conf deleted file mode 100644 index a1ad40da..00000000 --- a/matrix/nginx/conf/synapse-admin.conf +++ /dev/null @@ -1,16 +0,0 @@ -server { - listen 443 ssl; - listen [::]:443 ssl; - - ssl_certificate /etc/letsencrypt/live/admin.example.com/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/admin.example.com/privkey.pem; - include /etc/letsencrypt/options-ssl-nginx.conf; - ssl_dhparam /etc/ssl/dhparams.pem; - - server_name admin.example.com; - - root /var/www/synapse-admin; - - access_log /var/log/nginx/admin-access.log; - error_log /var/log/nginx/admin-error.log; -} diff --git a/matrix/nginx/workers/README.md b/matrix/nginx/workers/README.md deleted file mode 100644 index 659f3761..00000000 --- a/matrix/nginx/workers/README.md +++ /dev/null @@ -1,397 +0,0 @@ ---- -gitea: none -include_toc: true ---- - -# Reverse proxy for Synapse with workers - -Changing nginx's configuration from a reverse proxy for a normal, monolithic -Synapse to one for a Synapse that uses workers, is a big thing: quite a lot has to -be changed. - -As mentioned in [Synapse with workers](../../synapse/workers/README.md#synapse), -we're changing the "backend" from network sockets to UNIX sockets. - -Because we're going to have to forward a lot of specific requests to all kinds -of workers, we'll split the configuration into a few bits: - -* all `proxy_forward` settings -* all `location` definitions -* maps that define variables -* upstreams that point to the correct socket(s) with the correct settings -* settings for private access -* connection optimizations - -Some of these go into `/etc/nginx/conf.d` because they are part of the -configuration of nginx itself, others go into `/etc/nginx/snippets` because we -need to include them several times in different places. - -**Important consideration** - -This part isn't a quick "put these files in place and you're done": a -worker-based Synapse is tailor-made, there's no one-size-fits-all. This -documentation gives hints and examples, but in the end it's you who has to -decide what types of workers to use and how many, all depending on your -specific use case and the available hardware. - - - - -# Optimizations - -In the quest for speed, we are going to tweak several settings in nginx. To -keep things manageable, most of those tweaks go into separate configuration -files that are either automatically included (those under `/etc/nginx/conf.d`) -or explicitly where we need them (those under `/etc/nginx/snippets`). - -Let's start with a few settings that affect nginx as a whole. Edit these -options in `/etc/nginx/nginx.conf`: - -``` -pcre_jit on; -worker_rlimit_nofile 8192; -worker_connections 4096; -multi_accept off; -gzip_comp_level 2; -gzip_types application/javascript application/json application/x-javascript application/xml application/xml+rss image/svg+xml text/css text/javascript text/plain text/xml; -gzip_min_length 1000; -gzip_disable "MSIE [1-6]\."; -``` - -We're going to use lots of regular expressions in our config, `pcre_jit on` -speeds those up considerably. Workers get 8K open files, and we want 4096 -workers instead of the default 768. Workers can only accept one connection, -which is (in almost every case) proxy_forwarded, so we set `multi_accept off`. - -We change `gzip_comp_level` from 6 to 2, we expand the list of content that is -to be gzipped, and don't zip anything shorter than 1000 characters, instead of -the default 20. MSIE can take a hike... - -These are tweaks for the connection, save this in `/etc/ngnix/conf.d/conn_optimize.conf`. - -``` -client_body_buffer_size 32m; -client_header_buffer_size 32k; -client_max_body_size 1g; -http2_max_concurrent_streams 128; -keepalive_timeout 65; -keepalive_requests 100; -large_client_header_buffers 4 16k; -server_names_hash_bucket_size 128; -tcp_nodelay on; -server_tokens off; -``` - -We set a few proxy settings that we use in proxy_forwards other than to our -workers, save this to `conf.d/proxy_optimize.conf`: - -``` -proxy_buffer_size 128k; -proxy_buffers 4 256k; -proxy_busy_buffers_size 256k; -``` - -For every `proxy_forward` to our workers, we want to configure several settings, -and because we don't want to include the same list of settings every time, we put -all of them in one snippet of code, that we can include every time we need it. - -Create `/etc/nginx/snippets/proxy.conf` and put this in it: - -``` -proxy_connect_timeout 2s; -proxy_buffering off; -proxy_http_version 1.1; -proxy_read_timeout 3600s; -proxy_redirect off; -proxy_send_timeout 120s; -proxy_socket_keepalive on; -proxy_ssl_verify off; - -proxy_set_header Accept-Encoding ""; -proxy_set_header Host $host; -proxy_set_header X-Forwarded-For $remote_addr; -proxy_set_header X-Forwarded-Proto $scheme; -proxy_set_header Connection $connection_upgrade; -proxy_set_header Upgrade $http_upgrade; - -client_max_body_size 50M; -``` - -Every time we use a `proxy_forward`, we include this snippet. There are 2 more -things we might set: trusted locations that can use the admin endpoints, and a -dedicated DNS-recursor. We include the `snippets/private.conf` in the -forwards to admin endpoints, so that not the entire Internet can play with it. -The dedicated nameserver is something you really want, because synchronising a -large room can easily result in 100.000+ DNS requests. You'll hit flood -protection on most servers if you do that. - -List the addresses from which you want to allow admin access in -`snippets/private.conf`: - -``` -allow 127.0.0.1; -allow ::1; -allow 12.23.45.78; -allow 87.65.43.21; -allow dead:beef::/48; -allow 2a10:1234:abcd::1; -deny all; -satisfy all; -``` - -Of course, subsitute these random addresses for the ones you trust. The -dedicated nameserver (if you have one, which is strongly recommended) should -be configured in `conf.d/resolver.conf`: - -``` -resolver [::1] 127.0.0.1 valid=60; -resolver_timeout 10s; -``` - - -# Maps {#maps} - -A map sets a variable based on, usually, another variable. One case we use this -is in determining the type of sync a client is doing. A normal sync, simply -updating an existing session, is a rather lightweight operation. An initial sync, -meaning a full sync because the session is brand new, is not so lightweight. - -A normal sync can be recognised by the `since` bit in the request: it tells -the server when its last sync was. If there is no `since`, we're dealing with -an initial sync. - -We want to forward requests for normal syncs to the `normal_sync` workers, and -the initial syncs to the `initial_sync` workers. - -We decide to which type of worker to forward the sync request to by looking at -the presence or absence of `since`: if it's there, it's a normal sync and we -set the variable `$sync` to `normal_sync`. If it's not there, we set `$sync` to -`initial_sync`. The content of `since` is irrelevant for nginx. - -This is what the map looks like: - -``` -map $arg_since $sync { - default normal_sync; - '' initial_sync; -} -``` - -We evaluate `$arg_since` to set `$sync`: `$arg_since` is nginx's variable `$arg_` -followed by `since`, the argument we want. See [the index of -variables in nginx](https://nginx.org/en/docs/varindex.html) for more -variables we can use in nginx. - -By default we set `$sync` to `normal_sync`, unless the argument `since` is -empty (absent); then we set it to `initial_sync`. - -After this mapping, we forward the request to the correct worker like this: - -``` -proxy_pass http://$sync; -``` - -See a complete example of maps in the file [maps.conf](maps.conf). - - -# Upstreams - -In our configuration, nginx is not only a reverse proxy, it's also a load balancer. -Just like what `haproxy` does, it can forward requests to "servers" behind it. -Such a server is the inbound UNIX socket of a worker, and there can be several -of them in one group. - -Let's start with a simple one, the `login` worker, that handles the login -process for clients. There's only one worker, so only one socket: - -``` -upstream login { - server unix:/run/matrix-synapse/inbound_login.sock max_fails=0; - keepalive 10; -} -``` - -Ater this definition, we can forward traffic to `login`. What traffic to -forward is decided in the `location` statements, see further. - -## Synchronisation - -A more complex example are the sync workers. Under [Maps](#Maps) we split sync -requests into two different types; those different types are handled by -different worker pools. In our case we have 2 workers for the initial_sync -requests, and 3 for the normal ones: - -``` -upstream initial_sync { - hash $mxid_localpart consistent; - server unix:/run/matrix-synapse/inbound_initial_sync1.sock max_fails=0; - server unix:/run/matrix-synapse/inbound_initial_sync2.sock max_fails=0; - keepalive 10; -} - -upstream normal_sync { - hash $mxid_localpart consistent; - server unix:/run/matrix-synapse/inbound_normal_sync1.sock max_fails=0; - server unix:/run/matrix-synapse/inbound_normal_sync2.sock max_fails=0; - server unix:/run/matrix-synapse/inbound_normal_sync3.sock max_fails=0; - keepalive 10; -} -``` - -The `hash` bit is to make sure that request from one user are consistently -forwarded to the same worker. We filled the variable `$mxid_localpart` in the -maps. - -## Federation - -Something similar goes for the federation workers. Some requests need to go -to the same worker as all the other requests from the same IP-addres, other -can go to any of these workers. - -We define two upstreams with the same workers, only with different names and -the explicit IP-address ordering for one: - -``` -upstream incoming_federation { - server unix:/run/matrix-synapse/inbound_federation_reader1.sock max_fails=0; - server unix:/run/matrix-synapse/inbound_federation_reader2.sock max_fails=0; - server unix:/run/matrix-synapse/inbound_federation_reader3.sock max_fails=0; - server unix:/run/matrix-synapse/inbound_federation_reader4.sock max_fails=0; - keepalive 10; -} - -upstream federation_requests { - hash $remote_addr consistent; - server unix:/run/matrix-synapse/inbound_federation_reader1.sock max_fails=0; - server unix:/run/matrix-synapse/inbound_federation_reader2.sock max_fails=0; - server unix:/run/matrix-synapse/inbound_federation_reader3.sock max_fails=0; - server unix:/run/matrix-synapse/inbound_federation_reader4.sock max_fails=0; - keepalive 10; -} -``` - -Same workers, different handling. See how we forward requests in the next -paragraph. - -See [upstreams.conf](upstreams.conf) for a complete example. - - -# Locations - -Now that we have defined the workers and/or worker pools, we have to forward -the right traffic to the right workers. The Synapse documentation about -[available worker -types](https://element-hq.github.io/synapse/latest/workers.html#available-worker-applications) -lists which endpoints a specific worker type can handle. - -## Login - -Let's forward login requests to our login worker. The [documentation for the -generic_worker](https://element-hq.github.io/synapse/latest/workers.html#synapseappgeneric_worker) -says these endpoints are for registration and login: - -``` -# Registration/login requests -^/_matrix/client/(api/v1|r0|v3|unstable)/login$ -^/_matrix/client/(r0|v3|unstable)/register$ -^/_matrix/client/(r0|v3|unstable)/register/available$ -^/_matrix/client/v1/register/m.login.registration_token/validity$ -^/_matrix/client/(r0|v3|unstable)/password_policy$ -``` - -We forward that to our worker with this `location` definition, using the -`proxy_forward` settings we defined earlier: - -``` -location ~ ^(/_matrix/client/(api/v1|r0|v3|unstable)/login|/_matrix/client/(r0|v3|unstable)/register|/_matrix/client/(r0|v3|unstable)/register/available|/_matrix/client/v1/register/m.login.registration_token/validity|/_matrix/client/(r0|v3|unstable)/password_policy)$ { - include snippets/proxy.conf; - proxy_pass http://login; -} -``` - -## Synchronisation - -The docs say that the `generic_worker` can handle these requests for synchronisation -requests: - -``` -# Sync requests -^/_matrix/client/(r0|v3)/sync$ -^/_matrix/client/(api/v1|r0|v3)/events$ -^/_matrix/client/(api/v1|r0|v3)/initialSync$ -^/_matrix/client/(api/v1|r0|v3)/rooms/[^/]+/initialSync$ -``` - -We forward those to our 2 worker pools making sure the heavy initial syncs go -to the `initial_sync` pool, and the normal ones to `normal_sync`. We use the -variable `$sync`for that, which we defined in maps.conf. - -``` -# Normal/initial sync -location ~ ^/_matrix/client/(r0|v3)/sync$ { - include snippets/proxy.conf; - proxy_pass http://$sync; -} - -# Normal sync -location ~ ^/_matrix/client/(api/v1|r0|v3)/events$ { - include snippets/proxy.conf; - proxy_pass http://normal_sync; -} - -# Initial sync -location ~ ^(/_matrix/client/(api/v1|r0|v3)/initialSync|/_matrix/client/(api/v1|r0|v3)/rooms/[^/]+/initialSync)$ { - include snippets/proxy.conf; - proxy_pass http://initial_sync; -} -``` - -## Media - -The media worker is slightly different: some parts are public, but a few bits -are admin stuff. We split those, and limit the admin endpoints to the trusted -addresses we defined earlier: - -``` -# Media, public -location ~* ^(/_matrix/((client|federation)/[^/]+/)media/|/_matrix/media/v3/upload/) { - include snippets/proxy.conf; - proxy_pass http://media; -} - -# Media, admin -location ~ ^/_synapse/admin/v1/(purge_)?(media(_cache)?|room|user|quarantine_media|users)/[\s\S]+|media$ { - include snippets/private.conf; - include snippets/proxy.conf; - proxy_pass http://media; -} -``` - -# Federation - -Federation is done by two types of workers: one pool for requests from our -server to the rest of the world, and one pool for everything coming in from the -outside world. Only the latter is relevant for nginx. - -The documentation mentions two different types of federation: -* Federation requests -* Inbound federation transaction request - -The second is special, in that requests for that specific endpoint must be -balanced by IP-address. The "normal" federation requests can be sent to any -worker. We're sending all these requests to the same workers, but we make sure -to always send requests from 1 IP-address to the same worker: - -``` -# Federation readers -location ~ ^(/_matrix/federation/v1/event/|/_matrix/federation/v1/state/|/_matrix/federation/v1/state_ids/|/_matrix/federation/v1/backfill/|/_matrix/federation/v1/get_missing_events/|/_matrix/federation/v1/publicRooms|/_matrix/federation/v1/query/|/_matrix/federation/v1/make_join/|/_matrix/federation/v1/make_leave/|/_matrix/federation/(v1|v2)/send_join/|/_matrix/federation/(v1|v2)/send_leave/|/_matrix/federation/v1/make_knock/|/_matrix/federation/v1/send_knock/|/_matrix/federation/(v1|v2)/invite/|/_matrix/federation/v1/event_auth/|/_matrix/federation/v1/timestamp_to_event/|/_matrix/federation/v1/exchange_third_party_invite/|/_matrix/federation/v1/user/devices/|/_matrix/key/v2/query|/_matrix/federation/v1/hierarchy/) { - include snippets/proxy.conf; - proxy_pass http://incoming_federation; -} -# Inbound federation transactions -location ~ ^/_matrix/federation/v1/send/ { - include snippets/proxy.conf; - proxy_pass http://federation_requests; -} -``` - diff --git a/matrix/nginx/workers/conn_optimizations.conf b/matrix/nginx/workers/conn_optimizations.conf deleted file mode 100644 index 6822bc25..00000000 --- a/matrix/nginx/workers/conn_optimizations.conf +++ /dev/null @@ -1,13 +0,0 @@ -# These settings optimize the connection handling. Store this file under /etc/nginx/conf.d, because -# it should be loaded by default. - -client_body_buffer_size 32m; -client_header_buffer_size 32k; -client_max_body_size 1g; -http2_max_concurrent_streams 128; -keepalive_timeout 65; -keepalive_requests 100; -large_client_header_buffers 4 16k; -server_names_hash_bucket_size 128; -tcp_nodelay on; -server_tokens off; diff --git a/matrix/nginx/workers/locations.conf b/matrix/nginx/workers/locations.conf deleted file mode 100644 index b7adf25c..00000000 --- a/matrix/nginx/workers/locations.conf +++ /dev/null @@ -1,111 +0,0 @@ -# This file describes the forwarding of (almost) every endpoint to a worker or pool of -# workers. This file should go in /etc/nginx/snippets, because we need to load it once, on -# the right place in our site-definition. - -# Account-data -location ~ ^(/_matrix/client/(r0|v3|unstable)/.*/tags|/_matrix/client/(r0|v3|unstable)/.*/account_data) { - include snippets/proxy.conf; - proxy_pass http://account_data; -} - -# Typing -location ~ ^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/typing { - include snippets/proxy.conf; - proxy_pass http://typing; -} - -# Receipts -location ~ ^(/_matrix/client/(r0|v3|unstable)/rooms/.*/receipt|/_matrix/client/(r0|v3|unstable)/rooms/.*/read_markers) { - include snippets/proxy.conf; - proxy_pass http://receipts; -} - -# Presence -location ~ ^/_matrix/client/(api/v1|r0|v3|unstable)/presence/ { - include snippets/proxy.conf; - proxy_pass http://presence; -} - -# To device -location ~ ^/_matrix/client/(r0|v3|unstable)/sendToDevice/ { - include snippets/proxy.conf; - proxy_pass http://todevice; -} - -# Push rules -location ~ ^/_matrix/client/(api/v1|r0|v3|unstable)/pushrules/ { - include snippets/proxy.conf; - proxy_pass http://push_rules; -} - -# Userdir -location ~ ^/_matrix/client/(r0|v3|unstable)/user_directory/search$ { - include snippets/proxy.conf; - proxy_pass http://userdir; -} - -# Media, users1 -location ~* ^/_matrix/((client|federation)/[^/]+/)media/ { - include snippets/proxy.conf; - proxy_pass http://media; -} -# Media, users2 -location ~* ^/_matrix/media/v3/upload { - include snippets/proxy.conf; - proxy_pass http://media; -} - -# Media, admin -location ~ ^/_synapse/admin/v1/(purge_)?(media(_cache)?|room|user|quarantine_media|users)/[\s\S]+|media$ { - include snippets/private.conf; - include snippets/proxy.conf; - proxy_pass http://media; -} - -# Login -location ~ ^(/_matrix/client/(api/v1|r0|v3|unstable)/login|/_matrix/client/(r0|v3|unstable)/register|/_matrix/client/(r0|v3|unstable)/register/available|/_matrix/client/v1/register/m.login.registration_token/validity|/_matrix/client/(r0|v3|unstable)/password_policy)$ { - include snippets/proxy.conf; - proxy_pass http://login; -} - -# Normal/initial sync: -# To which upstream to pass the request depends on the map "$sync" -location ~ ^/_matrix/client/(r0|v3)/sync$ { - include snippets/proxy.conf; - proxy_pass http://$sync; -} -# Normal sync: -# These endpoints are used for normal syncs -location ~ ^/_matrix/client/(api/v1|r0|v3)/events$ { - include snippets/proxy.conf; - proxy_pass http://normal_sync; -} -# Initial sync: -# These endpoints are used for initial syncs -location ~ ^/_matrix/client/(api/v1|r0|v3)/initialSync$ { - include snippets/proxy.conf; - proxy_pass http://initial_sync; -} -location ~ ^/_matrix/client/(api/v1|r0|v3)/rooms/[^/]+/initialSync$ { - include snippets/proxy.conf; - proxy_pass http://initial_sync; -} - -# Federation -# All the "normal" federation stuff: -location ~ ^(/_matrix/federation/v1/event/|/_matrix/federation/v1/state/|/_matrix/federation/v1/state_ids/|/_matrix/federation/v1/backfill/|/_matrix/federation/v1/get_missing_events/|/_matrix/federation/v1/publicRooms|/_matrix/federation/v1/query/|/_matrix/federation/v1/make_join/|/_matrix/federation/v1/make_leave/|/_matrix/federation/(v1|v2)/send_join/|/_matrix/federation/(v1|v2)/send_leave/|/_matrix/federation/v1/make_knock/|/_matrix/federation/v1/send_knock/|/_matrix/federation/(v1|v2)/invite/|/_matrix/federation/v1/event_auth/|/_matrix/federation/v1/timestamp_to_event/|/_matrix/federation/v1/exchange_third_party_invite/|/_matrix/federation/v1/user/devices/|/_matrix/key/v2/query|/_matrix/federation/v1/hierarchy/) { - include snippets/proxy.conf; - proxy_pass http://incoming_federation; -} -# Inbound federation transactions: -location ~ ^/_matrix/federation/v1/send/ { - include snippets/proxy.conf; - proxy_pass http://federation_requests; -} - - -# Main thread for all the rest -location / { - include snippets/proxy.conf; - proxy_pass http://inbound_main; - diff --git a/matrix/nginx/workers/maps.conf b/matrix/nginx/workers/maps.conf deleted file mode 100644 index 376c8080..00000000 --- a/matrix/nginx/workers/maps.conf +++ /dev/null @@ -1,55 +0,0 @@ -# These maps set all kinds of variables we can use later in our configuration. This fil -# should be stored under /etc/nginx/conf.d so that it is loaded whenever nginx starts. - -# List of allowed origins, can only send one. -map $http_origin $allow_origin { - ~^https?://element.example.com$ $http_origin; - ~^https?://call.example.com$ $http_origin; - ~^https?://someserver.example.com$ $http_origin; - # NGINX won't set empty string headers, so if no match, header is unset. - default ""; -} - -# Client username from MXID -map $http_authorization $mxid_localpart { - default $http_authorization; - "~Bearer syt_(?.*?)_.*" $username; - "" $accesstoken_from_urlparam; -} - -# Whether to upgrade HTTP connection -map $http_upgrade $connection_upgrade { - default upgrade; - '' close; -} - -#Extract room name from URI -map $request_uri $room_name { - default "not_room"; - "~^/_matrix/(client|federation)/.*?(?:%21|!)(?[\s\S]+)(?::|%3A)(?[A-Za-z0-9.\-]+)" "!$room:$domain"; -} - -# Choose sync worker based on the existence of "since" query parameter -map $arg_since $sync { - default normal_sync; - '' initial_sync; -} - -# Extract username from access token passed as URL parameter -map $arg_access_token $accesstoken_from_urlparam { - # Defaults to just passing back the whole accesstoken - default $arg_access_token; - # Try to extract username part from accesstoken URL parameter - "~syt_(?.*?)_.*" $username; -} - -# Extract username from access token passed as authorization header -map $http_authorization $mxid_localpart { - # Defaults to just passing back the whole accesstoken - default $http_authorization; - # Try to extract username part from accesstoken header - "~Bearer syt_(?.*?)_.*" $username; - # if no authorization-header exist, try mapper for URL parameter "access_token" - "" $accesstoken_from_urlparam; -} - diff --git a/matrix/nginx/workers/private.conf b/matrix/nginx/workers/private.conf deleted file mode 100644 index 461857ae..00000000 --- a/matrix/nginx/workers/private.conf +++ /dev/null @@ -1,13 +0,0 @@ -# This file defines the "safe" IP addresses that are allowed to use the admin endpoints -# of our installation. Store this file under /etc/nginx/snippets, so you can load it on -# demand for the bits you want/need to protect. - -allow 127.0.0.1; -allow ::1; -allow 12.23.45.78; -allow 87.65.43.21; -allow dead:beef::/48; -allow 2a10:1234:abcd::1; -deny all; -satisfy all; - diff --git a/matrix/nginx/workers/proxy.conf b/matrix/nginx/workers/proxy.conf deleted file mode 100644 index 4c3dbc54..00000000 --- a/matrix/nginx/workers/proxy.conf +++ /dev/null @@ -1,8 +0,0 @@ -# These are a few proxy settings that should be default. These are not used in the proxy_forward to -# our workers, we don't want buffering there. Store this file under /etc/nginx/conf.d because it contains -# defaults. - -proxy_buffer_size 128k; -proxy_buffers 4 256k; -proxy_busy_buffers_size 256k; - diff --git a/matrix/nginx/workers/proxy_forward.conf b/matrix/nginx/workers/proxy_forward.conf deleted file mode 100644 index 95bd3c25..00000000 --- a/matrix/nginx/workers/proxy_forward.conf +++ /dev/null @@ -1,20 +0,0 @@ -# Settings that we want for every proxy_forward to our workers. This file should live -# under /etc/nginx/snippets, because it should not be loaded automatically but on demand. - -proxy_connect_timeout 2s; -proxy_buffering off; -proxy_http_version 1.1; -proxy_read_timeout 3600s; -proxy_redirect off; -proxy_send_timeout 120s; -proxy_socket_keepalive on; -proxy_ssl_verify off; - -proxy_set_header Accept-Encoding ""; -proxy_set_header Host $host; -proxy_set_header X-Forwarded-For $remote_addr; -proxy_set_header X-Forwarded-Proto $scheme; -proxy_set_header Connection $connection_upgrade; -proxy_set_header Upgrade $http_upgrade; - -client_max_body_size 50M; diff --git a/matrix/nginx/workers/upstreams.conf b/matrix/nginx/workers/upstreams.conf deleted file mode 100644 index a9120301..00000000 --- a/matrix/nginx/workers/upstreams.conf +++ /dev/null @@ -1,116 +0,0 @@ -# Stream workers first, they are special. The documentation says: -# "each stream can only have a single writer" - -# Account-data -upstream account_data { - server unix:/run/matrix-synapse/inbound_accountdata.sock max_fails=0; - keepalive 10; -} - -# Userdir -upstream userdir { - server unix:/run/matrix-synapse/inbound_userdir.sock max_fails=0; - keepalive 10; -} - -# Typing -upstream typing { - server unix:/run/matrix-synapse/inbound_typing.sock max_fails=0; - keepalive 10; -} - -# To device -upstream todevice { - server unix:/run/matrix-synapse/inbound_todevice.sock max_fails=0; - keepalive 10; -} - -# Receipts -upstream receipts { - server unix:/run/matrix-synapse/inbound_receipts.sock max_fails=0; - keepalive 10; -} - -# Presence -upstream presence { - server unix:/run/matrix-synapse/inbound_presence.sock max_fails=0; - keepalive 10; -} - -# Push rules -upstream push_rules { - server unix:/run/matrix-synapse/inbound_push_rules.sock max_fails=0; - keepalive 10; -} - -# End of the stream workers, the following workers are of a "normal" type - -# Media -# If more than one media worker is used, they *must* all run on the same machine -upstream media { - server unix:/run/matrix-synapse/inbound_mediaworker.sock max_fails=0; - keepalive 10; -} - -# Synchronisation by clients: - -# Normal sync. Not particularly heavy, but happens a lot -upstream normal_sync { - # Use the username mapper result for hash key - hash $mxid_localpart consistent; - server unix:/run/matrix-synapse/inbound_normal_sync1.sock max_fails=0; - server unix:/run/matrix-synapse/inbound_normal_sync2.sock max_fails=0; - server unix:/run/matrix-synapse/inbound_normal_sync3.sock max_fails=0; - keepalive 10; -} -# Initial sync -# Much heavier than a normal sync, but happens less often -upstream initial_sync { - # Use the username mapper result for hash key - hash $mxid_localpart consistent; - server unix:/run/matrix-synapse/inbound_initial_sync1.sock max_fails=0; - server unix:/run/matrix-synapse/inbound_initial_sync2.sock max_fails=0; - keepalive 10; -} - -# Login -upstream login { - server unix:/run/matrix-synapse/inbound_login.sock max_fails=0; - keepalive 10; -} - -# Clients -upstream client { - hash $mxid_localpart consistent; - server unix:/run/matrix-synapse/inbound_clientworker1.sock max_fails=0; - server unix:/run/matrix-synapse/inbound_clientworker2.sock max_fails=0; - server unix:/run/matrix-synapse/inbound_clientworker3.sock max_fails=0; - server unix:/run/matrix-synapse/inbound_clientworker4.sock max_fails=0; - keepalive 10; -} - -# Federation -# "Normal" federation, balanced round-robin over 4 workers. -upstream incoming_federation { - server unix:/run/matrix-synapse/inbound_federation_reader1.sock max_fails=0; - server unix:/run/matrix-synapse/inbound_federation_reader2.sock max_fails=0; - server unix:/run/matrix-synapse/inbound_federation_reader3.sock max_fails=0; - server unix:/run/matrix-synapse/inbound_federation_reader4.sock max_fails=0; - keepalive 10; -} -# Inbound federation requests, need to be balanced by IP-address, but can go -# to the same pool of workers as the other federation stuff. -upstream federation_requests { - hash $remote_addr consistent; - server unix:/run/matrix-synapse/inbound_federation_reader1.sock max_fails=0; - server unix:/run/matrix-synapse/inbound_federation_reader2.sock max_fails=0; - server unix:/run/matrix-synapse/inbound_federation_reader3.sock max_fails=0; - server unix:/run/matrix-synapse/inbound_federation_reader4.sock max_fails=0; - keepalive 10; -} - -# Main thread for all the rest -upstream inbound_main { - server unix:/run/matrix-synapse/inbound_main.sock max_fails=0; - keepalive 10; -} diff --git a/matrix/postgresql/README.md b/matrix/postgresql/README.md deleted file mode 100644 index a5421024..00000000 --- a/matrix/postgresql/README.md +++ /dev/null @@ -1,84 +0,0 @@ ---- -gitea: none -include_toc: true ---- - -# Installing PostgreSQL and creating database and user - -Installing [PostgreSQL](https://www.postgresql.org/) on Debian is very easy: - -``` -apt install postgresql python3-psycopg - -sudo -u postgres bash - -createuser --pwprompt synapse -createdb --encoding=UTF8 --locale=C --template=template0 --owner=synapse synapse - -``` - -After this, PostgreSQL is installed, the database `synapse` exists and so does -the database user `synapse`. Make sure you choose a strong password. - - -# Configuring access - -After a clean installation, PostgreSQL will listen on localhost, both IPv4 and -IPv6 (if available). In many cases, this is exactly what you want. - -## Network - -PostgreSQL will listen on localhost, this is configured in -`/etc/postgresql//main/postgresql.conf`: - -``` -listen_addresses = 'localhost' -``` - -This line is usually commented out, but as it is the default, it's really -there. - - -## UNIX socket - -If you want PostgreSQL to listen only to a local UNIX socket (more efficient -than network and -depending on the configuration of the rest of you system- -easier to protect), make the aforementioned option explicitly empty and -uncomment it: - -``` -listen_addresses = '' -``` - -Check these options to make sure the socket is placed in the right spot and -given the correct permissions: - -``` -unix_socket_directories = '/var/run/postgresql' -#unix_socket_group = '' -#unix_socket_permissions = 0777 -``` - - -## Permissions - -Add permission for the user to connect to the database from localhost (if -PostgreSQL listens on localhost), or the socket (if you use that). This is -configured in `/etc/postgresql//main/pg_hba.conf`: - -``` -local synapse synapse password # for use with UNIX sockets -host synapse synapse localhost md5 # for use with localhost network -``` - -Make sure you add these lines under the one that gives access to the postgres -superuser, the first line. - - -# Tuning {#tuning} - -This is for later, check [Tuning your PostgreSQL Server](https://wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server) -on the PostgreSQL wiki. - -For tuning in the scenario with [Synapse workers](../synapse/workers), see [this -useful site](https://tcpipuk.github.io/postgres/tuning/index.html). diff --git a/matrix/synapse-admin/README.md b/matrix/synapse-admin/README.md deleted file mode 100644 index 7a636e72..00000000 --- a/matrix/synapse-admin/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# Synapse-admin - -This is the webgui for Synapse. - -Installation can be done in 3 ways -([see Github](https://github.com/Awesome-Technologies/synapse-admin)), we'll -pick the easiest one: using the precompiled tar. - -Unpack it under `/var/www`, link `synapse-admin` to the directory that the -archive creates. This is to make sure you can easily unpack a newer version, -prepare that, and then change the symlink. - -``` -# ls -l /var/www -total 8 -drwxr-xr-x 2 root root 4096 Nov 4 18:05 html -lrwxrwxrwx 1 root root 20 Nov 18 13:24 synapse-admin -> synapse-admin-0.10.3 -drwxr-xr-x 5 root root 4096 Nov 18 15:54 synapse-admin-0.10.3 -``` - -We use 0.10.3, but point nginx to '/var/www/synapse-admin'. Configuring nginx -is fairly straightforward, [see here](../nginx/README.md#synapse-admin). - -You should probably restrict Synapse-Admin to your own Synapse-server, instead -of letting users fill in whatever they want. Do this by adding this bit to -`config.json`. In our config we've moved that file to -`/etc/synapse-admin` and link to that from `/var/www/synapse-admin`. - -``` -{ - "restrictBaseUrl": "https://matrix.example.com" -} -``` diff --git a/matrix/synapse/README.md b/matrix/synapse/README.md deleted file mode 100644 index 86586581..00000000 --- a/matrix/synapse/README.md +++ /dev/null @@ -1,646 +0,0 @@ ---- -gitea: none -include_toc: true ---- - -# Installation and configuration of Synapse - -Mind you: this an installation on Debian Linux (at least for now). - -Start by installing the latest Synapse server, see the [upstream -documentation](https://element-hq.github.io/synapse/latest/setup/installation.html). - -``` -apt install -y lsb-release wget apt-transport-https build-essential python3-dev libffi-dev \ - python3-pip python3-setuptools sqlite3 \ - libssl-dev virtualenv libjpeg-dev libxslt1-dev libicu-dev git python3-jinja2 - -wget -O /usr/share/keyrings/matrix-org-archive-keyring.gpg https://packages.matrix.org/debian/matrix-org-archive-keyring.gpg - -echo "deb [signed-by=/usr/share/keyrings/matrix-org-archive-keyring.gpg] https://packages.matrix.org/debian/ $(lsb_release -cs) main" | - tee /etc/apt/sources.list.d/matrix-org.list - -apt update -apt install matrix-synapse-py3 -``` - -This leaves a very basic configuration in `/etc/matrix-synapse/homeserver.yaml` -and two settings under `/etc/conf.d`. All other configuration items will also -be configured with yaml-files in this directory. - -Configure the domain you with to use in `/etc/matrix-synapse/conf.d/server_name.yaml`. -What you configure here will also be the global part of your Matrix handles -(the part after the colon). Also add the URL clients should connect to: - -``` -server_name: example.com -public_baseurl: https://matrix.example.com/ -``` - -The `public_baseurl` will probably be different than the `server_name`, see -also [Delegation and DNS](#Delegation). - -You now have a standard Matrix server that uses sqlite. You really don't want -to use this in production, so probably want to replace this with PostgreSQL. - -There are two different ways to configure Synapse, documented here: - -* [Monolithic](monolithic) -* [Workers](workers) - -We'll use Synapse, using the workers architecture to make it scalable, flexible and reusable. - - -# Listeners - -A fresh installation configures one listener, for both client and federation -traffic. This listens on port 8008 on localhost (IPv4 and IPv6) and does not -do TLS: - -``` -listeners: - - port: 8008 - tls: false - type: http - x_forwarded: true - bind_addresses: ['::1', '127.0.0.1'] - resources: - - names: [client, federation] - compress: false -``` - -# Database - -The default installation leaves you with an sqlite3 database. Nice for experimenting, but -unsuitable for a production environment. - -[Here's how you setup PostgreSQL](../postgresql). - -Once you've created a database and user in PostgreSQL, you configure Synapse -to use it. - -First delete (or comment out) the SQLITE datbase in `homeserver.yaml`: - -``` -#database: -# name: sqlite3 -# args: -# database: /var/lib/matrix-synapse/homeserver.db -``` - -Then create the database configuration for PostgreSQL in -`conf.d/database.yaml`: - -``` -database: - name: psycopg2 - args: - user: synapse - password: - dbname: synapse - host: /var/run/postgresql - cp_min: 5 - cp_max: 10 -``` - -Note: you configure the directory where the UNIX socket file lives, not the -actual file. - -Of course, if you use localhost, you should configure it like this: - -``` - host: localhost - port: 5432 -``` - -After changing the database, restart Synapse and check whether it can connect -and create the tables it needs. - - -# Create admin - -Synapse doesn't create an admin account at install time, so you'll have to do -that yourself. - -You need to set a `registration_shared_secret` for this, set that in -`conf.d/keys.yaml` like this: - -``` -registration_shared_secret: xxxx -``` - -You can create such a key by running `pwgen -csn 52 1`. Restart Synapse after -setting this key. - -Now create an admin user. Login and issue this command: - -``` -register_new_matrix_user -u admin -a -c /etc/matrix-synapse/conf.d/keys.yaml -``` - -This will ask for a password, choose a safe one. - - -# Logging - -Logging is configured in `log.yaml`. Some logging should go to systemd, the -more specific logging to Synapse's own logfile(s). - -This part is yet to be completed, the default configuration is adequate for -most cases. - -# Delegation and DNS {#Delegation} - -If you run your server under a different FQDN than just the domain name you -want to use, you need to delegate: point from your domain to the server. - -Example. You want to use example.com for your domain, but your server is -called matrix.example.com. To make that work, you need to serve 2 bits of -JSON-code on example.com to point clients and servers to the correct -machine: matrix.example.com. - -Pointing servers to the correct server is done by publishing this bit of -JSON-code under `https://example.com/.well-known/matrix/server`: - -``` -{ - "m.homeserver": {"base_url": "https://matrix.example.com"} -} -``` - -Pointing clients to the correct server needs this at -`https://example.com/.well-known/matrix/client`: - -``` -{ - "m.server": "matrix.example.com" -} -``` - -Very important: both names (example.com and matrix.example.com) must be A -and/or AAAA records in DNS, not CNAME. - -You can also publish support data: administrator, security officer, helpdesk -page. Publish that as `.well-known/matrix/support`. - -See the included files for more elaborate examples, and check -[nginx](../nginx) for details about how to publish this data. - - -# E-mail {#Email} - -Synapse should probably be able to send out e-mails; notifications for those -who want that, and password reset for those who need one. - -You configure this under the section `email` (yes, really). - -First of all, you need an SMTP-server that is configured to send e-mail for -your domain. Configuring that is out of scope, we'll assume we can use the -server `smtp.example.com`. - -Configure this in `conf.d/email.yaml`: - -``` -email: - smtp_host: smtp.example.com - smtp_port: 465 - smtp_user: matrix@example.com - smtp_pass: SuperSecretPassword - force_tls: true - notif_from: "Your Matrix server " -``` - -This configures an SMTP-connection with SSL (port 465, `force_tls`). See Matrix' -[email documentation](https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html?highlight=require_transport_security#email) -for more information. - - -# Media store {#mediastore} - -Files and avatars need to be stored somewhere, we configure these options in -`conf.d/mediastore.yaml`: - -``` -media_store_path: /var/lib/matrix-synapse/media -enable_authenticated_media: true -max_upload_size: 50M -url_preview_enabled: true -url_preview_ip_range_blacklist: - - '127.0.0.0/8' - - '10.0.0.0/8' - - '172.16.0.0/12' - - '192.168.0.0/16' - - '100.64.0.0/10' - - '192.0.0.0/24' - - '169.254.0.0/16' - - '192.88.99.0/24' - - '198.18.0.0/15' - - '192.0.2.0/24' - - '198.51.100.0/24' - - '203.0.113.0/24' - - '224.0.0.0/4' - - '::1/128' - - 'fe80::/10' - - 'fc00::/7' - - '2001:db8::/32' - - 'ff00::/8' - - 'fec0::/10' -``` - -These are a few sane (?) defaults, check [Matrix' documentation](https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html?highlight=media_store_path#media-store) -for many more options. - - -# Homeserver blocking {#blocking} - -This is a series of options that can be used to block and/or limit users. The -whole list of options can be found in [Matrix' documentation](https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html?highlight=mau_stats_only%3A#homeserver-blocking), -we're going to pick out a few useful ones. - -Let's configure these options in `conf.d/homeserver_blocking.yaml`. - -``` -admin_contact: matrixadmin@example.com -mau_stats_only: true -max_avatar_size: 2M -allowed_avatar_mimetypes: - - "image/png" - - "image/jpeg" - - "image/gif" -forgotten_room_retention_period: 7d -``` - - -# Authentication {#authentication} - -Logging in can be done in basically two ways: an internal or external -database. Let's start with the first: users and their passwords are stored in -Synapse's database. - -We use `conf.d/authentication.yaml` to configure this stuff. - -``` -password_config: - policy: - enabled: true - localdb_enabled: true - pepper: - minimum_length: 8 - require_digit: true - require_symbol: true - require_lowercase: true - require_uppercase: true -``` - -With this bit, we configure Synapse to let users pick and change their own -passwords, as long as they meet the configured conditions. Mind you: `pepper` is -a secret random string that should *NEVER* be changed after initial setup. - -But in a bigger environment you'll probably want to use some authentication -backend, such as LDAP. LDAP is configured by means of a module (see -[Synapse LDAP auth Provider](https://github.com/matrix-org/matrix-synapse-ldap3/) -on Github). - -Configuring Synapse to use LDAP, would be something like this: - -``` -password_config: - policy: - enabled: only_for_reauth - localdb_enabled: false - -password_providers: - - module: "ldap_auth_provider.LdapAuthProvider" - config: - enabled: true - uri: "ldap://ldap.example.com:389" - start_tls: true - base: "ou=users,dc=example,dc=com" - attributes: - uid: "uid" - mail: "mail" - name: "cn" - filter: "(&(objectClass=posixAccount)(accountStatus=active))" - - mode: "search" - bind_dn: "cn=matrix,ou=service,dc=example,dc=com" - bind_password: "" -``` - -This would connect to ldap.example.com over TLS, and authenticate users that -live under `ou=users,dc=example,dc=com` and that are active Posix -accounts. Users will not be able to change their passwords via Matrix, they -have to do that in LDAP. - -The bottom 3 lines enable search mode, necessary to find users' displayname -and e-mail address. These values are in LDAP under the attributes "mail" and -"cn" (completely dependent on your LDAP DIT of course, this setup is common -for OpenLDAP). The bind_dn and bind_password are for the account Synapse can -use to connect and search, necessary if anonymous access is prohibited. - - -# Server configuration {#serverconfig} - -See [Define your homeserver name and other base options](https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html?highlight=require_auth_for_profile_requests#server) -in the Synapse documentation. - -It would be logical to put the next options under `conf.d/server.yaml`, but -Debian insists on `conf.d/server_name.yaml` existing and containing the name -of the domain. So we'll use that file for the next options as well. Add these -options: - -``` -presence: - enabled: true - include_offline_users_on_sync: false - -require_auth_for_profile_requests: true -allow_public_rooms_over_federation: true - -ip_range_blacklist: - - '127.0.0.0/8' - - '10.0.0.0/8' - - '172.16.0.0/12' - - '192.168.0.0/16' - - '100.64.0.0/10' - - '192.0.0.0/24' - - '169.254.0.0/16' - - '192.88.99.0/24' - - '198.18.0.0/15' - - '192.0.2.0/24' - - '198.51.100.0/24' - - '203.0.113.0/24' - - '224.0.0.0/4' - - '::1/128' - - 'fe80::/10' - - 'fc00::/7' - - '2001:db8::/32' - - 'ff00::/8' - - 'fec0::/10' - -filter_timeline_limit: 500 -delete_stale_devices_after: 1y -``` - -These should be reasonable defaults, but do check the [Server block](https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html#server) -in Synapse's documentation for more options and information. - - -# Registration {#Registration} - -Registration of new users is configured under `conf.d/registration.yaml`: - -``` -enable_registration: false -enable_registration_without_verification: false -registrations_require_3pid: email -registration_shared_secret: -allow_guest_access: false - -enable_set_displayname: false -enable_3pid_changes: false -``` - -The last two lines prohibit users to change their displayname and 3pid-data -(i.e. e-mail address and phone number). In many cases you'd want them to be -able to set these, of course. But when you use LDAP, which provides these -values, you don't want users to change those. - -See for more options [Synapse's documentation](https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html#registration). - - -# TURN - -Check for more information about [how to configure the TURN -server](../coturn) or [LiveKit](../element-call#livekit). You probably want -LiveKit, but read on if you choose coturn. - -It might be useful to use both coturn and LiveKit, so as to support both -legacy and EC calls, but you'd need to tweak the configurations so that they -don't bite each other. - -Once you've set up your TURN server, configure it in -Synapse, in `conf.d/turn.yaml`: - -``` -turn_shared_secret: "" -turn_uris: - - "turn:turn.matrixdev.example.com?transport=udp" - - "turn:turn.matrixdev.example.com?transport=tcp" -turn_user_lifetime: 86400000 -turn_allow_guests: true -``` - -Restart Synapse to activate this bit. - - -# Consent Tracking {#consenttracking} - -As administrator you sometimes need to push a message to all your users. See -the [Synapse documentation](https://element-hq.github.io/synapse/latest/server_notices.html) -to see how to configure that. - -It's also necessary for moderation ([see Draupnir](../draupnir)). - - -## Server Notices - -Server notices allow administrators to send messages to users, much like the -`wall` functionality in UNIX/Linux. - -Add this bit of info to `conf.d/server_notices.yaml`: - -``` -server_notices: - system_mxid_localpart: server - system_mxid_display_name: "Server Notices" -# system_mxid_avatar_url: "mxc://example.com/QBBZcaxfrrpvreGeNhqRaCjG" - room_name: "Server Notices" -# room_avatar_url: "mxc://example.com/QBBZcaxfrrpvreGeNhqRaCjG" - room_topic: "Room used by your server admin to notice you of important -information" - auto_join: true -``` - -This means that the user sending the messages (who isn't really a user anyway) -is `server@example.com`, with the display name `Server Notices`. The room that users receive -these messages in is called the same. The room will be created if it doesn't -yet exist, every user that receives a server message will be put in a room -with that name. - -Every user gets his own room, so if you send a server notice to 100 users, -there will be (at least) 100 rooms by that name, all containing 1 user. - -The option `auto_join` means that users will automatically join the room as -soon as it's created. They can leave afterwards, but they'll be put into it again -as soon as they receive another server message. - -The two commented out options are the avatars for user and room. This is a bit -tricky. You'll need to upload an image to a room first, so that it's present -in the media store. Then you can refer to it by the ID it gets, in the way -shown above. These avatars will only be set or changed when you send a server -notice. - -Important bit: you must upload these pictures to an unencrypted room. Pictures -in an encrypted room are... well... encrypted, and that causes a problem for -the thumbnailer. Pictures in encrypted rooms are stored as MIME type -`application/octet-stream`, you want one of the formats you configured under -[Homeserver Blocking](#blocking). Or, if you haven't defined a whitelist, at -least an image mimetype... - -Apparently this was a bug that's supposed to be fixed in Synapse 1.20, but we -haven't tested that yet. - -You can find the ID of the picture in the database (table `local_media_repository`) -or, more conveniently, in [Synapse-Admin](../synapse-admin), which is also -where you'll want to go if you want to send a server notice. - -In Synapse-Admin, open the User tab, select the user(s) you want to send a -notice to, and click "Send Server Notices". - -If the result is that you're returned to the login screen of Synapse-Admin, -there was an error sending the notice. Check the Synapse logs. - - -## Consent template - -You can force your users to accept an agreement before you let them on your -machine, see the [Synapse Documentation](https://element-hq.github.io/synapse/latest/consent_tracking.html#support-in-synapse-for-tracking-agreement-to-server-terms-and-conditions). - -First, make the directory where you want Synapse to search for the document, -we create the directory `consent_policy`: - - -``` -mkdir -p /var/lib/matrix-synapse/consent_policy/en -``` - -You'll have to add the directory `en` under that, as every document is assumed -to be in English. Support for other languages is on the wish list. - -Create a Jinja2 template with the texts you want: the text users have to agree -to before they can use the service, and the text users that have already -agreed will see. Something like this: - -``` - - - - Example End User Policy - - - {% if has_consented %} -

- You have already accepted the Example End User Policy. -

- {% else %} -

Example End User Policy

- -These are the terms under which you can use this service. Unless you accept these terms, you -will not be allowed to send any messages. - -
    -
  1. You will not be abusive to other users, be they on this server or on an other. -
  2. You will not do other nasty stuff. -
  3. Basically: you will behave like a good person. -
- -We promise you a few things too: - -
    -
  1. We'll keep your data safe -
  2. We won't snoop on you -
  3. We'll only turn you in with the authorities if you do nasty stuff. -
- -If you accept these terms, you can use this system. - {% if not public_version %} - -
- - - - -
- {% endif %} - {% endif %} - - -``` - -The name of this document needs to be a version name with the extension `.html`. -Say you want your users to accept version 0.1, the file must be named -0.1.html. This version is referred to in the configuration. - -After a user has agreed to this policy, he is presented with `success.html`, -which you will also have to make (although it's not mentioned in the -documentation). This doesn't have to be very complicated. - -``` - - - - ProcoliX End User Policy - - -

You have agreed to our End User Policy, you can now use our service.

- -

Have fun!

- - -``` - -We now have the texts ready, time to configure Synapse to use it. - -Create a `form_secret`: - -``` -pwgen -csny 30 1 -``` - -Add this bit to `conf.d/server_notices.yaml`: - -``` -form_secret: "" -user_consent: - require_at_registration: true - policy_name: "Example End User Policy" - template_dir: consent_policy - version: - server_notice_content: - msgtype: m.text - body: >- - You have to agree to our End User Policy before you can use this - service. Please read and accept it at %(consent_uri)s. - block_events_error: >- - You haven't accepted the End User Policy yet, so you can't post any - messages yet. Please read and accept the policy at %(consent_uri)s. -``` - -Last bit it to enable the consent tracking on all listeners where `client` is -active. We have only one listener, so we add `consent` to that: - -``` -listeners: - - port: 8008 - tls: false - type: http - x_forwarded: true - bind_addresses: ['::1', '127.0.0.1'] - resources: - - names: - - client - - consent - - federation - compress: false -``` - -Restart Synapse for these changes to take effect. - -If you update your policy, you'll have to copy the current one to a new -version, edit that (e.g. `0.2.html`) and change the `version` to the new -document. Restart Synapse after that. Your users will all have to agree to the -new policy. - -The options `server_notice_content` and `block_events_error` do not seem to be -used, this is something that needs to be investigated. diff --git a/matrix/synapse/conf.d/authentication.yaml b/matrix/synapse/conf.d/authentication.yaml deleted file mode 100644 index 47292f95..00000000 --- a/matrix/synapse/conf.d/authentication.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# Authentication stuff - -password_config: - policy: - enabled: only_for_reauth - localdb_enabled: false - -password_providers: - - module: "ldap_auth_provider.LdapAuthProvider" - config: - enabled: true - uri: "ldap://ldap.example.com" - start_tls: true - mode: "search" - base: "ou=users,o=Example,dc=example,dc=eu" - attributes: - uid: "uid" - mail: "mail" - name: "cn" - filter: "(&(objectClass=posixAccount)(accountStatus=active))" - bind_dn: "cn=matrix,ou=service,dc=example,dc=com" - bind_password: "" diff --git a/matrix/synapse/conf.d/call.yaml b/matrix/synapse/conf.d/call.yaml deleted file mode 100644 index 00e6da4b..00000000 --- a/matrix/synapse/conf.d/call.yaml +++ /dev/null @@ -1,19 +0,0 @@ -experimental_features: - # MSC3266: Room summary API. Used for knocking over federation - msc3266_enabled: true - -# The maximum allowed duration by which sent events can be delayed, as -# per MSC4140. -max_event_delay_duration: 24h - -rc_message: - # This needs to match at least the heart-beat frequency plus a bit of headroom - # Currently the heart-beat is every 5 seconds which translates into a rate of 0.2s - per_second: 0.5 - burst_count: 30 - -extra_well_known_client_content: - org.matrix.msc4143.rtc_foci: - type: livekit - livekit_service_url: https://livekit.example.com - diff --git a/matrix/synapse/conf.d/database.yaml b/matrix/synapse/conf.d/database.yaml deleted file mode 100644 index 9e43cd13..00000000 --- a/matrix/synapse/conf.d/database.yaml +++ /dev/null @@ -1,9 +0,0 @@ -database: - name: psycopg2 - args: - user: synapse - password: - dbname: synapse - host: /var/run/postgresql - cp_min: 5 - cp_max: 10 diff --git a/matrix/synapse/conf.d/email.yaml b/matrix/synapse/conf.d/email.yaml deleted file mode 100644 index 08d5a4df..00000000 --- a/matrix/synapse/conf.d/email.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# This takes care of sending e-mail - -email: - smtp_host: smtp.example.com - smtp_port: 465 - smtp_user: matrix@example.com - smtp_pass: - force_tls: true - notif_from: "Your Matrix server " diff --git a/matrix/synapse/conf.d/homeserver_blocking.yaml b/matrix/synapse/conf.d/homeserver_blocking.yaml deleted file mode 100644 index b98e4fe9..00000000 --- a/matrix/synapse/conf.d/homeserver_blocking.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# Various settings for blocking stuff. -# See https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html?highlight=mau_stats_only%3A#homeserver-blocking - -admin_contact: admin@example.com -mau_stats_only: true -max_avatar_size: 2M -allowed_avatar_mimetypes: - - "image/png" - - "image/jpeg" - - "image/gif" -forgotten_room_retention_period: 7d diff --git a/matrix/synapse/conf.d/keys.yaml b/matrix/synapse/conf.d/keys.yaml deleted file mode 100644 index 6be08442..00000000 --- a/matrix/synapse/conf.d/keys.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# This file contains secrets - -signing_key_path: "/etc/matrix-synapse/homeserver.signing.key" -macaroon_secret_key: -registration_shared_secret: diff --git a/matrix/synapse/conf.d/mediastore.yaml b/matrix/synapse/conf.d/mediastore.yaml deleted file mode 100644 index 80d65921..00000000 --- a/matrix/synapse/conf.d/mediastore.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# Media stuff -# See https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html?highlight=media_store_path#media-store - -media_store_path: /var/lib/matrix-synapse/media -enable_authenticated_media: true -max_upload_size: 50M -url_preview_enabled: true -url_preview_ip_range_blacklist: - - '127.0.0.0/8' - - '10.0.0.0/8' - - '172.16.0.0/12' - - '192.168.0.0/16' - - '100.64.0.0/10' - - '192.0.0.0/24' - - '169.254.0.0/16' - - '192.88.99.0/24' - - '198.18.0.0/15' - - '192.0.2.0/24' - - '198.51.100.0/24' - - '203.0.113.0/24' - - '224.0.0.0/4' - - '::1/128' - - 'fe80::/10' - - 'fc00::/7' - - '2001:db8::/32' - - 'ff00::/8' - - 'fec0::/10' - -dynamic_thumbnails: true diff --git a/matrix/synapse/conf.d/report_stats.yaml b/matrix/synapse/conf.d/report_stats.yaml deleted file mode 100644 index 8e8bc67a..00000000 --- a/matrix/synapse/conf.d/report_stats.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# This file is autogenerated, and will be recreated on upgrade if it is deleted. -# Any changes you make will be preserved. - -# Whether to report homeserver usage statistics. -report_stats: true diff --git a/matrix/synapse/conf.d/server_name.yaml b/matrix/synapse/conf.d/server_name.yaml deleted file mode 100644 index ea7106eb..00000000 --- a/matrix/synapse/conf.d/server_name.yaml +++ /dev/null @@ -1,43 +0,0 @@ -# This file is autogenerated, and will be recreated on upgrade if it is deleted. -# Any changes you make will be preserved. - -# The domain name of the server, with optional explicit port. -# This is used by remote servers to connect to this server, -# e.g. matrix.org, localhost:8080, etc. -# This is also the last part of your UserID. -# -server_name: example.com - -# The rest is our local configuration: -public_baseurl: https://matrix.example.com/ - -presence: - enabled: true - include_offline_users_on_sync: false - -require_auth_for_profile_requests: true -allow_public_rooms_over_federation: true - -ip_range_blacklist: - - '127.0.0.0/8' - - '10.0.0.0/8' - - '172.16.0.0/12' - - '192.168.0.0/16' - - '100.64.0.0/10' - - '192.0.0.0/24' - - '169.254.0.0/16' - - '192.88.99.0/24' - - '198.18.0.0/15' - - '192.0.2.0/24' - - '198.51.100.0/24' - - '203.0.113.0/24' - - '224.0.0.0/4' - - '::1/128' - - 'fe80::/10' - - 'fc00::/7' - - '2001:db8::/32' - - 'ff00::/8' - - 'fec0::/10' - -filter_timeline_limit: 500 -delete_stale_devices_after: 1y diff --git a/matrix/synapse/conf.d/server_notices.yaml b/matrix/synapse/conf.d/server_notices.yaml deleted file mode 100644 index 1c8b82a8..00000000 --- a/matrix/synapse/conf.d/server_notices.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# Necessary for server notices, and moderation - -server_notices: - system_mxid_localpart: server - system_mxid_display_name: "Server Notices" - system_mxid_avatar_url: "mxc://example.com/QBBZcaxfrrpvreGeNhqRaCjG" - room_name: "Server Notices" - room_avatar_url: "mxc://example.com/QBBZcaxfrrpvreGeNhqRaCjG" - room_topic: "Room used by your server admin to notice you of important information" - auto_join: true - -user_consent: - require_at_registration: true - policy_name: "Example End User Policy" - template_dir: consent_policy - version: 0.2 - server_notice_content: - msgtype: m.text - body: >- - You have to agree to our End User Policy before you can use this - service. Please read and accept it at %(consent_uri)s. - block_events_error: >- - You haven't accepted the End User Policy yet, so you can't post any - messages yet. Please read and accept the policy at %(consent_uri)s. - -form_secret: "" diff --git a/matrix/synapse/conf.d/turn.yaml b/matrix/synapse/conf.d/turn.yaml deleted file mode 100644 index 037dc35d..00000000 --- a/matrix/synapse/conf.d/turn.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# This configures the connection to the TURN server - -turn_shared_secret: "" -turn_uris: - - "turn:turn.example.com?transport=udp" - - "turn:turn.example.com?transport=tcp" -turn_user_lifetime: 86400000 -turn_allow_guests: true - diff --git a/matrix/synapse/homeserver.yaml b/matrix/synapse/homeserver.yaml deleted file mode 100644 index 0df64a0c..00000000 --- a/matrix/synapse/homeserver.yaml +++ /dev/null @@ -1,34 +0,0 @@ -# Configuration file for Synapse. -# -# This is a YAML file: see [1] for a quick introduction. Note in particular -# that *indentation is important*: all the elements of a list or dictionary -# should have the same indentation. -# -# [1] https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html -# -# For more information on how to configure Synapse, including a complete accounting of -# each option, go to docs/usage/configuration/config_documentation.md or -# https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html -# -# This is set in /etc/matrix-synapse/conf.d/server_name.yaml for Debian installations. -# server_name: "SERVERNAME" -pid_file: "/var/run/matrix-synapse.pid" -listeners: - - port: 8008 - tls: false - type: http - x_forwarded: true - bind_addresses: ['::1', '127.0.0.1'] - resources: - - names: - - client - - consent - - federation - compress: false -#database: -# name: sqlite3 -# args: -# database: /var/lib/matrix-synapse/homeserver.db -log_config: "/etc/matrix-synapse/log.yaml" -trusted_key_servers: - - server_name: "matrix.org" diff --git a/matrix/synapse/templates/0.1.html b/matrix/synapse/templates/0.1.html deleted file mode 100644 index e4c2129b..00000000 --- a/matrix/synapse/templates/0.1.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - Example End User Policy - - - {% if has_consented %} -

- You have already accepted the Example End User Policy. -

- {% else %} -

Example End User Policy

- -These are the terms under which you can use this service. Unless you accept these terms, you -will not be allowed to send any messages. - -
    -
  1. You will not be abusive to other users, be they on this server or on an other. -
  2. You will not do other nasty stuff. -
  3. Basically: you will behave like a good person. -
- -We promise you a few things too: - -
    -
  1. We'll keep your data safe -
  2. We won't snoop on you -
  3. We'll only turn you in with the authorities if you do nasty stuff. -
- -If you accept these terms, you can use this system. - {% if not public_version %} - -
- - - - -
- {% endif %} - {% endif %} - - diff --git a/matrix/synapse/templates/success.html b/matrix/synapse/templates/success.html deleted file mode 100644 index e1c324cc..00000000 --- a/matrix/synapse/templates/success.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - Example End User Policy - - -

You have agreed to our End User Policy, you can now use our service.

- -

Have fun!

- - diff --git a/matrix/synapse/well-known-client.json b/matrix/synapse/well-known-client.json deleted file mode 100644 index 28a67dbc..00000000 --- a/matrix/synapse/well-known-client.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "m.homeserver": { - "base_url": "https://matrix.example.com" - }, - - "org.matrix.msc4143.rtc_foci":[ - { - "type": "livekit", - "livekit_service_url": "https://livekit.example.com" - } - ] -} diff --git a/matrix/synapse/well-known-server.json b/matrix/synapse/well-known-server.json deleted file mode 100644 index b9ffd998..00000000 --- a/matrix/synapse/well-known-server.json +++ /dev/null @@ -1 +0,0 @@ -{"m.server": "matrix.example.com"} diff --git a/matrix/synapse/well-known-support.json b/matrix/synapse/well-known-support.json deleted file mode 100644 index ef9be1a1..00000000 --- a/matrix/synapse/well-known-support.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "contacts": [ - { - "email_address": "admin@example.com", - "matrix_id": "@john:example.com", - "role": "m.role.admin" - }, - - { - "email_address": "security@example.com", - "matrix_id": "@bob:example.com", - "role": "m.role.security" - } - ], - - "support_page": "https://support.example.com/" -} diff --git a/matrix/synapse/workers/README.md b/matrix/synapse/workers/README.md deleted file mode 100644 index 2f8aebc5..00000000 --- a/matrix/synapse/workers/README.md +++ /dev/null @@ -1,593 +0,0 @@ ---- -gitea: none -include_toc: true ---- - -# Introduction to a worker-based setup - -Very busy servers are brought down because a single thread can't keep up with -the load. So you want to create several threads for different types of work. - -See this [Matrix blog](https://matrix.org/blog/2020/11/03/how-we-fixed-synapse-s-scalability/) -for some background information. - -The traditional Synapse setup is one monolithic piece of software that does -everything. Joining a very busy room makes a bottleneck, as the server will -spend all its cycles on synchronizing that room. - -You can split the server into workers, that are basically Synapse servers -themselves. Redirect specific tasks to them and you have several different -servers doing all kinds of tasks at the same time. A busy room will no longer -freeze the rest. - -Workers communicate with each other via UNIX sockets and Redis. We choose -UNIX sockets because they're much more efficient than network sockets. Of -course, if you scale to more than one machine, you will need network sockets -instead. - -**Important note** - -While the use of workers can drastically improve speed, the law of diminished -returns applies. Splitting off more and more workers will not further improve -speed after a certain point. Plus: you need to understand what the most -resource-consuming tasks are before you can start to plan how many workers for -what tasks you need. - -In this document we'll basically create a worker for every task, and several -workers for a few heavy tasks, as an example. You mileage may not only vary, it -will. - -Tuning the rest of the machine and network also counts, especially PostgreSQL. -A well-tuned PostgreSQL can make a really big difference and should probably -be considered even before configuring workers. - -With workers, PostgreSQL's configuration should be changed accordingly: see -[Tuning PostgreSQL for a Matrix Synapse -server](https://tcpipuk.github.io/postgres/tuning/index.html) for hints and -examples. - -A worker-based Synapse is tailor-made, there is no one-size-fits-all approach. -All we can do here is explain how things work, what to consider and how to -build what you need by providing examples. - - -# Redis - -Workers need Redis as part of their communication, so our first step will be -to install Redis. - -``` -apt install redis-server -``` - -For less overhead we use a UNIX socket instead of a network connection to -localhost. Disable the TCP listener and enable the socket in -`/etc/redis/redis.conf`: - -``` -port 0 - -unixsocket /run/redis/redis-server.sock -unixsocketperm 770 -``` - -Our matrix user (`matrix-synapse`) has to be able to read from and write to -that socket, which is created by Redis and owned by `redis:redis`, so we add -user `matrix-synapse` to the group `redis`. You may come up with a -finer-grained permission solution, but for our example this will do. - -``` -adduser matrix-synapse redis -``` - -Restart Redis for these changes to take effect. Check for error messages in -the logs, if port 6379 is no longer active, and if the socketfile -`/run/redis/redis-server.sock` exists. - -Now point Synapse at Redis in `conf.d/redis.yaml`: - -``` -redis: - enabled: true - path: /run/redis/redis-server.sock -``` - -Restart Synapse and check if it can connect to Redis via the socket, you should find log -entries like this: - -``` -synapse.replication.tcp.redis - 292 - INFO - sentinel - Connecting to redis server UNIXAddress('/run/redis/redis-server.sock') -synapse.util.httpresourcetree - 56 - INFO - sentinel - Attaching to path b'/_synapse/replication' -synapse.replication.tcp.redis - 126 - INFO - sentinel - Connected to redis -synapse.replication.tcp.redis - 138 - INFO - subscribe-replication-0 - Sending redis SUBSCRIBE for ['matrix.example.com/USER_IP', 'matrix.example.com'] -synapse.replication.tcp.redis - 141 - INFO - subscribe-replication-0 - Successfully subscribed to redis stream, sending REPLICATE command -synapse.replication.tcp.redis - 146 - INFO - subscribe-replication-0 - REPLICATE successfully sent -``` - - -# Synapse - -Workers communicate with each other over sockets, that are all placed in one -directory. These sockets are owned by `matrix-synapse:matrix-synapse`, so make -sure nginx can write to them: add user `www-data` to group `matrix-synapse` -and restart nginx. - -Then, make sure systemd creates the directory for the sockets as soon as -Synapse starts: - -``` -systemctl edit matrix-synapse -``` - -Now override parts of the `Service` stanza to add these two lines: - -``` -[Service] -RuntimeDirectory=matrix-synapse -RuntimeDirectoryPreserve=yes -``` - -The directory `/run/matrix-synapse` will be created as soon -as Synapse starts, and will not be removed on restart or stop, because that -would create problems with workers who suddenly lose their sockets. - -Then we change Synapse from listening on `localhost:8008` to listening on a -socket. We'll do most of our workers work in `conf.d/listeners.yaml`, so let's -put the new listener configuration for the main proccess there. - -Remove the `localhost:8008` stanza, and configure these two sockets: - -``` -listeners: - - path: /run/matrix-synapse/inbound_main.sock - mode: 0660 - type: http - resources: - - names: - - client - - consent - - federation - - - path: /run/matrix-synapse/replication_main.sock - mode: 0660 - type: http - resources: - - names: - - replication -``` - -This means Synapse will create two sockets under `/run/matrix-synapse`: one -for incoming traffic that is forwarded by nginx (`inbound_main.sock`), and one for -communicating with all the other workers (`replication_main.sock`). - -If you restart Synapse now, it won't do anything anymore, because nginx is -still forwarding its traffic to `localhost:8008`. We'll get to nginx later, -but for now you should change: - -``` -proxy_forward http://localhost:8008; -``` - -to - -``` -proxy_forward http://unix:/run/matrix-synapse/inbound_main.sock; -``` - -If you've done this, restart Synapse and nginx, and check if the sockets are created -and have the correct permissions. - -Synapse should work normally again, we've switched from network sockets to -UNIX sockets, and added Redis. Now we'll create the actual workers. - - -# Worker overview - -Every worker is, in fact, a Synapse server, only with a limited set of tasks. -Some tasks can be handled by a number of workers, others only by one. Every -worker starts as a normal Synapse process, reading all the normal -configuration files, and then a bit of configuration for the specific worker -itself. - -Workers need to communicate with each other and the main process, they do that -via the `replication` sockets under `/run/matrix-synapse` and Redis. - -Most worker also need a way to be fed traffic by nginx: they have an `inbound` -socket for that, in the same directory. - -Finally, all those replicating workers need to be registered in the main -process: all workers and their replication sockets are listed in the `instance_map`. - - -## Types of workers - -We'll make separate workers for almost every task, and several for the -heaviest tasks: synchronising. An overview of what endpoints are to be -forwarded to a worker is in [Synapse's documentation](https://element-hq.github.io/synapse/latest/workers.html#available-worker-applications). - -We'll create the following workers: - -* login -* federation_sender -* mediaworker -* userdir -* pusher -* push_rules -* typing -* todevice -* accountdata -* presence -* receipts -* initial_sync: 1 and 2 -* normal_sync: 1, 2 and 3 - -Some of them are `stream_writers`, and the [documentation about -stream_witers](https://element-hq.github.io/synapse/latest/workers.html#stream-writers) -says: - -``` -Note: The same worker can handle multiple streams, but unless otherwise documented, each stream can only have a single writer. -``` - -So, stream writers must have unique tasks: you can't have two or more workers -writing to the same stream. Stream writers have to be listed in `stream_writers`: - -``` -stream_writers: - account_data: - - accountdata - presence: - - presence - receipts: - - receipts - to_device: - - todevice - typing: - - typing - push_rules: - - push_rules -``` - -As you can see, we've given the stream workers the name of the stream they're -writing to. We could combine all those streams into one worker, which would -probably be enough for most instances. - -We could define a worker with the name streamwriter and list it under all -streams instead of a single worker for every stream. - -Finally, we have to list all these workers under `instance_map`: their name -and their replication socket: - -``` -instance_map: - main: - path: "/run/matrix-synapse/replication_main.sock" - login: - path: "/run/matrix-synapse/replication_login.sock" - federation_sender: - path: "/run/matrix-synapse/replication_federation_sender.sock" - mediaworker: - path: "/run/matrix-synapse/replication_mediaworker.sock" -... - normal_sync1: - path: "unix:/run/matrix-synapse/replication_normal_sync1.sock" - normal_sync2: - path: "unix:/run/matrix-synapse/replication_normal_sync2.sock" - normal_sync3: - path: "unix:/run/matrix-synapse/replication_normal_sync3.sock" -``` - - -## Defining a worker - -Every working starts with the normal configuration files, and then loads its -own. We put those files under `/etc/matrix-synapse/workers`. You have to -create that directory, and make sure Synapse can read them. Being -profesionally paranoid, we restrict access to that directory and the files in -it: - -``` -mkdir /etc/matrix-synapse/workers -chown matrix-synapse:matrix-synapse /etc/matrix-synapse/workers -chmod 750 /etc/matrix-synapse-workers -``` - -We'll fill this directory with `yaml` files; one for each worker. - - -### Generic worker - -Workers look very much the same, very little configuration is needed. This is -what you need: - -* name -* replication socket (not every worker needs this) -* inbound socket (not every worker needs this) -* log configuration - -One worker we use handles the login actions, this is how it's configured in -/etc/matrix-synapse/workers/login.yaml`: - -``` -worker_app: "synapse.app.generic_worker" -worker_name: "login" -worker_log_config: "/etc/matrix-synapse/logconf.d/login.yaml" - -worker_listeners: - - path: "/run/matrix-synapse/inbound_login.sock" - type: http - resources: - - names: - - client - - consent - - federation - - - path: "/run/matrix-synapse/replication_login.sock" - type: http - resources: - - names: [replication] -``` - -The first line defines the type of worker. In the past there were quite a few -different types, but most of them have been phased out in favour of one -generic worker. - -The first listener is the socket where nginx sends all traffic related to logins -to. You have to configure nginx to do that, we'll get to that later. - -The `worker_log_config` defines how and where the worker logs. Of course you'll -need to configure that too, see further. - -The first `listener` is the inbound socket, that nginx uses to forward login -related traffic to. Make sure nginx can write to this socket. The -`resources` vary between workers. - -The second `listener` is used for communication with the other workers and the -main thread. The only `resource` it needs is `replication`. This socket needs -to be listed in the `instance_map` in the main thread, the inbound socket does -not. - -Of course, if you need to scale up to the point where you need more than one -machine, these listeners can no longer use UNIX sockets, but will have to use -the network. This creates extra overhead, so you want to use sockets whenever -possible. - - -### Media worker - -The media worker is slightly different than the generic one. It doesn't use the -`synapse.app.generic_worker`, but a specialised one: `synapse.app.media_repository`. -To prevent the main process from handling media itself, you have to explicitly -tell it to leave that to the worker, by adding this to the configuration (in -our setup `conf.d/listeners.yaml`): - -``` -enable_media_repo: false -media_instance_running_background_jobs: mediaworker -``` - -The worker `mediaworker` looks like this: - -``` -worker_app: "synapse.app.media_repository" -worker_name: "mediaworker" -worker_log_config: "/etc/matrix-synapse/logconf.d/media.yaml" - -worker_listeners: - - path: "/run/matrix-synapse/inbound_mediaworker.sock" - type: http - resources: - - names: [media] - - - path: "/run/matrix-synapse/replication_mediaworker.sock" - type: http - resources: - - names: [replication] -``` - -If you use more than one mediaworker, know that they must all run on the same -machine; scaling it over more than one machine will not work. - - -## Worker logging - -As stated before, you configure the logging of workers in a separate yaml -file. As with the definitions of the workers themselves, you need a directory for -that. We'll use `/etc/matrix-synapse/logconf.d` for that; make it and fix the -permissions. - -``` -mkdir /etc/matrix-synapse/logconf.d -chgrp matrix-synapse /etc/matrix-synapse/logconf.d -chmod 750 /etc/matrix-synapse/logconf.d -``` - -There's a lot you can configure for logging, but for now we'll give every -worker the same layout. Here's the configuration for the `login` worker: - -``` -version: 1 -formatters: - precise: - format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s' -handlers: - file: - class: logging.handlers.TimedRotatingFileHandler - formatter: precise - filename: /var/log/matrix-synapse/login.log - when: midnight - backupCount: 3 - encoding: utf8 - - buffer: - class: synapse.logging.handlers.PeriodicallyFlushingMemoryHandler - target: file - capacity: 10 - flushLevel: 30 - period: 5 - -loggers: - synapse.metrics: - level: WARN - handlers: [buffer] - synapse.replication.tcp: - level: WARN - handlers: [buffer] - synapse.util.caches.lrucache: - level: WARN - handlers: [buffer] - twisted: - level: WARN - handlers: [buffer] - synapse: - level: INFO - handlers: [buffer] - -root: - level: INFO - handlers: [buffer] -``` - -The only thing you need to change if the filename to which the logs are -written. You could create only one configuration and use that in every worker, -but that would mean all logs will end up in the same file, which is probably -not what you want. - -See the [Python -documentation](https://docs.python.org/3/library/logging.config.html#configuration-dictionary-schema) -for all the ins and outs of logging. - - -# Systemd - -You want Synapse and its workers managed by systemd. First of all we define a -`target`: a group of services that belong together. - -``` -systemctl edit --force --full matrix-synapse.target -``` - -Feed it with this bit: - -``` -[Unit] -Description=Matrix Synapse with all its workers -After=network.target - -[Install] -WantedBy=multi-user.target -``` - -First add `matrix-synapse.service` to this target by overriding the `WantedBy` -in the unit file. We're overriding and adding a bit more. - -``` -systemctl edit matrix-synapse.service -``` - -Add this to the overrides: - -``` -[Unit] -PartOf=matrix-synapse.target -Before=matrix-synapse-worker -ReloadPropagatedFrom=matrix-synapse.target - -[Service] -RuntimeDirectory=matrix-synapse -RuntimeDirectoryMode=0770 -RuntimeDirectoryPreserve=yes - -[Install] -WantedBy=matrix-synapse.target -``` - -The additions under `Unit` mean that `matrix-synapse.service` is part of the -target we created earlier, and that is should start before the workers. -Restarting the target means this service must be restarted too. - -Under `Service` we define the directory where the sockets live (`/run` is -prefixed automatically), its permissions and that it should not be removed if -the service is stopped. - -The `WantedBy` under `Install` includes it in the target. The target itself is -included in `multi-user.target`, so it should always be started in the multi-user -runlevel. - -For the workers we're using a template instead of separate unit files for every -single one. Create the template: - -``` -systemctl edit --full --force matrix-synapse-worker@ -``` - -Mind the `@` at the end, that's not a typo. Fill it with this content: - -``` -[Unit] -Description=Synapse worker %i -AssertPathExists=/etc/matrix-synapse/workers/%i.yaml - -# This service should be restarted when the synapse target is restarted. -PartOf=matrix-synapse.target -ReloadPropagatedFrom=matrix-synapse.target - -# if this is started at the same time as the main, let the main process start -# first, to initialise the database schema. -After=matrix-synapse.service - -[Service] -Type=notify -NotifyAccess=main -User=matrix-synapse -Group=matrix-synapse -WorkingDirectory=/var/lib/matrix-synapse -ExecStart=/opt/venvs/matrix-synapse/bin/python -m synapse.app.generic_worker --config-path=/etc/matrix-synapse/homeserver.yaml --config-path=/etc/matrix-synapse/conf.d/ --config-path=/etc/matrix-synapse/workers/%i.yaml -ExecReload=/bin/kill -HUP $MAINPID -Restart=always -RestartSec=3 -SyslogIdentifier=matrix-synapse-%i - -[Install] -WantedBy=matrix-synapse.target -``` - -Now you can start/stop/restart every worker individually. Starting the `login` -worker would be done by: - -``` -systemctl start matrix-synapse-worker@login -``` - -Every worker needs to be enabled and started individually. Quickest way to do -that, is to run a loop in the directory: - -``` -cd /etc/matrix-synapse/workers -for worker in `ls *yaml | sed -n 's/\.yaml//p'`; do systemctl enable matrix-synapse-worker@$worker; done -``` - -After a reboot, Synapse and all its workers should be started. But starting -the target should also do that: - -``` -systemctl start matrix-synapse.target -``` - -This should start `matrix-synapse.service` first, the main worker. After that -all the workers should be started too. Check if the correct sockets appear and -if there are any error messages in the logs. - - -# nginx - -We may have a lot of workers, but if nginx doesn't forward traffic to the -correct worker(s), it won't work. We're going to have to change nginx's -configuration quite a bit. - -See [Deploying a Synapse Homeserver with -Docker](https://tcpipuk.github.io/synapse/deployment/nginx.html) for the -inspiration. This details a Docker installation, which we don't have, but the -reasoning behind it applies to our configuration too. - -Here's [how to configure nginx for use with workers](../../nginx/workers). diff --git a/matrix/synapse/workers/federation_receiver1.yaml b/matrix/synapse/workers/federation_receiver1.yaml deleted file mode 100644 index 64f394fa..00000000 --- a/matrix/synapse/workers/federation_receiver1.yaml +++ /dev/null @@ -1,15 +0,0 @@ -worker_app: "synapse.app.generic_worker" -worker_name: "federation_reader1" -worker_log_config: "/etc/matrix-synapse/logconf.d/federation_reader-log.yaml" - -worker_listeners: - - path: "/run/matrix-synapse/replication_federation_reader1.sock" - type: http - resources: - - names: [replication] - - - path: "/run/matrix-synapse/inbound_federation_reader1.sock" - type: http - resources: - - names: [federation] - diff --git a/matrix/synapse/workers/federation_sender1.yaml b/matrix/synapse/workers/federation_sender1.yaml deleted file mode 100644 index d2b0399c..00000000 --- a/matrix/synapse/workers/federation_sender1.yaml +++ /dev/null @@ -1,10 +0,0 @@ -worker_app: "synapse.app.generic_worker" -worker_name: "federation_sender1" -worker_log_config: "/etc/matrix-synapse/logconf.d/federation_sender-log.yaml" - -worker_listeners: - - path: "/run/matrix-synapse/replication_federation_sender1.sock" - type: http - resources: - - names: [replication] - diff --git a/matrix/synapse/workers/initial_sync1.yaml b/matrix/synapse/workers/initial_sync1.yaml deleted file mode 100644 index 45d9b858..00000000 --- a/matrix/synapse/workers/initial_sync1.yaml +++ /dev/null @@ -1,19 +0,0 @@ -worker_app: "synapse.app.generic_worker" -worker_name: "initial_sync1" -worker_log_config: "/etc/matrix-synapse/logconf.d/initial_sync-log.yaml" - -worker_listeners: - - - path: "/run/matrix-synapse/inbound_initial_sync1.sock" - type: http - resources: - - names: - - client - - consent - - federation - - - path: "/run/matrix-synapse/replication_initial_sync1.sock" - type: http - resources: - - names: [replication] - diff --git a/matrix/synapse/workers/login-log.yaml b/matrix/synapse/workers/login-log.yaml deleted file mode 100644 index 7cb59753..00000000 --- a/matrix/synapse/workers/login-log.yaml +++ /dev/null @@ -1,41 +0,0 @@ -version: 1 -formatters: - precise: - format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s' -handlers: - file: - class: logging.handlers.TimedRotatingFileHandler - formatter: precise - filename: /var/log/matrix-synapse/login.log - when: midnight - backupCount: 3 - encoding: utf8 - - buffer: - class: synapse.logging.handlers.PeriodicallyFlushingMemoryHandler - target: file - capacity: 10 - flushLevel: 30 - period: 5 - -loggers: - synapse.metrics: - level: WARN - handlers: [buffer] - synapse.replication.tcp: - level: WARN - handlers: [buffer] - synapse.util.caches.lrucache: - level: WARN - handlers: [buffer] - twisted: - level: WARN - handlers: [buffer] - synapse: - level: INFO - handlers: [buffer] - -root: - level: INFO - handlers: [buffer] - diff --git a/matrix/synapse/workers/login.yaml b/matrix/synapse/workers/login.yaml deleted file mode 100644 index c21bd540..00000000 --- a/matrix/synapse/workers/login.yaml +++ /dev/null @@ -1,19 +0,0 @@ -worker_app: "synapse.app.generic_worker" -worker_name: "login" -worker_log_config: "/etc/matrix-synapse/logconf.d/login-log.yaml" - -worker_listeners: - - - path: "/run/matrix-synapse/inbound_login.sock" - type: http - resources: - - names: - - client - - consent - - federation - - - path: "/run/matrix-synapse/replication_login.sock" - type: http - resources: - - names: [replication] - diff --git a/matrix/synapse/workers/media-log.yaml b/matrix/synapse/workers/media-log.yaml deleted file mode 100644 index bbddbc1d..00000000 --- a/matrix/synapse/workers/media-log.yaml +++ /dev/null @@ -1,41 +0,0 @@ -version: 1 -formatters: - precise: - format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s' -handlers: - file: - class: logging.handlers.TimedRotatingFileHandler - formatter: precise - filename: /var/log/matrix-synapse/media.log - when: midnight - backupCount: 3 - encoding: utf8 - - buffer: - class: synapse.logging.handlers.PeriodicallyFlushingMemoryHandler - target: file - capacity: 10 - flushLevel: 30 - period: 5 - -loggers: - synapse.metrics: - level: WARN - handlers: [buffer] - synapse.replication.tcp: - level: WARN - handlers: [buffer] - synapse.util.caches.lrucache: - level: WARN - handlers: [buffer] - twisted: - level: WARN - handlers: [buffer] - synapse: - level: INFO - handlers: [buffer] - -root: - level: INFO - handlers: [buffer] - diff --git a/matrix/synapse/workers/media.yaml b/matrix/synapse/workers/media.yaml deleted file mode 100644 index 65b3bf18..00000000 --- a/matrix/synapse/workers/media.yaml +++ /dev/null @@ -1,15 +0,0 @@ -worker_app: "synapse.app.media_repository" -worker_name: "mediaworker" -worker_log_config: "/etc/matrix-synapse/logconf.d/media-log.yaml" - -worker_listeners: - - path: "/run/matrix-synapse/inbound_mediaworker.sock" - type: http - resources: - - names: [media] - - - path: "/run/matrix-synapse/replication_mediaworker.sock" - type: http - resources: - - names: [replication] - diff --git a/website/.gitignore b/website/.gitignore deleted file mode 100644 index 726d2d63..00000000 --- a/website/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -result -.direnv diff --git a/website/README.md b/website/README.md deleted file mode 100644 index bc5ac99b..00000000 --- a/website/README.md +++ /dev/null @@ -1,92 +0,0 @@ -# Fediversity web site - -This web site is built with a static site generator based on the Nix language [module system](https://nix.dev/tutorials/module-system/). -It has unique features such as: -- correct-by-construction relative links, automatic redirects for moved pages -- correct-by-construction content fields -- customisable templating and content structure, all seamlessly expressed in the Nix language -- correct-by-construction spec-compliant HTML output -- content source organisation independent of output structure - -Structured content is managed through Nix expressions, and copy is written in [CommonMark](https://commonmark.org/). - -# Contributing - -- [Install Nix](https://nix.dev/install-nix) -- [Set up `direnv`](https://github.com/nix-community/nix-direnv#installation) -- Run `direnv allow` in the directory where repository is stored on your machine - - > **Note** - > - > This is a security boundary, and allows automatically running code from this repository on your machine. - -- Start a live preview in a different terminal: - - ```bash - devmode - ``` - - This will open your default web browser and automatically reload the page when the source changes. - -- Edit any of the files, see [repository layout](#repository-layout) for guidance - -# Testing - -As a derivation, e.g. for CI: - -```bash -nix-build -A tests -``` - -In the development shell: - -```bash -run-tests -``` - -Running tests in a loop on source code changes: - -```bash -test-loop -``` - -# Repository layout - -- [content](./content) - - Content of the web site is managed here. - The entry point is [`content/default.nix`](./content/default.nix) and is built to correspond to `index.html` in the result. - All other content sources are automatically included in `imports`, and can be accessed though the `config` module argument. - -- [structure](./structure) - - Definitions of content data structures, such as pages, articles, menus, collections, etc. - -- [presentation](./presentation) - - Code specific to how the web site is rendered. - In particular, it encodes the mechanism for distributing content to files, and for putting together files for the final result. - - In principle, different output formats (such as RSS feeds) are possible, and would be implemented there. - -- [default.nix](./default.nix) - - Entry point for building the project. - This is where content, structure, and presentation are wired up. - -- [shell.nix](./shell.nix) - - Convenience wrapper to enable running `nix-shell` without arguments. - -- [lib.nix](./lib.nix) - - Reusable convenience functions. - Also exposed under the `lib` attribute in [default.nix](./default.nix). - -- [npins](./npins) - - Dependencies, managed with [`npins`](https://github.com/andir/npins/). - -- [README.md](./README.md) - - This file. diff --git a/website/assets/images/avatar-sm.png b/website/assets/images/avatar-sm.png deleted file mode 100644 index e1699dc1..00000000 Binary files a/website/assets/images/avatar-sm.png and /dev/null differ diff --git a/website/assets/images/avatar.png b/website/assets/images/avatar.png deleted file mode 100755 index 387b035c..00000000 Binary files a/website/assets/images/avatar.png and /dev/null differ diff --git a/website/assets/images/avhuffelenmastodonpin.jpg b/website/assets/images/avhuffelenmastodonpin.jpg deleted file mode 100644 index ff8d07d5..00000000 Binary files a/website/assets/images/avhuffelenmastodonpin.jpg and /dev/null differ diff --git a/website/assets/images/banner.png b/website/assets/images/banner.png deleted file mode 100644 index 5f8a9e81..00000000 Binary files a/website/assets/images/banner.png and /dev/null differ diff --git a/website/assets/images/bergen-airport.jpeg b/website/assets/images/bergen-airport.jpeg deleted file mode 100644 index 1c026226..00000000 Binary files a/website/assets/images/bergen-airport.jpeg and /dev/null differ diff --git a/website/assets/images/call-to-action.png b/website/assets/images/call-to-action.png deleted file mode 100755 index ec2d625c..00000000 Binary files a/website/assets/images/call-to-action.png and /dev/null differ diff --git a/website/assets/images/checkbox-illustration-scaled.png b/website/assets/images/checkbox-illustration-scaled.png deleted file mode 100644 index e4bb37d8..00000000 Binary files a/website/assets/images/checkbox-illustration-scaled.png and /dev/null differ diff --git a/website/assets/images/checkbox-illustration.png b/website/assets/images/checkbox-illustration.png deleted file mode 100644 index 0bd2196f..00000000 Binary files a/website/assets/images/checkbox-illustration.png and /dev/null differ diff --git a/website/assets/images/code.png b/website/assets/images/code.png deleted file mode 100644 index 763b5a2b..00000000 Binary files a/website/assets/images/code.png and /dev/null differ diff --git a/website/assets/images/dc1.jpg b/website/assets/images/dc1.jpg deleted file mode 100644 index 74a7b92a..00000000 Binary files a/website/assets/images/dc1.jpg and /dev/null differ diff --git a/website/assets/images/favicon-archive.png b/website/assets/images/favicon-archive.png deleted file mode 100644 index 13f24a31..00000000 Binary files a/website/assets/images/favicon-archive.png and /dev/null differ diff --git a/website/assets/images/gallery/01.jpg b/website/assets/images/gallery/01.jpg deleted file mode 100644 index 662fc1dc..00000000 Binary files a/website/assets/images/gallery/01.jpg and /dev/null differ diff --git a/website/assets/images/gallery/02.jpg b/website/assets/images/gallery/02.jpg deleted file mode 100644 index 22fb37f8..00000000 Binary files a/website/assets/images/gallery/02.jpg and /dev/null differ diff --git a/website/assets/images/gallery/03.jpg b/website/assets/images/gallery/03.jpg deleted file mode 100644 index cea735f6..00000000 Binary files a/website/assets/images/gallery/03.jpg and /dev/null differ diff --git a/website/assets/images/gallery/04.jpg b/website/assets/images/gallery/04.jpg deleted file mode 100644 index 48d7c32b..00000000 Binary files a/website/assets/images/gallery/04.jpg and /dev/null differ diff --git a/website/assets/images/gallery/05.jpg b/website/assets/images/gallery/05.jpg deleted file mode 100644 index 09878097..00000000 Binary files a/website/assets/images/gallery/05.jpg and /dev/null differ diff --git a/website/assets/images/gallery/06.jpg b/website/assets/images/gallery/06.jpg deleted file mode 100644 index 662fc1dc..00000000 Binary files a/website/assets/images/gallery/06.jpg and /dev/null differ diff --git a/website/assets/images/globe.png b/website/assets/images/globe.png deleted file mode 100644 index aec66542..00000000 Binary files a/website/assets/images/globe.png and /dev/null differ diff --git a/website/assets/images/home.svg b/website/assets/images/home.svg deleted file mode 100644 index 164ca2fe..00000000 --- a/website/assets/images/home.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/website/assets/images/image-placeholder.png b/website/assets/images/image-placeholder.png deleted file mode 100755 index a61a0c09..00000000 Binary files a/website/assets/images/image-placeholder.png and /dev/null differ diff --git a/website/assets/images/kabelachterkant.jpg b/website/assets/images/kabelachterkant.jpg deleted file mode 100644 index 79612014..00000000 Binary files a/website/assets/images/kabelachterkant.jpg and /dev/null differ diff --git a/website/assets/images/logo-archive.png b/website/assets/images/logo-archive.png deleted file mode 100644 index afee1070..00000000 Binary files a/website/assets/images/logo-archive.png and /dev/null differ diff --git a/website/assets/images/logo-darkmode-archive.png b/website/assets/images/logo-darkmode-archive.png deleted file mode 100644 index c85cca95..00000000 Binary files a/website/assets/images/logo-darkmode-archive.png and /dev/null differ diff --git a/website/assets/images/logo-darkmode.png b/website/assets/images/logo-darkmode.png deleted file mode 100644 index 6dee57c3..00000000 Binary files a/website/assets/images/logo-darkmode.png and /dev/null differ diff --git a/website/assets/images/logo.png b/website/assets/images/logo.png deleted file mode 100644 index 6dee57c3..00000000 Binary files a/website/assets/images/logo.png and /dev/null differ diff --git a/website/assets/images/mastodon.svg b/website/assets/images/mastodon.svg deleted file mode 100644 index 3d811ac7..00000000 --- a/website/assets/images/mastodon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/website/assets/images/no-search-found.png b/website/assets/images/no-search-found.png deleted file mode 100755 index 1e1e6e16..00000000 Binary files a/website/assets/images/no-search-found.png and /dev/null differ diff --git a/website/assets/images/og-image.png b/website/assets/images/og-image.png deleted file mode 100644 index e31ac0e2..00000000 Binary files a/website/assets/images/og-image.png and /dev/null differ diff --git a/website/assets/images/rack.jpg b/website/assets/images/rack.jpg deleted file mode 100644 index a963c264..00000000 Binary files a/website/assets/images/rack.jpg and /dev/null differ diff --git a/website/assets/images/service-1.png b/website/assets/images/service-1.png deleted file mode 100755 index 5842791a..00000000 Binary files a/website/assets/images/service-1.png and /dev/null differ diff --git a/website/assets/images/service-2.png b/website/assets/images/service-2.png deleted file mode 100755 index 2cc116a3..00000000 Binary files a/website/assets/images/service-2.png and /dev/null differ diff --git a/website/assets/images/service-3.png b/website/assets/images/service-3.png deleted file mode 100755 index cf690b7a..00000000 Binary files a/website/assets/images/service-3.png and /dev/null differ diff --git a/website/assets/images/stepping-up.png b/website/assets/images/stepping-up.png deleted file mode 100644 index 1dbd9f19..00000000 Binary files a/website/assets/images/stepping-up.png and /dev/null differ diff --git a/website/assets/images/tvtoren1.jpg b/website/assets/images/tvtoren1.jpg deleted file mode 100644 index 0475d869..00000000 Binary files a/website/assets/images/tvtoren1.jpg and /dev/null differ diff --git a/website/assets/images/uitzicht.jpg b/website/assets/images/uitzicht.jpg deleted file mode 100644 index aaf0ab87..00000000 Binary files a/website/assets/images/uitzicht.jpg and /dev/null differ diff --git a/website/assets/images/user.png b/website/assets/images/user.png deleted file mode 100644 index 810e426d..00000000 Binary files a/website/assets/images/user.png and /dev/null differ diff --git a/website/assets/images/users-scaled.png b/website/assets/images/users-scaled.png deleted file mode 100644 index 519e40da..00000000 Binary files a/website/assets/images/users-scaled.png and /dev/null differ diff --git a/website/assets/images/users.png b/website/assets/images/users.png deleted file mode 100644 index e852fe72..00000000 Binary files a/website/assets/images/users.png and /dev/null differ diff --git a/website/assets/images/users.svg b/website/assets/images/users.svg deleted file mode 100644 index 5bf51a75..00000000 --- a/website/assets/images/users.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/website/assets/images/website-new.png b/website/assets/images/website-new.png deleted file mode 100644 index 84409045..00000000 Binary files a/website/assets/images/website-new.png and /dev/null differ diff --git a/website/assets/scss/base.scss b/website/assets/scss/base.scss deleted file mode 100755 index 336b27d4..00000000 --- a/website/assets/scss/base.scss +++ /dev/null @@ -1,59 +0,0 @@ -html { - @apply text-base-sm md:text-base; -} - -body { - @apply bg-body font-primary font-normal leading-relaxed text-text; -} - -h1, -h2, -h3, -h4, -h5, -h6 { - @apply font-secondary font-bold leading-tight text-dark; -} - -h1, -.h1 { - @apply text-h1-sm md:text-h1; -} - -h2, -.h2 { - @apply text-h2-sm md:text-h2; -} - -h3, -.h3 { - @apply text-h3-sm md:text-h3; -} - -h4, -.h4 { - @apply text-h4; -} - -h5, -.h5 { - @apply text-h5; -} - -h6, -.h6 { - @apply text-h6; -} - -b, -strong { - @apply font-semibold; -} - -code { - @apply after:border-none; -} - -blockquote > p { - @apply my-0 #{!important}; -} diff --git a/website/assets/scss/buttons.scss b/website/assets/scss/buttons.scss deleted file mode 100755 index 8b4c8b18..00000000 --- a/website/assets/scss/buttons.scss +++ /dev/null @@ -1,15 +0,0 @@ -.btn { - @apply inline-block rounded border border-transparent px-5 py-2 font-semibold capitalize transition; -} - -.btn-sm { - @apply rounded-sm px-4 py-1.5 text-sm; -} - -.btn-primary { - @apply border-primary bg-primary text-white; -} - -.btn-outline-primary { - @apply border-dark text-dark hover:bg-dark bg-transparent hover:text-white; -} diff --git a/website/assets/scss/components.scss b/website/assets/scss/components.scss deleted file mode 100755 index 97eb781f..00000000 --- a/website/assets/scss/components.scss +++ /dev/null @@ -1,74 +0,0 @@ -main { - min-height: 70vh; -} - -// section style -.section { - @apply py-24 xl:py-28; - &-sm { - @apply py-16 xl:py-20; - } -} - -// container -.container { - @apply mx-auto px-4 2xl:max-w-[1320px]; -} - -// form style -.form-input { - @apply bg-theme-light text-dark placeholder:text-light focus:border-primary w-full rounded border-transparent px-6 py-4 focus:ring-transparent; -} - -.form-label { - @apply font-secondary text-dark mb-4 block text-xl font-normal; -} - -// social icons -.social-icons { - @apply space-x-4; - li { - @apply inline-block; - a { - @apply bg-primary flex h-9 w-9 items-center justify-center rounded text-center leading-9 text-white; - svg { - @apply h-5 w-5; - } - } - } -} - -// swiper pagination -.swiper-pagination-bullet { - @apply bg-theme-light h-2.5 w-2.5 opacity-100 mx-1.5 #{!important}; - - &-active { - @apply bg-primary h-4 w-4 #{!important}; - } -} - -// content style -.content { - @apply prose max-w-none; - @apply prose-headings:mb-[.3em] prose-headings:mt-[.6em] prose-headings:text-dark; - @apply prose-h1:text-h1-sm md:prose-h1:text-h1; - @apply prose-h2:text-h2-sm md:prose-h2:text-h2; - @apply prose-h3:text-h3-sm md:prose-h3:text-h3; - @apply prose-img:max-w-full prose-img:rounded; - @apply prose-hr:border-border; - @apply prose-p:text-base prose-p:text-text; - @apply prose-blockquote:rounded-lg prose-blockquote:border prose-blockquote:border-l-[10px] prose-blockquote:border-primary prose-blockquote:bg-theme-light prose-blockquote:px-8 prose-blockquote:py-10 prose-blockquote:font-secondary prose-blockquote:text-2xl prose-blockquote:not-italic prose-blockquote:text-dark; - @apply prose-pre:rounded-lg prose-pre:bg-theme-light; - @apply prose-code:px-1; - @apply prose-strong:text-dark; - @apply prose-a:text-text prose-a:underline hover:prose-a:text-primary; - @apply prose-li:text-text; - @apply prose-table:relative prose-table:overflow-hidden prose-table:rounded-lg prose-table:before:absolute prose-table:before:left-0 prose-table:before:top-0 prose-table:before:h-full prose-table:before:w-full prose-table:before:rounded-[inherit] prose-table:before:border prose-table:before:content-[""]; - @apply prose-thead:border-border prose-thead:bg-theme-light; - @apply prose-th:relative prose-th:z-10 prose-th:px-4 prose-th:py-[18px] prose-th:text-dark; - @apply prose-tr:border-border; - @apply prose-td:relative prose-td:z-10 prose-td:px-3 prose-td:py-[18px]; - .btn { - @apply no-underline hover:text-white #{!important}; - } -} diff --git a/website/assets/scss/custom.scss b/website/assets/scss/custom.scss deleted file mode 100755 index ae596155..00000000 --- a/website/assets/scss/custom.scss +++ /dev/null @@ -1,127 +0,0 @@ -// Add your own custom styles here -.grid-container { - display: flex; - justify-content: space-between; - } - - .column { - flex-basis: calc(50% - 10px); /* Adjust width as necessary */ - } - - .list { - list-style-type: none; - padding: 0; - } - - .list-item { - margin-bottom: 10px; - } - - .link { - text-decoration: none; - color: inherit; - } - - .title { - font-weight: bold; - } - - .hr-list { - border: 0; - border-top: 1px solid #ccc; - margin-top: 5px; - margin-bottom: 5px; - } - - .list-item { - display: flex; - justify-content: space-between; - align-items: center; - } - - .content { - flex: 1; - } - - .link { - text-align: left; - } - - .time { - text-align: right; - } - - - .grid-container { - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 20px; - } - - .grid-item { - - padding: 20px; - } - - .header-with-image { - display: flex; - align-items: flex-start; - } - - .header-with-image img { - margin-right: 10px; - max-width: 100px; /* Adjust as needed */ - max-height: 100px; /* Adjust as needed */ - align-items: center; - } - - .read-more-link { - color: #FF6E00; /* Use the variable defined in theme.json */ - } - - .center-wrapper { - display: flex; - justify-content: center; - align-items: center; - - } - - .grid-container-small { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 20px; - } - - .hr-list { - margin-top: 0; - margin-bottom: 0; - margin-right: .5rem; - } - - .center-layout { - display: flex; - justify-content: center; - - - } - - .hr-list2 { - border: 20; - border-top: 1px solid #FF6E00; - margin-top: 5px; - margin-bottom: 5px; - } - - .header-with-image2 { - text-align: center; - } - - .header-with-image2 img { - display: inline-block; - - } - - .line { - border-top: 1px solid #FF6E00; /* Change color and thickness as needed */ - margin: 10px 0; /* Adjust spacing between the line and the divs */ -} \ No newline at end of file diff --git a/website/assets/scss/main.scss b/website/assets/scss/main.scss deleted file mode 100755 index 4bbaf781..00000000 --- a/website/assets/scss/main.scss +++ /dev/null @@ -1,30 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; - -@layer base { - @import "base"; -} - -@layer components { - @import "components"; - @import "navigation"; - @import "buttons"; -} - -@layer utilities { - @import "utilities"; -} - -@import "search"; -@import "social-share"; -@import "gallery-slider"; -@import "images"; -@import "toc"; -@import "tab"; -@import "accordion"; -@import "modal"; -@import "notice"; - -@import "module-overrides"; -@import "custom"; diff --git a/website/assets/scss/module-overrides.scss b/website/assets/scss/module-overrides.scss deleted file mode 100644 index 8a122670..00000000 --- a/website/assets/scss/module-overrides.scss +++ /dev/null @@ -1,57 +0,0 @@ -// table of contents -.table-of-content { - @apply overflow-hidden rounded; -} - -// share icons -.share-icons { - .share-link { - @apply h-9 w-9 rounded leading-9; - @apply bg-primary hover:bg-primary; - } - .share-icon svg { - } -} - -// notice -.notice { - @apply rounded-lg; -} - -// tab -.tab { - @apply border-border overflow-hidden rounded-lg border; - &-nav { - @apply border-border bg-theme-light pl-4; - - &-item { - @apply text-dark px-8 text-lg #{!important}; - &.active { - @apply border-dark; - } - } - } - &-content { - &-panel { - @apply px-4 pt-0 #{!important}; - } - } -} - -// accordion -.accordion { - @apply border-border bg-theme-light mb-6 overflow-hidden rounded-lg border; - &-header { - @apply text-dark; - } -} - -// cookie consent -.cookie-box { - @apply rounded-lg #{!important}; -} - -// slider -.gallery-slider { - @apply ml-0 #{!important}; -} diff --git a/website/assets/scss/navigation.scss b/website/assets/scss/navigation.scss deleted file mode 100755 index a97aa2c2..00000000 --- a/website/assets/scss/navigation.scss +++ /dev/null @@ -1,87 +0,0 @@ -// navbar toggler -input#nav-toggle:checked + label #show-button { - @apply hidden; -} - -input#nav-toggle:checked + label #hide-button { - @apply block; -} - -input#nav-toggle:checked ~ #nav-menu { - @apply block; -} - -.header { - @apply bg-body py-6; -} - -// navbar items -.navbar { - @apply relative flex flex-wrap items-center justify-between; -} - -.navbar-brand { - @apply text-dark text-xl font-semibold; - image { - @apply max-h-full max-w-full; - } -} - -.navbar-nav { - @apply text-center lg:text-left; -} - -// .nav-item { -// @apply mx-3; -// } - -.nav-link { - @apply text-dark hover:text-primary block p-3 cursor-pointer font-semibold transition lg:px-2 lg:py-3; -} - -.nav-dropdown { - @apply mr-0; - & > svg { - @apply pointer-events-none; - } - &.active { - .nav-dropdown-list { - @apply block; - } - } -} - -.nav-dropdown-list { - @apply bg-body z-10 min-w-[180px] rounded p-4 shadow hidden lg:invisible lg:absolute lg:block lg:opacity-0; -} - -.nav-dropdown-item { - @apply [&:not(:last-child)]:mb-2; -} - -.nav-dropdown-link { - @apply text-dark hover:text-primary block py-1 font-semibold transition; -} - -//theme-switcher -.theme-switcher { - @apply inline-flex; - - label { - @apply bg-border relative inline-block h-4 w-6 cursor-pointer rounded-2xl lg:w-10; - } - - input { - @apply absolute opacity-0; - } - - span { - @apply bg-dark absolute -top-1 left-0 flex h-6 w-6 items-center justify-center rounded-full transition-all duration-300; - } - - input:checked + label { - span { - @apply lg:left-4; - } - } -} diff --git a/website/assets/scss/utilities.scss b/website/assets/scss/utilities.scss deleted file mode 100755 index 7889b3a5..00000000 --- a/website/assets/scss/utilities.scss +++ /dev/null @@ -1,20 +0,0 @@ -.bg-gradient { - @apply bg-gradient-to-b from-[rgba(249,249,249,1)] from-[0.53%] to-white to-[83.28%]; -} - -.rounded-sm { - @apply rounded-[4px]; -} -.rounded { - @apply rounded-[6px]; -} -.rounded-lg { - @apply rounded-[12px]; -} -.rounded-xl { - @apply rounded-[16px]; -} - -.shadow { - box-shadow: 0px 4px 40px rgba(0, 0, 0, 0.05); -} diff --git a/website/content/default.nix b/website/content/default.nix deleted file mode 100644 index 0aa4dc38..00000000 --- a/website/content/default.nix +++ /dev/null @@ -1,184 +0,0 @@ -{ config, lib, ... }: -let - inherit (config) pages; - cfg = config; -in -{ - imports = lib.nixFiles ./.; - - collections.news.type = cfg.content-types.article; - collections.events.type = cfg.content-types.event; - - pages.index = - { config, link, ... }: - { - title = "Welcome to the Fediversity project"; - description = "Fediversity web site"; - summary = '' - This web site hosts up-to-date information about the the NGI Zero Fediversity project. - ''; - body = '' - ${pages.fediversity.summary} - - [Learn more about Fediversity](${link pages.fediversity}) - ''; - outputs.html = (cfg.templates.html.page config).override ( - _final: prev: { - html = { - head.title.text = "Fediversity"; - head.link.stylesheets = prev.html.head.link.stylesheets ++ [ - { href = "${link cfg.assets."index.css"}"; } - ]; - body.content = - let - to-section = - { - heading, - body, - attrs ? { }, - }: - { - section = { - heading.content = heading; - inherit attrs; - content = [ - (cfg.templates.html.markdown { - name = "${config.name}-${lib.slug heading}"; - inherit body; - }) - ]; - }; - }; - in - [ - (lib.head prev.html.body.content) - { - section = { - attrs = { }; - heading.content = config.title; - content = - [ - (cfg.templates.html.markdown { inherit (config) name body; }) - ] - ++ (map to-section [ - { - heading = "Fediversity grants"; - body = '' - ${pages.grants.summary} - - [Learn more about Fediversity grants](${link pages.grants}) - ''; - } - { - heading = "Consortium"; - body = '' - The Consortium behind the Fediversity project is a cooperation between NLnet, Open Internet Discourse Foundation, NORDUnet and Tweag. - - ${toString ( - map - (partner: '' - ### ${partner.title} - - ${partner.summary} - - [Read more about ${partner.title}](${link partner}) - '') - ( - with pages; - [ - nlnet - oid - tweag - nordunet - ] - ) - )} - ''; - } - { - heading = "Fediverse explained"; - body = '' - ${toString ( - map - (role: '' - ### ${role.title} - - ${role.summary} - - [Read more about ${role.title}](${link role}) - '') - ( - with pages; - [ - individuals - developers - european-commission - ] - ) - )} - ''; - } - ]); - }; - } - ] - ++ (map to-section [ - { - heading = "News"; - attrs = { - class = [ "collection" ]; - }; - body = - let - sorted = with lib; reverseList (sortOn (entry: entry.date) cfg.collections.news.entry); - in - lib.join "\n" ( - map (article: '' - - ${article.date} [${article.title}](${link article}) - '') sorted - ); - } - { - heading = "Events"; - attrs = { - class = [ "collection" ]; - }; - body = - let - sorted = with lib; reverseList (sortOn (entry: entry.start-date) cfg.collections.events.entry); - in - lib.join "\n" ( - map (article: '' - - ${article.start-date} [${article.title}](${link article}) - '') sorted - ); - } - ]); - }; - - } - ); - }; - - assets."index.css".path = - with lib; - builtins.toFile "index.css" '' - section h1, section h2, section h3 - { - text-align: center; - } - section h1 { - font-size: 3em; - } - section h2 { - font-size: 2.5em; - } - section h3 { - font-size: 1.5em; - } - section.collection h1 { - font-size: 2em; - text-align: left; - } - ''; -} diff --git a/website/content/developers.nix b/website/content/developers.nix deleted file mode 100644 index 5416d95a..00000000 --- a/website/content/developers.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ ... }: -{ - pages.developers = { - title = "Developers"; - description = "Information for developers about the Fediversity project"; - summary = '' - As a developer building the next generation of social platforms, you are looking to make it easier to facilitate your customers to use your product. Fediversity can help. - ''; - body = '' - The Fediversity Project enables easy hosting for a wide variety of fediverse platforms, all based on NixOS. At the start, the project will support Mastodon, PixelFed,PeerTube, Matrix and Nexcloud, and the project is actively working to expand this offering. Other services that are offered are email (based on Stalwart) and domain registry. - - As part of the NGI Funding, the Fediversity Project also offers grants to developers to expand the ecosystem. The NLNet website has more information on how you as a developer can apply to grants, ranging from 5.000 to 50.000 euro's. - - If you are a developer of fediverse software, and would like to get your platform also offered for easy hosting as part of the Fediversity Project, please reach out to us. You can contact us HERE. - - As the project is based upon NixOS, we are actively supporting making fediverse projects available as nix packages. If your project is on the fence about this, please reach out. Nix packages make updating and maintaining fediverse projects a breeze! - ''; - }; -} diff --git a/website/content/european-commission.nix b/website/content/european-commission.nix deleted file mode 100644 index 79a0438f..00000000 --- a/website/content/european-commission.nix +++ /dev/null @@ -1,15 +0,0 @@ -{ ... }: -{ - pages.european-commission = { - title = "European Commission"; - description = "Information about the Fediversity project for the grant providers"; - summary = '' - The Fediversity Project operates on a grant gratiously provided by the HORIZON fund by the EC. Learn more about the accountability of the project. - ''; - body = '' - The Fediversity project implements the visions outlined by the Next Generation Internet (NGI) initiative for an open internet in several ways. Most importantly, it helps with decentralisation of the internet, a core principle of the NGI, by making it easier for people to participate in the Open Social Web on their own terms. NGI's goal of empowering individuals in the digital sphere is helped by making it easy for them to set up their own servers and platforms. While a variety of Fediverse software exist, there are still barriers of entry for people. In order for people to be truly empowered, joining the fediverse needs to be as weasy as possible. Additionally, the Fediverse emphasises interoperability and openness, which are key concerns addressed by the NGI. - - Part of the values of openness and transparency of is that the Fediversity project is that all the deliverables of the projects are have a 'Public' Dissemination level. On this page an overview of all deliverables of the Fediversity project can be found. - ''; - }; -} diff --git a/website/content/events.nix b/website/content/events.nix deleted file mode 100644 index 6d92ffb5..00000000 --- a/website/content/events.nix +++ /dev/null @@ -1,26 +0,0 @@ -{ config, lib, ... }: -{ - pages.events = - { link, ... }: - rec { - title = "Events"; - description = "Events related to the Fediverse and NixOS"; - summary = description; - body = - with lib; - let - events = map ( - event: with lib; '' - ## [${event.title}](${link event}) - - ${event.start-date} ${ - optionalString (!isNull event.end-date && event.end-date != event.start-date) "to ${event.end-date}" - } in ${event.location} - '' - ) config.collections.events.entry; - in - '' - ${join "\n" events} - ''; - }; -} diff --git a/website/content/events/2024-11-zurich-zhf.nix b/website/content/events/2024-11-zurich-zhf.nix deleted file mode 100644 index 8f634586..00000000 --- a/website/content/events/2024-11-zurich-zhf.nix +++ /dev/null @@ -1,25 +0,0 @@ -{ config, ... }: -{ - collections.events.entry = - { link, ... }: - { - title = "NixOS 24.11 ZHF hackathon"; - name = "zhf-24-11"; - description = "NixOS 24.11 ZHF hackathon in Zürich"; - start-date = "2024-11-23"; - end-date = "2024-11-24"; - start-time = "10:00"; - end-time = "17:00"; - location = "OST Campus Rapperswil"; - body = '' - The biannual [Zürich NixOS ZHF hackathon](https://zurich.nix.ug/) has become somewhat of an institution for maintaining the tradition of preparing the upcoming NixOS release. - - The main goal of the two-day gathering is to bring down the number of build failures on the [continuous integration system Hydra](https://status.nixos.org/) before the release: ZHF stands for *Zero Hydra Failures*. - It also presents a great opportunity to learn Nix, squash bugs together, get to know each other, discuss current events, and make plans for the future. - - This is the greatest event in the series so far, with more than 40 participants from all over Europe, including many high-profile contributors and maintainers in the Nix ecosystem. - - [Fediversity engineers attended](${link config.collections.news.by-name.zhf-24-11}) to present prototypes and exchange ideas with other developers. - ''; - }; -} diff --git a/website/content/events/owc-annual-conference-2024.nix b/website/content/events/owc-annual-conference-2024.nix deleted file mode 100644 index f44d5208..00000000 --- a/website/content/events/owc-annual-conference-2024.nix +++ /dev/null @@ -1,26 +0,0 @@ -{ ... }: -{ - collections.events.entry = - { ... }: - { - title = "OW2con 2024"; - description = "OW2con is the annual European open source conference in Paris"; - start-date = "2024-06-11"; - end-date = "2024-06-12"; - start-time = "09:00"; - end-time = "18:00"; - location = "Paris-Chatillon"; - body = '' - OW2con is the European open source conference organized by OW2. - An international meeting of developpers, IT companies, academics and non-profit organizations, OW2con brings together the entire open source community, during two days of presentations ranging from tech topics to business and ethical issues of open source. - It also offers a unique opportunity to establish contact with peers through friendly networking sessions. - OW2con is [open](https://www.ngi.eu/event/open-source-community-annual-conference-2024/) to all, the event is free and all sessions are held in English. - - The OW2con’24 call for presentations is open. - This year we are giving the highlight on the theme of open source funding: - What are the current solutions for innovators, start-ups or ISVs to finance their development? - Private or public financing? - Are national and European public policies up to the challenges? - ''; - }; -} diff --git a/website/content/events/publicspaces-conference-2024.nix b/website/content/events/publicspaces-conference-2024.nix deleted file mode 100644 index 3f2af58a..00000000 --- a/website/content/events/publicspaces-conference-2024.nix +++ /dev/null @@ -1,20 +0,0 @@ -{ ... }: -{ - collections.events.entry = - { ... }: - { - title = "PublicSpaces Conference 2024"; - description = "A conference by PublicSpaces, Taking Back the Internet."; - start-date = "2024-06-06"; - end-date = "2024-06-07"; - start-time = "09:00"; - end-time = "18:00"; - location = "Pakhuis de Zwijger - Amsterdam"; - body = '' - On June 6th and 7th, PublicSpaces and Waag Futurelab proudly present the fourth edition of the PublicSpaces conference under the theme 'Empowering the Internet'. - Held at Pakhuis de Zwijger, this two-day event will feature panels, keynotes, roundtable discussions, lectures, as well as art and cultural showcases, all aimed at collectively shaping the rules for a more inclusive internet. - Join us as we navigate towards a digital landscape where everyone has a voice. - For more information, check out the [website](https://publicspaces.net/2024/02/01/save-the-date-publicspaces-conferentie-2024/) - ''; - }; -} diff --git a/website/content/events/waag-state-internet-2024.nix b/website/content/events/waag-state-internet-2024.nix deleted file mode 100644 index 0c6d607b..00000000 --- a/website/content/events/waag-state-internet-2024.nix +++ /dev/null @@ -1,27 +0,0 @@ -{ ... }: -{ - collections.events.entry = - { ... }: - { - title = "State of the Internet 2024"; - description = "The State of the Internet 2024 by Waag"; - start-date = "2024-05-16"; - end-date = "2024-05-16"; - start-time = "18:00"; - end-time = "20:00"; - location = "OBA Oosterdok - Amsterdam"; - body = '' - Join us at the State of the Internet 2024, where Waag Futurelab, alongside the Municipality of Amsterdam and the OBA, delves into the depths of the online realm. - Featuring Kim van Sparrentak, Member of the European Parliament, discussing Europe's efforts to regulate Big Tech and enhance digital rights. - Explore the impact of pivotal European laws like the GDPR and AI Act while celebrating 30 years of Waag Futurelab's dedication to democratizing technology access for all. - - The event takes place at: - - OBA Oosterdok
- Oosterdokskade 143
- 1011 DK Amsterdam - - Registration available [here](https://waag.org/nl/event/de-staat-van-het-internet-2024-met-kim-van-sparrentak/). - ''; - }; -} diff --git a/website/content/fediversity.nix b/website/content/fediversity.nix deleted file mode 100644 index 4e8f2ccb..00000000 --- a/website/content/fediversity.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ ... }: -{ - pages.fediversity = { - title = "Fediversity"; - description = "More information about the Fediversity project"; - summary = '' - The Fediversity Project is a comprehensive effort to bring easy-to-use, hosted cloud services that have service portability and personal freedom at their core to everyone. - ''; - body = '' - Fediversity is a comprehensive effort to bring easy-to-use, hosted cloud services with service portability and personal freedom at their core to everyone. It wants to provide everyone with high-quality, secure IT systems for everyday use. Without tracking, without exploitation, in a way that runs everywhere and scales effortlessly. Fediversity is based on NixOS, a disruptive Linux distribution with a unique approach to package and configuration management. Built on top of the Nix package manager, NixOS is completely declarative, makes upgrading systems reliable, and has many other advantages. Because it is reproducible, it is ideally suited for complex deployment scenario’s where consistent behaviour, stability and configurability matter. - - One such “complex” deployment scenario is running state-of-the-art services for the Fediverse, like PeerTube, Mastodon, Owncast or Lemmy — especially if you want to for instance add services like live chat or transcoding. But even running more traditional services like modern e-mail servers with possible whistles and bells can be daunting. The same holds for deploying a VPN, private cloud storage, wiki, etc. Fediversity will enable all of these use cases, and more — finally bringing these to the market in a way that is as conveient as using a hosted service. - - Fediversity is a pilot funded by the European Commission, building on many projects funding through the Next Generation Internet initiative. The results of the project should greatly simplify the creation and delivery of robust and secure services, on the web and beyond. - - Fediversity will deliver an ambitious development effort, but this is a vast domain with many more challenges than what any preconceived effort could tackle by itself. This is why we invite your contribution to help us reshape the state of play, and together create an open, trustworthy and reliable internet for all. - ''; - }; -} diff --git a/website/content/grants.nix b/website/content/grants.nix deleted file mode 100644 index 2dfe1344..00000000 --- a/website/content/grants.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ ... }: -{ - pages.grants = { - title = "Grants"; - description = "How to apply for grants as part of the Fediversity Project"; - summary = '' - Fediversity will award 450 000 euro in small to medium-size R&D grants towards solutions that bring the next generation of social networks closer. We are seeking project proposals between 5.000 and 50.000 euro’s — which should get you on your way. - ''; - body = '' - Fediversity invites other people to join this ambitious development effort. It is a vast domain with many more challenges than what any preconceived effort could tackle by itself. This is why we invite your contribution to help us reshape the state of play, and together create an open, trustworthy and reliable internet for all. - - This is your opportunity to make a real difference. You tell us how your project can help Fediversity go harder, better, faster, stronger. In order to enable you to make such contributions, NLnet will award 450 000 euro in small to medium-size R&D grants towards solutions that bring the next generation of social networks closer. NLnet is seeking project proposals between 5.000 and 50.000 euro’s — which should get you on your way. - - Noteworthy fact: many projects which are to be deployed inside Fediversity were themselves bootstrapped on precisely such a grant from NGI, and now it is your turn. - - For more information on how to apply, check the NLnet website. - ''; - }; -} diff --git a/website/content/individuals.nix b/website/content/individuals.nix deleted file mode 100644 index bf041d30..00000000 --- a/website/content/individuals.nix +++ /dev/null @@ -1,20 +0,0 @@ -{ ... }: -{ - pages.individuals = { - title = "Individuals"; - description = "Information about the project for regular people"; - summary = '' - Always be in control with your own data on social networks, whether that’s with Mastodon, PeerTube or Pixelfed: Fediversity makes it possible. - ''; - body = '' - The fediverse shows great potential in fundamentally rethinking how we approach the internet. It is a new way of thinking about how the internet can be a social web, and solves for the problems that the current Big Tech platforms have, while at the same time enabling a new wave of innovation and new ideas on the social web. - - - Giving people control of their data and social connections, allowing them to choose whatever platform and product they want. - - Giving people control of their privacy and their feeds, without black-box algorithms that decide for them what they get to see. - - The Fediversity project is working on making it easier for people to join the fediverse, and taking full control on their own online social presence. We make it easier for you to join the fediverse, giving you an easy way to select what you need. With one click, you can select whether you need photo sharing, microblogging, video sharing, blogging or simply email. You can get a domain name as well, so you can be up and running with a professional social presence on the new internet in without any effort. - - Fediversity is currently in development, and you can follow us on Mastodon for all the latest information. - ''; - }; -} diff --git a/website/content/navigation.nix b/website/content/navigation.nix deleted file mode 100644 index 5f7481bf..00000000 --- a/website/content/navigation.nix +++ /dev/null @@ -1,49 +0,0 @@ -{ config, ... }: -let - inherit (config) pages; -in -{ - menus.main = { - label = "Main"; - items = [ - { - page = pages.index // { - title = "Start"; - }; - } - { - menu.label = "For you"; - menu.items = map (page: { inherit page; }) ( - with pages; - [ - individuals - developers - european-commission - ] - ); - } - { - menu.label = "Consortium"; - menu.items = map (page: { inherit page; }) ( - with pages; - [ - nlnet - oid - tweag - nordunet - ] - ); - } - { page = pages.fediversity; } - { page = pages.grants; } - { page = pages.news; } - { page = pages.events; } - { - link = { - label = "Contact"; - url = "mailto:contact@fediversity.eu"; - }; - } - ]; - }; -} diff --git a/website/content/news.nix b/website/content/news.nix deleted file mode 100644 index 96d7c160..00000000 --- a/website/content/news.nix +++ /dev/null @@ -1,24 +0,0 @@ -{ config, lib, ... }: -{ - pages.news = - { link, ... }: - rec { - title = "News"; - description = "News about Fediversity"; - summary = description; - body = - with lib; - let - news = map (article: '' - ## [${article.title}](${link article}) - - ${article.date} by ${article.author} - - ${article.summary} - '') config.collections.news.entry; - in - '' - ${join "\n\n" news} - ''; - }; -} diff --git a/website/content/news/2024-11-zurich-zhf.nix b/website/content/news/2024-11-zurich-zhf.nix deleted file mode 100644 index be331c04..00000000 --- a/website/content/news/2024-11-zurich-zhf.nix +++ /dev/null @@ -1,24 +0,0 @@ -{ config, ... }: -{ - collections.news.entry = - { link, ... }: - rec { - name = "zhf-24-11"; - title = "NixOS 24.11 release hackathon and workshop"; - description = "Fediversity engineers met in Zürich at a NixOS 24.11 ZHF hackathon"; - date = "2024-11-28"; - author = "Valentin Gagarin"; - summary = '' - Fediversity engineers met in Zürich at a [NixOS 24.11 ZHF hackathon](${link config.collections.events.by-name.zhf-24-11}) to present prototypes and exchange ideas with the Nix community. - ''; - body = '' - ${summary} - - Robert held a lightning talk on the design of [NixOps4](https://github.com/nixops4/nixops4), which is currently in the prototype stage of development. - Before that, Nicolas had already shown an internal demonstration that NixOps4 is capable of deploying multiple NixOS services in the Fediversity test environment. - - In the afternoon, Robert, Valentin, and Koen got together with Eli from [Thymis](https://thymis.io) and Johannes from [Clan](https://clan.lol/) to walk each other through the architecture of their respective systems. - This was an extraordinarily fruitful encounter that helped us to identify overlaps and potential for future collaboration! - ''; - }; -} diff --git a/website/content/news/nordunet-conference.nix b/website/content/news/nordunet-conference.nix deleted file mode 100644 index 17ffefad..00000000 --- a/website/content/news/nordunet-conference.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ ... }: -{ - collections.news.entry = { - title = "Nordunet Conference 2024"; - description = "Report from the NORDUnet Conference 2024"; - date = "2024-09-17"; - author = "Laurens Hof"; - summary = '' - Fediversity was represented in Bergen at the Nordunet Conference for 2024, with both the Internet Discourse Foundation and Nordunet themselves being present. - ''; - body = '' - Fediversity was represented in Bergen at the Nordunet Conference for 2024, with both the Internet Discourse Foundation and Nordunet themselves being present. This was a great opportunity for the different organisations in the consortium to meet with each other and exchange ideas. - - One of those new ideas that came out of the conference is to think about offering [EduMEET](https://edumeet.org/) as a part of Fediversity. EduMEET is an open source video conferencing platform that is build for and by the Research and Education community. EduMEET allows for the possibility of recording conference calls, but does not offer an easy place to host these recordings. PeerTube is already mature fediverse software that offers video hosting. Combining these two pieces of software in the offering to onboard public organisations can make it easier to offer a complete package for the organisations. It can potentially help lower the barrier of entry, while at the same time making it more attractive for public education organisations to start using fediverse software. - - Fediversity is now starting to explore if and how efforts with Nordunet to promote EduMEET can be combined with Fediversity's (and thus Nordunet!) project to promote the fediverse. - - Another aspect that came out of the conference is the possibility to use [Argus](https://openargus.org/) as a real-time monitoring tool as part of our hosting stack that we're building. How to do real-time monitoring was so far still unclear in our plans for building a Nix panel, but Argus might just be the open source tool we're looking for. - - It was exciting to meet so many people in the community that are all working towards building better digital systems for public organisations, and we're proud to contribute our small piece to a much larger puzzle. Hope to meet more of you all soon! - ''; - }; -} diff --git a/website/content/news/project-launch.nix b/website/content/news/project-launch.nix deleted file mode 100644 index 5d59a853..00000000 --- a/website/content/news/project-launch.nix +++ /dev/null @@ -1,22 +0,0 @@ -{ ... }: - -{ - collections.news.entry = - { ... }: - { - title = "Fediversity project publicly announced"; - description = "The Fediversity project has officially been announced"; - date = "2024-01-01"; - author = "Laurens Hof"; - summary = '' - We are pleased to introduce the launch of our new website dedicated to the Fediversity project. - ''; - body = '' - The Consortium behind the Fediversity project announces that the project has officially been started. NLnet, Tweag, NorduNet and the Open Internet Discourse Foundation are working together to build a new service for cloud hosters. - - Fediversity is a comprehensive effort to bring easy-to-use, hosted cloud services with service portability and personal freedom at their core to everyone. It wants to provide everyone with high-quality, secure IT systems for everyday use. Without tracking, without exploitation, in a way that runs everywhere and scales effortlessly. Fediversity is based on NixOS, a disruptive Linux distribution with a unique approach to package and configuration management. Built on top of the Nix package manager, NixOS is completely declarative, makes upgrading systems reliable, and has many other advantages. Because it is reproducible, it is ideally suited for complex deployment scenario's where consistent behaviour, stability and configurability matter. - - Fediversity has received funding from the European Union’s Horizon Europe research and innovation programme under grant agreement No. 101136078. - ''; - }; -} diff --git a/website/content/news/publicspaces-conference-2024.nix b/website/content/news/publicspaces-conference-2024.nix deleted file mode 100644 index b3850abf..00000000 --- a/website/content/news/publicspaces-conference-2024.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ ... }: -{ - collections.news.entry = { - title = "PublicSpaces Conference 2024"; - description = "Report from the PublicSpaces Conference 2024 - 'Take Back the Internet'"; - date = "2024-07-30"; - author = "Laurens Hof"; - summary = '' - PublicSpaces and Waag Futurelabs recently held their yearly conference in Amsterdam, titled ‘Taking Back the Internet’ - ''; - body = '' - PublicSpaces and Waag Futurelabs recently held their yearly conference in Amsterdam, titled 'Taking Back the Internet'. PublicSpaces is a network of public organisations fighting for an internet based on public values. The Fediversity Project attended, to share ideas, and learn more about how people and organisations think about an ethical internet. If you are interested, you can view all sessions [here](https://conference.publicspaces.net/en/archive/pubconf2024) (hosted on PeerTube!). - - Alexandra van Huffelen, who was Dutch Secretary of State of Digitalisation until last month, gave the opening talk to discuss digitalisation and public values. In the talk, van Huffelen said that the Netherlands has a prominent lead in the EU with the promotion of public values in the digital infrastructure. Van Huffelen has been a prominent supporter of open standards and decentralisation, and has pushed the usage of Mastodon within the Dutch government, which fits well with the goals and vision of the Fediversity project. Project Lead Koen de Jonge took the opportunity shortly before the talk to hand van Huffelen a Mastodon pin, which she proudly wore during her talk, as you can see in the header image! - - There were quite some other talks about the Fediverse as well, discussing how to move the space forward. The goal of the Fediversity Project is to provide the technological infrastructure that makes it easier for people to join an open, free and fair social internet. The strength of Fediversity is in our technological capabilities, making the infrastructure more accessible. For our project to be successful, we also need a social infrastructure, that teaches people what it is and how it is beneficial for them, and how to get them on board. We also need public organisations to lead by example. Both of these social aspects of growing the fediverse were on full display during the PublicSpaces conference, and there is a real enthusiasm in growing the social internet. Fediversity is a strong supporter of organisations like PublicSpaces; while organisations like PublicSpaces help facilitate people and organisations with their thinking about why they should join the fediverse, and which steps should they take, Fediversity can provide the technological infrastructure that makes it all as easy as possible. - ''; - }; -} diff --git a/website/content/news/tech-session.nix b/website/content/news/tech-session.nix deleted file mode 100644 index ebb8dd80..00000000 --- a/website/content/news/tech-session.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ ... }: -{ - collections.news.entry = { - title = "Fediversity tech session"; - description = "Fediversity tech session - NixOS and Kubernetes"; - date = "2024-08-05"; - author = "Laurens Hof"; - summary = '' - Recently Fediversity hosted a tech session on NixOS and Kubernetes. We invited people within the community to discuss some design considerations of the Fediversity project with us. - ''; - body = '' - Recently Fediversity hosted a tech session on NixOS and Kubernetes. We invited people within the community to discuss some design considerations of the Fediversity project with us. - - One of the core ideas of Fediversity is to build on top of NixOS. NixOS makes upgrading system reliable, and complex deployment reproducable. One of the goals of the Fediversity project that provides an interesting challenge is to help people move away from the cloud hyperscalers. Offering our project on Kubernetes offers easy integration with the storage platforms of the hyperscalers. Easy integration with the hyperscalers is an explicit anti-goal of Fediversity, but we're not sure if we can offer all the functionality with NixOS yet. - - You can check out our entire conversation right here. - ''; - }; -} diff --git a/website/content/news/website-launch.nix b/website/content/news/website-launch.nix deleted file mode 100644 index 2dae814e..00000000 --- a/website/content/news/website-launch.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ ... }: -{ - collections.news.entry = { - title = "Fediversity website launch"; - description = "Announcing our new website for the Fediversity project"; - date = "2024-05-15"; - author = "Laurens Hof"; - summary = '' - We are pleased to introduce the launch of our new website dedicated to the Fediversity project. - ''; - body = '' - We are pleased to introduce the launch of our new website dedicated to the Fediversity project. - - The project is broad in scope, and the website reflects this. Whether you are a developer, an individual interested in the project, or want to know how the grant money is spend, the website keeps you up to date with everything you need to know. - - We're excited to show you more of the progress of the Fediversity project, and how we can build a next generation of the open internet together! - ''; - }; -} diff --git a/website/content/partners/nlnet.nix b/website/content/partners/nlnet.nix deleted file mode 100644 index b7aaf102..00000000 --- a/website/content/partners/nlnet.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ ... }: -{ - pages.nlnet = { - title = "NLnet"; - description = "Details about the NLnet Foundation"; - summary = '' - NLnet supports organisations and people who contribute to an open internet for all. They fund projects that help fix the internet through open hardware, open software, open standards, open science and open data. - ''; - body = '' - The NLnet Foundation supports organisations and people who contribute to an open internet for all. NLnet funds projects that help fix the internet through open hardware, open software, open standards, open science and open data. After its historical contribution to the early internet in Europe in the 1980’s, NLnet has been financially supporting the open internet since 1997. - - NLnet provides grants to free and open source projects between 5.000 and 50.000 euro with the possibility to scale up. Funding is open to anyone: organisations of any type and individuals. Within NGI Fediversity, NLnet facilitates the open calls for third-party funding and contributes to outreach and dissemination. - ''; - - }; -} diff --git a/website/content/partners/nordunet.nix b/website/content/partners/nordunet.nix deleted file mode 100644 index 38647115..00000000 --- a/website/content/partners/nordunet.nix +++ /dev/null @@ -1,15 +0,0 @@ -{ ... }: -{ - pages.nordunet = { - title = "NORDUnet"; - description = "Details about NORDUnet"; - summary = '' - NORDUnet is a collaboration of the National Research and Education Networks (NREN) of the Nordic countries. - ''; - body = '' - NORDUnet connects universities and research institutions across Denmark, Finland, Iceland, Norway, and Sweden. It enables collaboration, data sharing, and access to online resources for academic and research purposes. - - Fun fact: the website of NORDUnet, nordu.net is the oldest still active domain on the internet. - ''; - }; -} diff --git a/website/content/partners/oid.nix b/website/content/partners/oid.nix deleted file mode 100644 index 54c4cfb0..00000000 --- a/website/content/partners/oid.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ ... }: -{ - - pages.oid = { - title = "Open Internet Discourse Foundation"; - description = "Details about the Open Internet Discourse Foundation"; - summary = '' - The Open Internet Discourse Foundation (OID) is founded on the belief that everyone deserves the freedom to express themselves and use the internet without constraints, and is committed to help build a better internet where individuals can truly be who they are. - ''; - body = '' - The three pillars that are at the core of the OID Foundation: - - OID believes in the fundamental right of individuals to privacy, self-determination, and freedom of expression. - Building sustainably. The OID Foundation believes that the internet is crucial infrastructure for society, and as such, should be build from the perspective that software projects can exist and be maintained for a long time; decades, not years. - Transparancy. The OID Foundation takes the commitment to openness seriously, and strives to use open software in all aspects. - In order to realise our vision, we need a healthy, functional and open internet. This is where OID comes in, working on the infrastructure that powers the internet in a way that promotes it’s values. - - OID Foundation is rooted in constructive optimism, believing in tackling challenges head-on with a positive outlook, viewing each obstacle as an opportunity for improvement. As a practical example of the long-term vision is the work on NixOS that the OID is doing, where the reproducibility and long-term maintainability of NixOS’s package management help with an open and sustainable internet. - ''; - }; -} diff --git a/website/content/partners/tweag.nix b/website/content/partners/tweag.nix deleted file mode 100644 index 5d72c64a..00000000 --- a/website/content/partners/tweag.nix +++ /dev/null @@ -1,13 +0,0 @@ -{ ... }: -{ - pages.tweag = { - title = "Tweag"; - description = "Details about Tweag"; - summary = '' - Tweag is the open source program office (OSPO) of Modus Create, and has extensive experience working with Nix, and many people at the forefront of the Nix community are Tweagers - ''; - body = '' - Tweag is the open source program office (OSPO) of Modus Create, a global digital consulting firm that helps enterprises build competitive advantage through digital innovation. Tweagers are leading contributors to several open source projects — from functional programming languages to cross-platform frameworks. Tweag has extensive experience working with Nix, and many people at the forefront of the Nix community are Tweagers. - ''; - }; -} diff --git a/website/content_/_index.md b/website/content_/_index.md deleted file mode 100755 index baba528d..00000000 --- a/website/content_/_index.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -# Banner -banner: - title: "Welcome to the Fediversity Project" - content: "" - # image: "/images/checkbox-illustration-scaled.png" - image: "/images/home.svg" - button: - enable: true - label: "For You" - link: "/individuals" - -# Features -features3: - - title: "Consortium" - image: "/images/users.svg" - content: "The Consortium behind the Fediversity project is a cooperation between NLnet, Open Internet Discourse Foundation, NORDUnet and Tweag." - button: - enable: false - label: "Learn more" - link: "" - - - title: "NLnet" - image: "/images/users.svg" - content: "NLnet supports organisations and people who contribute to an open internet for all. They fund projects that help fix the internet through open hardware, open software, open standards, open science and open data." - button: - enable: true - label: "Learn more" - link: "/nlnet" - - - title: "Open Internet Discourse" - image: "/images/users.svg" - content: "The Open Internet Discourse Foundation (OID) is founded on the belief that everyone deserves the freedom to express themselves and use the internet without constraints, and is committed to help build a better internet where individuals can truly be who they are." - button: - enable: true - label: "Learn more" - link: "/oid" - - - title: "Tweag" - image: "/images/users.svg" - content: "Tweag is the open source program office (OSPO) of Modus Create, and has extensive experience working with Nix, and many people at the forefront of the Nix community are Tweagers." - button: - enable: true - label: "Learn more" - link: "/tweag" - - - title: "NORDUnet" - image: "/images/users.svg" - content: "NORDUnet is a collaboration of the National Research and Education Networks of the Nordic countries." - button: - enable: true - label: "Learn more" - link: "/nordunet" - -features: - - title: "Fediversity Grants" - image: "/images/stepping-up.png" - content: "" - button: - enable: true - label: "Learn more" - link: "/grants" - -features2: - - title: "Individuals" - image: "/images/user.png" - content: "Always be in control with your own data on social networks, whether that's with Mastodon, PeerTube or Pixelfed: Fediversity makes it possible." - button: - enable: true - label: "Learn more" - link: "/individuals" - - - title: "Developers" - image: "/images/code.png" - content: "As a developer building the next generation of social platforms, you are looking to make it easier to facilitate your customers to use your product. Fediversity can help." - button: - enable: true - label: "Learn more" - link: "/developers" - - - title: "European Commission" - image: "/images/globe.png" - content: "The Fediversity Project operates on a grant gratiously provided by the HORIZON fund by the EC. Learn more about the accountability of the project." - button: - enable: true - label: "Learn more" - link: "/ec" - ---- diff --git a/website/content_/authors/_index.md b/website/content_/authors/_index.md deleted file mode 100644 index 62eae442..00000000 --- a/website/content_/authors/_index.md +++ /dev/null @@ -1,3 +0,0 @@ ---- -title: "Authors" ---- diff --git a/website/content_/authors/laurens-hof.md b/website/content_/authors/laurens-hof.md deleted file mode 100644 index ab98ec79..00000000 --- a/website/content_/authors/laurens-hof.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -title: Laurens Hof -email: laurens@procolix.com -image: "/images/avatar.png" -description: storyteller -social: - - name: github - icon: fa-brands fa-github - link: https://github.com ---- - -Story teller for the Fediversity Project. diff --git a/website/content_/contact/_index.md b/website/content_/contact/_index.md deleted file mode 100644 index cfccf0d4..00000000 --- a/website/content_/contact/_index.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: "Contact" -meta_title: "" -description: "How to contact us" -draft: false ---- - -Please feel free to reach out to us via email at the following addresses for any inquiries or assistance. We’re here to help and eager to hear from you! - -For generic questions about the Fediversity project: - -contact@fediversity.eu -For questions about the administrative side of the Fediversity Project: - -fediversity@nlnet.nl -If you have questions about the funding rounds that are part of the Fediversity project, you can find out more information on the NLnet website: - -https://nlnet.nl/fediversity/guideforapplicants/ \ No newline at end of file diff --git a/website/content_/pages/privacy-policy.md b/website/content_/pages/privacy-policy.md deleted file mode 100644 index 87aff88a..00000000 --- a/website/content_/pages/privacy-policy.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -title: "Privacy" -# meta title -meta_title: "" -# meta description -description: "Privacy Policy" -# save as draft -draft: false ---- - -The Fediversity website does not track you, and does not process any of your data. - diff --git a/website/default.nix b/website/default.nix deleted file mode 100644 index 258d1ffb..00000000 --- a/website/default.nix +++ /dev/null @@ -1,102 +0,0 @@ -{ - sources ? import ../npins, - system ? builtins.currentSystem, - pkgs ? import sources.nixpkgs { - inherit system; - config = { }; - overlays = [ ]; - }, - lib ? import "${sources.nixpkgs}/lib", -}: -let - lib' = - final: prev: - let - new = import ./lib.nix { lib = final; }; - in - new // { types = prev.recursiveUpdate prev.types new.types; }; - lib'' = lib.extend lib'; - -in -rec { - lib = lib''; - result = lib.evalModules { - modules = [ - ./structure - ./content - ./presentation - { - _module.args = { - inherit pkgs; - }; - } - ]; - }; - - inherit (result.config) build; - - shell = - let - run-tests = pkgs.writeShellApplication { - name = "run-tests"; - text = - with pkgs; - with lib; - '' - ${getExe nix-unit} ${toString ./tests.nix} "$@" - ''; - }; - test-loop = pkgs.writeShellApplication { - name = "test-loop"; - text = - with pkgs; - with lib; - '' - ${getExe watchexec} -w ${toString ./.} -- ${getExe nix-unit} ${toString ./tests.nix} - ''; - }; - devmode = pkgs.devmode.override { - buildArgs = "${toString ./.} -A build --show-trace"; - open = "/index.html"; - }; - in - pkgs.mkShellNoCC { - packages = [ - pkgs.npins - run-tests - test-loop - devmode - ]; - }; - - inherit sources pkgs; - tests = - with pkgs; - with lib; - let - source = fileset.toSource { - root = ../.; - fileset = fileset.unions [ - ./default.nix - ./tests.nix - ./lib.nix - ../npins - ]; - }; - in - runCommand "run-tests" - { - buildInputs = [ pkgs.nix ]; - } - '' - export HOME="$(realpath .)" - # HACK: nix-unit initialises its own entire Nix, so it needs a store to operate on, - # but since we're in a derivation, we can't fetch sources, so copy Nixpkgs manually here. - # `''${sources.nixpkgs}` resolves to `-source`, - # adding it verbatim will result in --source, so rename it first - cp -r ${sources.nixpkgs} source - nix-store --add --store "$HOME" source - ${getExe nix-unit} --gc-roots-dir "$HOME" --store "$HOME" ${source}/website/tests.nix "$@" - touch $out - ''; -} diff --git a/website/images/screenshot.png b/website/images/screenshot.png deleted file mode 100644 index 62d9852e..00000000 Binary files a/website/images/screenshot.png and /dev/null differ diff --git a/website/images/tn.png b/website/images/tn.png deleted file mode 100644 index 6765469e..00000000 Binary files a/website/images/tn.png and /dev/null differ diff --git a/website/layouts/404.html b/website/layouts/404.html deleted file mode 100755 index e038668d..00000000 --- a/website/layouts/404.html +++ /dev/null @@ -1,21 +0,0 @@ -{{ define "main" }} -
-
-
-
- 404 -

Page not found

-
-

- The page you are looking for might have been removed, had its name - changed, or is temporarily unavailable. -

-
- - Back to home - -
-
-
-
-{{ end }} diff --git a/website/layouts/_default/baseof.html b/website/layouts/_default/baseof.html deleted file mode 100755 index f1ceaab5..00000000 --- a/website/layouts/_default/baseof.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - {{ partial "essentials/head.html" . }} - - - {{ partialCached "essentials/style.html" . }} - - - - - {{ if hugo.IsProduction }} {{ partialCached "preloader.html" . }} {{ - partialCached "gtm-noscript.html" . }} {{ else }} {{ partial - "preloader.html" . }} - - - {{ partial "components/tw-size-indicator.html" . }} {{ end }} - - - {{ partial "essentials/header.html" . }} {{ partial "search-modal.html" - (dict "Context" . ) }} - -
{{ block "main" . }}{{ end }}
- - - {{ partial "essentials/footer.html" . }} - - - {{ partialCached "essentials/script.html" . }} - - diff --git a/website/layouts/_default/list.html b/website/layouts/_default/list.html deleted file mode 100755 index b4b2b9d4..00000000 --- a/website/layouts/_default/list.html +++ /dev/null @@ -1,16 +0,0 @@ -{{ define "main" }} {{ partial "page-header" . }} - -
-
- -
-
-{{ end }} diff --git a/website/layouts/_default/single.html b/website/layouts/_default/single.html deleted file mode 100755 index a3b5b191..00000000 --- a/website/layouts/_default/single.html +++ /dev/null @@ -1,12 +0,0 @@ -{{ define "main" }} {{ partial "page-header" . }} - -
-
-
-
-
{{ .Content }}
-
-
-
-
-{{ end }} diff --git a/website/layouts/_default/taxonomy.html b/website/layouts/_default/taxonomy.html deleted file mode 100755 index 8ad4a15d..00000000 --- a/website/layouts/_default/taxonomy.html +++ /dev/null @@ -1,20 +0,0 @@ -{{ define "main" }} {{ partial "page-header" . }} - -
-
-
- -
-
- {{ range .Data.Pages }} -
- {{ partial "components/blog-card" . }} -
- {{ end }} -
-
-
-
-
-{{ end }} - diff --git a/website/layouts/_default/terms.html b/website/layouts/_default/terms.html deleted file mode 100755 index 93cc45c7..00000000 --- a/website/layouts/_default/terms.html +++ /dev/null @@ -1,32 +0,0 @@ -{{ define "main" }} {{ partial "page-header" . }} - -
-
- -
-
-{{ end }} diff --git a/website/layouts/about/list.html b/website/layouts/about/list.html deleted file mode 100644 index b3e40164..00000000 --- a/website/layouts/about/list.html +++ /dev/null @@ -1,14 +0,0 @@ -{{ define "main" }} -
-
-
-
- {{ partial "image" (dict "Src" .Params.image "Alt" .Title "Class" - "mx-auto mb-6" "Size" "200x200") }} -

{{ .Title }}

-
{{ .Content }}
-
-
-
-
-{{ end }} diff --git a/website/layouts/authors/list.html b/website/layouts/authors/list.html deleted file mode 100644 index fda2b3db..00000000 --- a/website/layouts/authors/list.html +++ /dev/null @@ -1,14 +0,0 @@ -{{ define "main" }} {{ partial "page-header" . }} - -
-
-
- {{ range .RegularPages }} -
- {{ partial "components/author-card" . }} -
- {{ end }} -
-
-
-{{ end }} diff --git a/website/layouts/authors/single.html b/website/layouts/authors/single.html deleted file mode 100755 index 49802c99..00000000 --- a/website/layouts/authors/single.html +++ /dev/null @@ -1,46 +0,0 @@ -{{ define "main" }} -
-
-
-
- {{ $image:= .Params.image }} {{ if $image }} {{ partial "image" (dict - "Src" $image "Alt" .Title "Class" "mx-auto" "Size" "200x200") }} {{ else - if .Params.Email }} - {{ .Title }} - {{ end }} -

{{ .Title }}

-
{{ .Content }}
- -
-
- -
- {{ $filterByAuthor := where site.RegularPages "Params.author" "==" .Title - }} {{ range $filterByAuthor }} -
- {{ partial "components/blog-card" . }} -
- {{ end }} -
-
-
-{{ end }} diff --git a/website/layouts/blog/list.html b/website/layouts/blog/list.html deleted file mode 100644 index b899d218..00000000 --- a/website/layouts/blog/list.html +++ /dev/null @@ -1,22 +0,0 @@ -{{ define "main" }} {{ partial "page-header" . }} - -
-
-
- - -
- {{ $paginator:= .Paginate .RegularPages }} {{ range $paginator.Pages - }} -
- {{ partial "components/blog-card" . }} -
- {{ end }} -
- {{ partial "components/pagination.html" . }} - - -
-
-
-{{ end }} diff --git a/website/layouts/blog/single.html b/website/layouts/blog/single.html deleted file mode 100644 index 975de70f..00000000 --- a/website/layouts/blog/single.html +++ /dev/null @@ -1,68 +0,0 @@ -{{ define "main" }} -
-
-
-
- - {{ $image:= .Params.image }} {{ if $image }} -
-
-

{{ .Title }}

- -
{{ .Content }}
- -
-
-
- {{ partial "image" (dict "Src" $image "Alt" .Title "Class" "w-full rounded") }} -
-
-
- {{ end }} - - - - - -
- {{ $tags:= .Params.tags }} {{ if $tags }} -
-
{{ i18n "tags" }} :
- -
- {{ end }} - -
- - -
-
- - -
-
-{{ end }} diff --git a/website/layouts/contact/list.html b/website/layouts/contact/list.html deleted file mode 100755 index f6ee6fc7..00000000 --- a/website/layouts/contact/list.html +++ /dev/null @@ -1,64 +0,0 @@ -{{ define "main" }} {{ partial "page-header" . }} - - -
-
-
-
-
{{ .Content }}
-
-
-
-
- - - -
-
-
-
-
-
- - -
-
- - -
-
- - -
- -
-
-
-
-
- -{{ end }} \ No newline at end of file diff --git a/website/layouts/events/list.html b/website/layouts/events/list.html deleted file mode 100644 index f0657e17..00000000 --- a/website/layouts/events/list.html +++ /dev/null @@ -1,31 +0,0 @@ -{{ define "main" }} {{ partial "page-header" . }} -
-
    - {{ if gt (len (where .Site.RegularPages "Section" "events")) 0 }} -
    -
    - Image -

    Events

    -
    -
      - {{ range (first 5 (where .Site.RegularPages "Section" "events").ByDate.Reverse) }} -
    • - -
      - - -
      -
    • -
      - {{ end }} -
    - -
    - {{ end }} -
- -
- -{{ end }} diff --git a/website/layouts/events/single.html b/website/layouts/events/single.html deleted file mode 100644 index dcd51556..00000000 --- a/website/layouts/events/single.html +++ /dev/null @@ -1,73 +0,0 @@ -{{ define "main" }} -
-
-
-
- - {{ $image:= .Params.image }} {{ if $image }} -
-
-

{{ .Title }}

-
    - -
  • - - Start: {{ .Params.datetime_start }} -
  • -
    -
  • - - End: {{ .Params.datetime_end }} -
  • -
    -
  • - - Location: {{ .Params.location }} -
  • - - -
-
{{ .Content }}
- -
-
-
- {{ partial "image" (dict "Src" $image "Alt" .Title "Class" "w-full rounded") }} -
-
-
- {{ end }} - - - - - -
- {{ $tags:= .Params.tags }} {{ if $tags }} -
-
{{ i18n "tags" }} :
- -
- {{ end }} - -
- - -
-
- - -
-
-{{ end }} diff --git a/website/layouts/index.html b/website/layouts/index.html deleted file mode 100755 index 2667b3ee..00000000 --- a/website/layouts/index.html +++ /dev/null @@ -1,208 +0,0 @@ -{{ define "main" }} - -{{ with .Params.banner }} -
-
-
-
-

{{ .title | markdownify }}

-

{{ .content | markdownify }}

- {{ with .button }} {{ if .enable }} - - {{ .label }} - - - {{ end }} {{ end }} -
-
- {{ partial "image" (dict "Src" .image "Alt" "Banner image" "Loading" - "eager" "Class" "mx-auto lg:!max-w-[800px]" "DisplayXL" "800x" ) }} -
-
-
-
-{{ end }} - - - -

Consortium

- - -
-
- {{ range $i, $e := .Params.features3 }} - -
- -
- Image -
{{ .title | markdownify }}
-
- - -

{{ .content | markdownify }} - {{ with .button }} {{ if .enable }} - - Read more - - - {{ end }} {{ end }} -

-
- {{ end }} -
-
- - - - -{{ range $i, $e:= .Params.features }} -
-
-
-
- {{ partial "image" (dict "Src" .image "Alt" "feature image" "DisplayXL" - "520x" "DisplayLG" "425x" "DisplayMD" "360x") }} -
-
-

{{ .title | markdownify }}

-

{{ .content | markdownify }}

-
    - {{ range .bulletpoints }} -
  • - - {{ . | markdownify }} -
  • - {{ end }} -
- {{ with .button }} {{ if .enable }} - - {{ .label }} - - - {{ end }} {{ end }} -
-
-
-
-{{ end }} - - - - - - -

Fediverse Explained

- - -
-
- {{ range $i, $e := .Params.features2 }} -
-
- Image -

{{ .title | markdownify }}

-
- -

{{ .content | markdownify }}

- {{ with .button }} {{ if .enable }} - - {{ .label }} - - - {{ end }} {{ end }} -
- {{ end }} -
-
- - -
-
-
- - -{{ if gt (len (where .Site.RegularPages "Section" "blog")) 0 }} -
- -
-
-
-
    - {{ if gt (len (where .Site.RegularPages "Section" "events")) 0 }} -
    -
    - Image -

    Events

    -
    -
      - {{ range (first 5 (where .Site.RegularPages "Section" "events").ByDate.Reverse) }} -
    • - -
      - - -
      -
    • -
      - {{ end }} -
    - {{ end }} -
-
-
-
    - {{ if gt (len (where .Site.RegularPages "Section" "blog")) 0 }} -
    -
    - Image -

    Latest News

    -
    -
      - {{ range (first 5 (where .Site.RegularPages "Section" "blog").ByDate.Reverse) }} -
    • - -
      - - -
      -
    • -
      - {{ end }} -
    - {{ end }} -
-
-
-
-
-{{ end }} - - -{{ end }} diff --git a/website/layouts/partials/call-to-action.html b/website/layouts/partials/call-to-action.html deleted file mode 100644 index 931be79c..00000000 --- a/website/layouts/partials/call-to-action.html +++ /dev/null @@ -1,25 +0,0 @@ - -{{ with site.GetPage "sections/call-to-action" }} {{ if .Params.enable }} -
-
-
-
-
- {{ partial "image" (dict "Src" .image "Alt" "call to action" "Class" - "w-full") }} -
-
-

{{ .Title | markdownify }}

-

{{ .Params.description | markdownify }}

- {{ with .Params.button }} {{ if .enable }} - - {{ .label }} - - {{ end }} {{ end }} -
-
-
-
-
-{{ end }} {{ end }} - diff --git a/website/layouts/partials/components/author-card.html b/website/layouts/partials/components/author-card.html deleted file mode 100755 index 6d59c043..00000000 --- a/website/layouts/partials/components/author-card.html +++ /dev/null @@ -1,27 +0,0 @@ -
- {{ $image:= .Params.image }} {{ if $image }} {{ partial "image" (dict "Src" - $image "Alt" .Title "Class" "mx-auto mb-6 rounded" "size" "120x120") }} {{ - else if .Params.Email }} - {{ .Title }} - {{ end }} -

- {{ .Title }} -

-

{{ .Summary }}

- -
diff --git a/website/layouts/partials/components/blog-card.html b/website/layouts/partials/components/blog-card.html deleted file mode 100644 index 5fd8d170..00000000 --- a/website/layouts/partials/components/blog-card.html +++ /dev/null @@ -1,30 +0,0 @@ -
- {{ $image:= .Params.image }} {{ if $image }} {{ partial "image" (dict "Src" $image "Alt" .Title "Class" "w-full rounded") }} {{ end }} -

- {{ .Title }} -

- {{ $categories:= .Params.categories }} {{ if $categories }} - - {{ end }} -

{{ .Summary }}

- - {{ i18n "read_more" }} - -
diff --git a/website/layouts/partials/components/breadcrumb.html b/website/layouts/partials/components/breadcrumb.html deleted file mode 100644 index 07800098..00000000 --- a/website/layouts/partials/components/breadcrumb.html +++ /dev/null @@ -1,25 +0,0 @@ -{{ $context := .Context }} {{ $class := .Class }} {{ $base := -site.Home.Permalink }} - - diff --git a/website/layouts/partials/components/language-switcher.html b/website/layouts/partials/components/language-switcher.html deleted file mode 100644 index 95f07079..00000000 --- a/website/layouts/partials/components/language-switcher.html +++ /dev/null @@ -1,25 +0,0 @@ - -{{ $class := .Class }} {{ $context := .Context }} {{ $pageLang := $context.Lang -}} {{ $base:= urls.Parse site.Home.Permalink }} {{ $siteLanguages := -site.Home.AllTranslations }} {{ $pageLink := replace (replace -$context.RelPermalink (add $pageLang "/") "") $base.Path "/" }} {{ if -$context.IsTranslated }} - -{{ end }} diff --git a/website/layouts/partials/components/pagination.html b/website/layouts/partials/components/pagination.html deleted file mode 100755 index 23928cff..00000000 --- a/website/layouts/partials/components/pagination.html +++ /dev/null @@ -1,133 +0,0 @@ -{{ $paginator := .Paginator }} - -{{ $adjacent_links := 2 }} - -{{ $max_links := (add (mul $adjacent_links 2) 1) }} - -{{ $lower_limit := (add $adjacent_links 1) }} - -{{ $upper_limit := (sub $paginator.TotalPages $adjacent_links) }} - -{{ if gt $paginator.TotalPages 1 }} - -{{ end }} diff --git a/website/layouts/partials/components/theme-switcher.html b/website/layouts/partials/components/theme-switcher.html deleted file mode 100644 index 54d6075c..00000000 --- a/website/layouts/partials/components/theme-switcher.html +++ /dev/null @@ -1,65 +0,0 @@ - -{{ $class := .Class }} {{ if site.Params.theme_switcher }} -
- - -
- - - -{{ end }} diff --git a/website/layouts/partials/components/tw-size-indicator.html b/website/layouts/partials/components/tw-size-indicator.html deleted file mode 100644 index 4ac7e1ed..00000000 --- a/website/layouts/partials/components/tw-size-indicator.html +++ /dev/null @@ -1,10 +0,0 @@ -
- all - - - - - -
diff --git a/website/layouts/partials/essentials/footer.html b/website/layouts/partials/essentials/footer.html deleted file mode 100755 index 792179d0..00000000 --- a/website/layouts/partials/essentials/footer.html +++ /dev/null @@ -1,65 +0,0 @@ -
-
-
- -
-
    - {{ range site.Menus.footer }} -
  • - {{ .Name }} -
  • - {{ end }} -
-
-
- -
-
-
-
-
-

{{ site.Params.copyright | markdownify }}

-
-
-
diff --git a/website/layouts/partials/essentials/head.html b/website/layouts/partials/essentials/head.html deleted file mode 100755 index 9dae7a0d..00000000 --- a/website/layouts/partials/essentials/head.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - -{{ partialCached "favicon" . }} - - -{{ partialCached "manifest" . }} - - -{{ partialCached "site-verifications.html" . }} - - -{{ partial "basic-seo.html" . }} - - -{{ partialCached "custom-script.html" . }} - - -{{ if and site.Config.Services.GoogleAnalytics.ID (ne -site.Config.Services.GoogleAnalytics.ID "G-MEASUREMENT_ID") }} {{ template -"_internal/google_analytics.html" . }} {{ end }} - - -{{ partialCached "gtm.html" . }} - - -{{ partial "search-index.html" . }} - - -{{/* {{ partialCached "matomo-analytics.html" . }} */}} - - -{{/* {{ partialCached "baidu-analytics.html" . }} */}} - - -{{/* {{ partialCached "plausible-analytics.html" . }} */}} - - -{{/* {{ partialCached "counter-analytics.html" . }} */}} - - -{{/* {{ partialCached "crisp-chat.html" . }} */}} diff --git a/website/layouts/partials/essentials/header.html b/website/layouts/partials/essentials/header.html deleted file mode 100755 index 9e05694e..00000000 --- a/website/layouts/partials/essentials/header.html +++ /dev/null @@ -1,152 +0,0 @@ -
- -
diff --git a/website/layouts/partials/essentials/script.html b/website/layouts/partials/essentials/script.html deleted file mode 100755 index 9474a24a..00000000 --- a/website/layouts/partials/essentials/script.html +++ /dev/null @@ -1,45 +0,0 @@ - -{{ $scripts := slice }} {{ $scriptsLazy := slice }} {{ range -site.Params.plugins.js }} {{ if findRE "^http" .link }} - -{{ else }} {{ if not .lazy }} {{ $scripts = $scripts | append (resources.Get -.link) }} {{ else }} {{ $scriptsLazy = $scriptsLazy | append (resources.Get -.link) }} {{ end }} {{ end }} {{ end }} - - -{{ $scripts = $scripts | append (resources.Get "js/main.js") }} {{ $scripts = -$scripts | resources.Concat "js/script.js" }} {{ $scriptsLazy = $scriptsLazy | -resources.Concat "js/script-lazy.js" }} {{ if hugo.IsProduction }} {{ $scripts = -$scripts | minify | fingerprint }} {{ $scriptsLazy = $scriptsLazy | minify | -fingerprint }} {{ end }} {{/* scripts */}} - - -{{/* scripts lazy */}} - - - -{{ partialCached "pwa.html" . }} - - -{{ partialCached "cookie-consent.html" . }} - - -{{ partialCached "adsense-script.html" . }} diff --git a/website/layouts/partials/essentials/style.html b/website/layouts/partials/essentials/style.html deleted file mode 100755 index a496dab2..00000000 --- a/website/layouts/partials/essentials/style.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - - - - - - - - - - -{{ $pf:= site.Data.theme.fonts.font_family.primary }} {{ $sf:= -site.Data.theme.fonts.font_family.secondary }} - - - - - -{{ $styles := slice }} {{ $stylesLazy := slice }} {{ range -site.Params.plugins.css }} {{ if findRE "^http" .link }} - -{{ else }} {{ if not .lazy }} {{ $styles = $styles | append (resources.Get -.link) }} {{ else }} {{ $stylesLazy = $stylesLazy | append (resources.Get .link) -}} {{ end }} {{ end }} {{ end }} {{/* main style */}} {{ $styles = $styles | -append (resources.Get "scss/main.scss" | toCSS) }} {{ $styles = $styles | -resources.Concat "css/style.css" }} {{ $styles = $styles | resources.PostCSS }} -{{ $stylesLazy = $stylesLazy | resources.Concat "css/style-lazy.css" }} {{ -$stylesLazy = $stylesLazy | resources.PostCSS }} {{ if hugo.IsProduction }} {{ -$styles = $styles | resources.ExecuteAsTemplate "css/style.css" . | minify | -fingerprint | resources.PostProcess }} {{ $stylesLazy = $stylesLazy | -resources.ExecuteAsTemplate "css/style-lazy.css" . | minify | fingerprint | -resources.PostProcess }} {{ else }} {{ $styles = $styles | -resources.ExecuteAsTemplate "css/style.css" . }} {{ $stylesLazy = $stylesLazy | -resources.ExecuteAsTemplate "css/style-lazy.css" . }} {{ end }} {{/* styles */}} - - -{{/* styles lazy */}} - diff --git a/website/layouts/partials/page-header.html b/website/layouts/partials/page-header.html deleted file mode 100755 index 02f07512..00000000 --- a/website/layouts/partials/page-header.html +++ /dev/null @@ -1,10 +0,0 @@ -
-
-
-

{{ i18n (printf "%s" (lower .Title)) | default .Title | title }}

- {{ partial "components/breadcrumb" (dict "Context" . "Class" "mt-6") }} -
-
-
diff --git a/website/layouts/partials/widgets/categories.html b/website/layouts/partials/widgets/categories.html deleted file mode 100755 index c4750417..00000000 --- a/website/layouts/partials/widgets/categories.html +++ /dev/null @@ -1,23 +0,0 @@ - -{{ if isset site.Taxonomies "categories" }} {{ if not (eq (len -site.Taxonomies.categories) 0) }} -
-
{{ i18n "categories" }}
-
- -
-
-{{ end }} {{ end }} diff --git a/website/layouts/partials/widgets/tags.html b/website/layouts/partials/widgets/tags.html deleted file mode 100755 index 731ee488..00000000 --- a/website/layouts/partials/widgets/tags.html +++ /dev/null @@ -1,23 +0,0 @@ - -{{ if isset site.Taxonomies "tags" }} {{ if not (eq (len site.Taxonomies.tags) -0) }} -
-
{{ i18n "tags" }}
-
- -
-
-{{ end }} {{ end }} diff --git a/website/layouts/partials/widgets/widget-wrapper.html b/website/layouts/partials/widgets/widget-wrapper.html deleted file mode 100755 index 867b2d85..00000000 --- a/website/layouts/partials/widgets/widget-wrapper.html +++ /dev/null @@ -1 +0,0 @@ -{{ range .Widgets }} {{ partial ( print "widgets/" . ) $.Scope }} {{ end }} diff --git a/website/lib.nix b/website/lib.nix deleted file mode 100644 index 4ca8d77d..00000000 --- a/website/lib.nix +++ /dev/null @@ -1,226 +0,0 @@ -{ lib }: -rec { - template = - g: f: x: - let - base = f x; - result = g base; - in - result - // { - override = - new: - let - base' = - if lib.isFunction new then - lib.recursiveUpdate base (new base' base) - else - lib.recursiveUpdate base new; - result' = g base'; - in - result' - // { - override = new: (template g (_: base') x).override new; - }; - }; - - /** - Recursively replace occurrences of `from` with `to` within `string` - - Example: - - replaceStringRec "--" "-" "hello-----world" - => "hello-world" - */ - replaceStringsRec = - from: to: string: - let - replaced = lib.replaceStrings [ from ] [ to ] string; - in - if replaced == string then string else replaceStringsRec from to replaced; - - /** - Create a URL-safe slug from any string - */ - slug = - str: - let - # Replace non-alphanumeric characters with hyphens - replaced = join "" ( - builtins.map (c: if (c >= "a" && c <= "z") || (c >= "0" && c <= "9") then c else "-") ( - with lib; stringToCharacters (toLower str) - ) - ); - - # Remove leading and trailing hyphens - trimHyphens = - s: - let - matched = builtins.match "(-*)([^-].*[^-]|[^-])(-*)" s; - in - with lib; - optionalString (!isNull matched) (builtins.elemAt matched 1); - in - trimHyphens (replaceStringsRec "--" "-" replaced); - - squash = replaceStringsRec "\n\n" "\n"; - - /** - Trim trailing spaces and squash non-leading spaces - */ - trim = - string: - let - trimLine = - line: - with lib; - let - # separate leading spaces from the rest - parts = split "(^ *)" line; - spaces = head (elemAt parts 1); - rest = elemAt parts 2; - # drop trailing spaces - body = head (split " *$" rest); - in - if body == "" then "" else spaces + replaceStringsRec " " " " body; - in - join "\n" (map trimLine (splitLines string)); - - join = lib.concatStringsSep; - - splitLines = s: with builtins; filter (x: !isList x) (split "\n" s); - - indent = - prefix: s: - with lib.lists; - let - lines = splitLines s; - in - join "\n" ([ (head lines) ] ++ (map (x: if x == "" then x else "${prefix}${x}") (tail lines))); - - relativePath = - path1': path2': - let - inherit (lib.path) subpath; - inherit (lib) - lists - length - take - drop - min - max - ; - - path1 = subpath.components path1'; - prefix1 = take (length path1 - 1) path1; - path2 = subpath.components path2'; - prefix2 = take (length path2 - 1) path2; - - commonPrefixLength = - with lists; - findFirstIndex (i: i.fst != i.snd) (min (length prefix1) (length prefix2)) ( - zipLists prefix1 prefix2 - ); - - depth = max 0 (length prefix1 - commonPrefixLength); - - relativeComponents = - with lists; - [ "." ] ++ (replicate depth "..") ++ (drop commonPrefixLength path2); - in - join "/" relativeComponents; - - /** - Recursively list all Nix files from a directory, except the top-level `default.nix` - - Useful for module system `imports` from a top-level module. - * - */ - nixFiles = - dir: - with lib.fileset; - toList (difference (fileFilter ({ hasExt, ... }: hasExt "nix") dir) (dir + "/default.nix")); - - types = rec { - # arbitrarily nested attribute set where the leaves are of type `type` - # NOTE: this works for anything but attribute sets! - recursiveAttrs = - type: - with lib.types; - # NOTE: due to how `either` works, the first match is significant, - # so if `type` happens to be an attrset, the typecheck will consider - # `type`, not `attrsOf` - attrsOf (either type (recursiveAttrs type)); - - # collection of unnamed items that can be added to item-wise, i.e. without wrapping the item in a list - collection = - elemType: - let - unparenthesize = class: class == "noun"; - desc = type: types.optionDescriptionPhrase unparenthesize type; - desc' = - type: - let - typeDesc = lib.types.optionDescriptionPhrase unparenthesize type; - in - if type.descriptionClass == "noun" then typeDesc + "s" else "many instances of ${typeDesc}"; - in - lib.types.mkOptionType { - name = "collection"; - description = "separately specified ${desc elemType} for a collection of ${desc' elemType}"; - merge = - loc: defs: - map ( - def: - elemType.merge (loc ++ [ "[definition ${toString def.file}]" ]) [ - { - inherit (def) file; - value = def.value; - } - ] - ) defs; - check = elemType.check; - getSubOptions = elemType.getSubOptions; - getSubModules = elemType.getSubModules; - substSubModules = m: collection (elemType.substSubModules m); - functor = (lib.defaultFunctor "collection") // { - type = collection; - wrapped = elemType; - payload = { }; - }; - nestedTypes.elemType = elemType; - }; - - listOfUnique = - elemType: - let - baseType = lib.types.listOf elemType; - in - baseType - // { - merge = - loc: defs: - let - # Keep track of which definition each value came from - defsWithValues = map ( - def: - map (v: { - inherit (def) file; - value = v; - }) def.value - ) defs; - flatDefs = lib.flatten defsWithValues; - - # Check for duplicates while preserving source info - seen = builtins.foldl' ( - acc: def: - if lib.lists.any (v: v.value == def.value) acc then - throw "The option `${lib.options.showOption loc}` has duplicate values (${toString def.value}) defined in ${def.file}" - else - acc ++ [ def ] - ) [ ] flatDefs; - in - map (def: def.value) seen; - }; - }; -} diff --git a/website/presentation/default.nix b/website/presentation/default.nix deleted file mode 100644 index 8a20230d..00000000 --- a/website/presentation/default.nix +++ /dev/null @@ -1,101 +0,0 @@ -{ - config, - options, - lib, - pkgs, - ... -}: -let - inherit (lib) - mkOption - types - ; -in -{ - imports = lib.nixFiles ./.; - - options.templates = mkOption { - description = '' - Collection of named helper functions for conversion different structured representations which can be rendered to a string - ''; - type = with types; recursiveAttrs (functionTo (either str attrs)); - }; - - options.files = mkOption { - description = '' - Files that make up the site, mapping from output path to contents - - Add more files to the output by assigning to this attribute set. - ''; - type = with types; attrsOf path; - }; - - options.build = mkOption { - description = '' - The final output of the web site - ''; - type = types.package; - default = - let - script = - '' - mkdir $out - '' - + lib.join "\n" copy; - copy = lib.mapAttrsToList (path: file: '' - mkdir -p $out/$(dirname ${path}) - cp -r ${file} $out/${path} - '') config.files; - in - pkgs.runCommand "source" { } script; - }; - - # TODO: this is an artefact of exploration; needs to be adapted to actual use - config.templates.table-of-contents = - { config, ... }: - let - outline = - { ... }: - { - options = { - value = mkOption { - # null denotes root - type = with types; nullOr (either str (listOf (attrTag categories.phrasing))); - subsections = mkOption { - type = with types; listOf (submodule outline); - default = - with lib; - map - # TODO: go into depth manually here, - # we don't want to pollute the DOM implementation - (c: (lib.head (attrValues c)).outline) - (filter (c: isAttrs c && (lib.head (attrValues c)) ? outline) config.content); - }; - }; - __toString = mkOption { - type = with types; functionTo str; - # TODO: convert to HTML - default = - self: - lib.squash '' - ${if isNull self.value then "root" else self.value} - ${if self.subsections != [ ] then " " + lib.indent " " (lib.join "\n" self.subsections) else ""} - ''; - }; - }; - }; - in - { - options.outline = mkOption { - type = types.submodule outline; - default = { - value = null; - subsections = - with lib; - map (c: (lib.head (attrValues c)).outline) ( - filter (c: isAttrs c && (lib.head (attrValues c)) ? outline) config.content - ); - }; - }; - }; -} diff --git a/website/presentation/dom.nix b/website/presentation/dom.nix deleted file mode 100644 index 3946758b..00000000 --- a/website/presentation/dom.nix +++ /dev/null @@ -1,859 +0,0 @@ -/** - A strongly typed module system implementation of the Document Object Model (DOM) - - Based on the WHATWG's HTML Living Standard https://html.spec.whatwg.org (CC-BY 4.0) - Inspired by https://github.com/knupfer/type-of-html by @knupfer (BSD-3-Clause) - Similar work from the OCaml ecosystem: https://github.com/ocsigen/tyxml -*/ -{ config, lib, ... }: - -let - inherit (lib) mkOption types; - inherit (types) submodule; - - # https://html.spec.whatwg.org/multipage/dom.html#content-models - # https://html.spec.whatwg.org/multipage/dom.html#kinds-of-content - content-categories = [ - "none" # https://html.spec.whatwg.org/multipage/dom.html#the-nothing-content-model - "text" # https://html.spec.whatwg.org/multipage/dom.html#text-content - "metadata" # https://html.spec.whatwg.org/multipage/dom.html#metadata-content - "flow" # https://html.spec.whatwg.org/multipage/dom.html#flow-content - "sectioning" # https://html.spec.whatwg.org/multipage/dom.html#sectioning-content - "heading" # https://html.spec.whatwg.org/multipage/dom.html#heading-content - "phrasing" # https://html.spec.whatwg.org/multipage/dom.html#phrasing-content - "embedded" # https://html.spec.whatwg.org/multipage/dom.html#embedded-content-2 - "interactive" # https://html.spec.whatwg.org/multipage/dom.html#interactive-content - "palpable" # https://html.spec.whatwg.org/multipage/dom.html#palpable-content - "scripting" # https://html.spec.whatwg.org/multipage/dom.html#script-supporting-elements - ]; - - # base type for all DOM elements - element = - { ... }: - { - # TODO: add fields for upstream documentation references - # TODO: programmatically generate documentation - options = with lib; { - categories = mkOption { - type = types.listOfUnique (types.enum content-categories); - }; - __toString = mkOption { - internal = true; - type = with types; functionTo str; - }; - }; - }; - - # options with types for all the defined DOM elements - element-types = lib.mapAttrs (_name: value: mkOption { type = submodule value; }) elements; - - # attrset of categories, where values are module options with the type of the - # elements that belong to these categories - categories = - with lib; - genAttrs content-categories ( - category: - (mapAttrs (_: e: mkOption { type = submodule e; }) - # HACK: don't evaluate the submodule types, just grab the config directly - # TODO: we may want to do this properly and loop `categories` through the top-level `config` - ( - filterAttrs ( - _: e: - elem category - (e { - name = "dummy"; - config = { }; - }).config.categories - ) elements - ) - ) - ); - - global-attrs = lib.mapAttrs (_name: value: mkOption value) { - class = { - type = with types; listOf nonEmptyStr; - default = [ ]; - }; - hidden = { - type = types.bool; - default = false; - }; - id = { - # TODO: would be cool if we could enforce unique IDs per document - type = with types; nullOr nonEmptyStr; - default = null; - }; - lang = { - # TODO: https://www.rfc-editor.org/rfc/rfc5646.html - type = with types; nullOr str; - default = null; - }; - style = { - # TODO: CSS type ;..) - type = with types; nullOr str; - default = null; - }; - title = { - type = with types; nullOr lines; - default = null; - }; - # TODO: more global attributes - # https://html.spec.whatwg.org/#global-attributes - # https://html.spec.whatwg.org/#attr-aria-* - # https://html.spec.whatwg.org/multipage/microdata.html#encoding-microdata - }; - - # all possible attributes to `` elements. - # since not all of them apply to each `rel=` type, the separate implementations can pick from this collection - link-attrs = lib.mapAttrs (_name: value: mkOption value) { - href = { - # TODO: implement https://html.spec.whatwg.org/multipage/semantics.html#the-link-element:attr-link-href-3 - # TODO: https://url.spec.whatwg.org/#valid-url-string - type = types.nonEmptyStr; - }; - media = { - # TODO: https://drafts.csswg.org/mediaqueries/#media - # it's awsome we have that standard, but ugh so much work - # ;..S - # Clay seems to do it right: https://github.com/sebastiaanvisser/clay - type = with types; nullOr str; - default = null; - }; - integrity = { - # TODO: implement https://w3c.github.io/webappsec-subresource-integrity/ - type = with types; nullOr str; - default = null; - }; - # TODO: more attributes - # https://html.spec.whatwg.org/multipage/semantics.html#the-link-element:concept-element-attributes - }; - - # TODO: not sure where to put these, since so far they apply to multiple elements, - # but have the same properties for all of them - attrs = lib.mapAttrs (_name: value: mkOption value) { - # TODO: investigate: `href` may be coupled with other attributes such as `target` or `hreflang`, this could simplify things - href = { - # TODO: https://url.spec.whatwg.org/#valid-url-string - # ;..O - type = types.str; - }; - target = { - # https://html.spec.whatwg.org/multipage/document-sequences.html#valid-navigable-target-name-or-keyword - type = - let - is-valid-target = - s: - let - inherit (lib) match; - has-lt = s: match ".*<.*" s != null; - has-tab-or-newline = s: match ".*[\t\n].*" s != null; - has-valid-start = s: match "^[^_].*$" s != null; - in - has-valid-start s && !(has-lt s && has-tab-or-newline s); - in - with types; - either (enum [ - "_blank" - "_self" - "_parent" - "_top" - ]) (types.addCheck str is-valid-target); - }; - }; - - mkAttrs = - attrs: - with lib; - mkOption { - type = submodule { - options = global-attrs // attrs; - }; - default = { }; - }; - - print-attrs = - with lib; - attrs: - # TODO: figure out how let attributes know how to print themselves without polluting the interface - let - result = trim ( - join " " ( - mapAttrsToList - # TODO: this needs to be smarter for boolean attributes - # where the value must be written out explicitly. - # probably the attribute itself should have its own `__toString`. - ( - name: value: - if isBool value then - if value then name else "" - # TODO: some attributes must be explicitly empty - else - optionalString (toString value != "") ''${name}="${toString value}"'' - ) - attrs - ) - ); - in - if attrs == null then throw "wat" else optionalString (stringLength result > 0) " " + result; - - print-element = - name: attrs: content: - with lib; - # TODO: be smarter about content to save some space and repetition at the call sites - squash (trim '' - <${name}${print-attrs attrs}> - ${lib.indent " " content} - - ''); - - print-element' = name: attrs: "<${name}${print-attrs attrs}>"; - - toString-unwrap = - e: - with lib; - if isAttrs e then - toString (head (attrValues e)) - else if isList e then - toString (map toString-unwrap e) - else - e; - - elements = rec { - document = - { ... }: - { - imports = [ element ]; - options = { - inherit (element-types) html; - attrs = mkAttrs { }; - }; - - config.categories = [ ]; - config.__toString = self: '' - - ${self.html} - ''; - }; - - html = - { name, ... }: - { - imports = [ element ]; - options = { - attrs = mkAttrs { }; - inherit (element-types) head body; - }; - - config.categories = [ ]; - config.__toString = - self: - print-element name self.attrs '' - ${self.head} - ${self.body} - ''; - }; - - head = - { name, ... }: - { - imports = [ element ]; - options = with lib; { - attrs = mkAttrs { }; - # https://html.spec.whatwg.org/multipage/semantics.html#the-head-element:concept-element-content-model - # XXX: this doesn't implement the iframe srcdoc semantics - # as those have questionable value and would complicate things a bit. - # it should be possible though, by passing a flag via module arguments. - inherit (element-types) title; - base = mkOption { - type = with types; nullOr (submodule base); - default = null; - }; - # https://html.spec.whatwg.org/multipage/semantics.html#attr-meta-charset - meta.charset = mkOption { - # TODO: create programmatically from https://encoding.spec.whatwg.org/encodings.json - type = types.enum [ - "utf-8" - ]; - default = "utf-8"; - }; - # https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag#viewport_width_and_screen_width - # this should not exist and no one should ever have to think about it - meta.viewport = mkOption { - type = submodule ( - { ... }: - { - # TODO: figure out how to render only non-default values - options = { - width = mkOption { - type = with types; either (ints.between 1 10000) (enum [ "device-width" ]); - default = "device-width"; # not default by standard - }; - height = mkOption { - type = with types; either (ints.between 1 10000) (enum [ "device-height" ]); - default = "device-height"; # not default by standard (but seems to work if you don't set it) - }; - initial-scale = mkOption { - type = types.numbers.between 0.1 10; - default = 1; - }; - minimum-scale = mkOption { - type = types.numbers.between 0.1 10; - # TODO: render only as many digits as needed - default = 0.1; - }; - maximum-scale = mkOption { - type = types.numbers.between 0.1 10; - default = 10; - }; - user-scalable = mkOption { - type = types.bool; - default = true; - }; - interactive-widget = mkOption { - type = types.enum [ - "resizes-visual" - "resizes-content" - "overlays-content" - ]; - default = "resizes-visual"; - }; - }; - } - ); - default = { }; - }; - - meta.authors = mkOption { - type = with types; listOf str; - default = [ ]; - }; - meta.description = mkOption { - type = with types; nullOr str; - default = null; - }; - # TODO: this one has more internal structure, e.g with hreflang - # TODO: print in output - link.canonical = mkOption { - type = with types; nullOr str; - default = null; - }; - link.stylesheets = mkOption { - type = types.listOf (submodule stylesheet); - default = [ ]; - }; - - # TODO: figure out `meta` elements - # https://html.spec.whatwg.org/multipage/semantics.html#the-meta-element:concept-element-attributes - # https://html.spec.whatwg.org/multipage/semantics.html#other-metadata-names - }; - - config.categories = [ ]; - config.__toString = - self: - with lib; - print-element name self.attrs '' - ${self.title} - ${with lib; optionalString (!isNull self.base) self.base} - - - ${ - # https://html.spec.whatwg.org/multipage/semantics.html#attr-meta-http-equiv-x-ua-compatible - "" - } - - - - - - ${print-element' "meta" { - name = "viewport"; - content = "${join ", " ( - mapAttrsToList (name: value: "${name}=${toString value}") self.meta.viewport - )}"; - }} - - ${join "\n" ( - map ( - author: - print-element' "meta" { - name = "author"; - content = "${author}"; - } - ) self.meta.authors - )} - - ${join "\n" ( - map ( - stylesheet: - print-element' "link" ( - { - rel = "stylesheet"; - } - // (removeAttrs stylesheet [ - "categories" - "__toString" - ]) - ) - ) self.link.stylesheets - )} - ''; - }; - - title = - { name, ... }: - { - imports = [ element ]; - options.attrs = mkAttrs { }; - options.text = mkOption { - type = types.str; - }; - config.categories = [ "metadata" ]; - config.__toString = self: "<${name}${print-attrs self.attrs}>${self.text}"; - - }; - - base = - { ... }: - { - imports = [ element ]; - # TODO: "A base element must have either an href attribute, a target attribute, or both." - options = global-attrs // { - inherit (attrs) href target; - }; - config.categories = [ "metadata" ]; - config.__toString = self: ""; - }; - - link = - { ... }: - { - imports = [ element ]; - options = global-attrs // { - # TODO: more attributes - # https://html.spec.whatwg.org/multipage/semantics.html#the-link-element:concept-element-attributes - inherit (attrs) href; - # XXX: there are variants of `rel` for `link`, `a`/`area`, and `form` - rel = mkOption { - # https://html.spec.whatwg.org/multipage/semantics.html#attr-link-rel - type = - with types; - listOfUnique str (enum - # TODO: work out link types in detail, there are lots of additional constraints - # https://html.spec.whatwg.org/multipage/links.html#linkTypes - [ - "alternate" - "dns-prefetch" - "expect" - "help" - "icon" - "license" - "manifest" - "modulepreload" - "next" - "pingback" - "preconnect" - "prefetch" - "preload" - "prev" - "privacy-policy" - "search" - "terms-of-service" - ]); - }; - }; - # TODO: figure out how to make body-ok `link` elements - # https://html.spec.whatwg.org/multipage/semantics.html#allowed-in-the-body - config.categories = [ "metadata" ]; - config.__toString = self: ""; - }; - - # is implemented separately because it can be used both in `` and `` - # semantically it's a standalone thing but syntactically happens to be subsumed under `` - stylesheet = - { config, ... }: - { - imports = [ element ]; - options = global-attrs // { - type = mkOption { - # TODO: this must be a valid MIME type string, which is a bit involved. - # the syntax is explicated here: https://mimesniff.spec.whatwg.org/#mime-type-writing - # but the spec refers to RFC9110: https://www.rfc-editor.org/rfc/rfc9110#name-media-type - # all registered MIME types: https://www.iana.org/assignments/top-level-media-types/top-level-media-types.xhtml - # XXX: if nothing is specified, "text/css" is assumed. - # https://html.spec.whatwg.org/multipage/links.html#link-type-stylesheet:link-type-stylesheet-2 - # there's no specification on what else could be there, and it's questionable whether setting anything else even makes sense. - # in practice, browsers seem to ignore anything but "text/css", so we may as well not care at all. - type = with types; nullOr str; - default = null; - }; - # https://html.spec.whatwg.org/multipage/semantics.html#attr-link-disabled - disabled = mkOption { - type = types.bool; - default = false; - }; - # TODO: implement the rest of the stylesheet attributes - # https://html.spec.whatwg.org/#link-type-stylesheet - inherit (link-attrs) href media integrity; - }; - # https://html.spec.whatwg.org/multipage/links.html#link-type-stylesheet:body-ok - config.categories = [ - "metadata" - "phrasing" - ]; - config.__toString = - self: - print-attrs ( - removeAttrs self [ - "categories" - "__toString" - ] - ); - }; - - body = - { config, name, ... }: - { - imports = [ element ]; - options = { - attrs = mkAttrs { }; - content = mkOption { - type = - with types; - let - # Type check that ensures spec-compliant section hierarchy - # https://html.spec.whatwg.org/multipage/sections.html#headings-and-outlines-2:concept-heading-7 - with-section-constraints = - baseType: - baseType - // { - merge = - loc: defs: - with lib; - let - find-and-attach = - def: - let - process-with-depth = - depth: content: - map ( - x: - if isAttrs x && x ? section then - x - // { - section = x.section // { - heading-level = depth; - content = process-with-depth (depth + 1) (x.section.content or [ ]); - }; - } - else - x - ) content; - - find-with-depth = - depth: content: - let - sections = map (v: { - inherit (def) file; - value = v; - depth = depth; - }) (filter (x: isAttrs x && x ? section) content); - subsections = concatMap ( - x: - if isAttrs x && x ? section && x.section ? content then - find-with-depth (depth + 1) x.section.content - else - [ ] - ) content; - in - sections ++ subsections; - - in - { - inherit def; - processed = process-with-depth 1 def.value; - validation = find-with-depth 1 def.value; - }; - - processed = map find-and-attach defs; - all-sections = flatten (map (p: p.validation) processed); - too-deep = filter (sec: sec.depth > 6) all-sections; - in - if too-deep != [ ] then - throw '' - The option `${lib.options.showOption loc}` has sections nested too deeply: - ${concatMapStrings ( - sec: " - depth ${toString sec.depth} section in ${toString sec.file}\n" - ) too-deep} - Section hierarchy must not be deeper than 6 levels.'' - else - baseType.merge loc (map (p: p.def // { value = p.processed; }) processed); - }; - in - with-section-constraints - # TODO: find a reasonable cut-off for where to place raw content - (listOf (either str (attrTag categories.flow))); - default = [ ]; - }; - }; - - config.categories = [ ]; - config.__toString = - self: with lib; print-element name self.attrs (join "\n" (map toString-unwrap self.content)); - }; - - section = - { config, name, ... }: - { - imports = [ element ]; - options = { - # setting to an attribute set will wrap the section in `
` - attrs = mkOption { - type = - with types; - nullOr (submodule { - options = global-attrs; - }); - default = null; - }; - heading = mkOption { - # XXX: while there are no explicit rules on whether sections should contain headers, - # sections should have content that would be listed in an outline. - # - # https://html.spec.whatwg.org/multipage/sections.html#use-div-for-wrappers - # - # such an outline is rather meaningless without headings for navigation, - # which is why we enforce headings in sections. - # arguably, and this is encoded here, a section *is defined* by its heading. - type = - with types; - submodule ( - { config, ... }: - { - imports = [ element ]; - options = { - attrs = mkAttrs { }; - # setting to an attribute set will wrap the section in `
` - hgroup.attrs = mkOption { - type = - with types; - nullOr (submodule { - options = global-attrs; - }); - default = with lib; if (config.before == [ ] && config.after == [ ]) then null else { }; - }; - # https://html.spec.whatwg.org/multipage/sections.html#the-hgroup-element - before = mkOption { - type = with types; listOf (attrTag ({ inherit (element-types) p; } // categories.scripting)); - default = [ ]; - }; - content = mkOption { - # https://html.spec.whatwg.org/multipage/sections.html#the-h1,-h2,-h3,-h4,-h5,-and-h6-elements - type = with types; either str (listOf (attrTag categories.phrasing)); - }; - after = mkOption { - type = with types; listOf (attrTag ({ inherit (element-types) p; } // categories.scripting)); - default = [ ]; - }; - }; - } - ); - }; - # https://html.spec.whatwg.org/multipage/sections.html#headings-and-outlines - content = mkOption { - type = with types; listOf (either str (attrTag categories.flow)); - default = [ ]; - }; - }; - options.heading-level = mkOption { - # XXX: this will proudly fail if the invariant is violated, - # but the error message will be inscrutable - type = with types; ints.between 1 6; - internal = true; - }; - config = { - categories = [ - "flow" - "sectioning" - "palpable" - ]; - __toString = - self: - with lib; - let - n = toString config.heading-level; - heading = ''${self.heading.content}''; - hgroup = - with lib; - print-element "hgroup" self.heading.hgroup.attrs (squash '' - ${optionalString (!isNull self.heading.before) (toString-unwrap self.heading.before)} - ${heading} - ${optionalString (!isNull self.heading.after) (toString-unwrap self.heading.after)} - ''); - content = - (if isNull self.heading.hgroup.attrs then heading else hgroup) - + join "\n" (map toString-unwrap self.content); - in - if !isNull self.attrs then print-element name self.attrs content else content; - }; - }; - - p = - { name, ... }: - { - imports = [ element ]; - options = { - attrs = mkAttrs { }; - content = mkOption { - type = with types; either str (listOf (attrTag categories.phrasing)); - }; - }; - config.categories = [ - "flow" - "palpable" - ]; - config.__toString = self: print-element name self.attrs (toString self.content); - }; - - dl = - { config, name, ... }: - { - imports = [ element ]; - options = { - attrs = mkAttrs { }; - content = mkOption { - type = - with types; - listOf ( - submodule ( - { ... }: - { - options = { - # TODO: wrap in `
` if set - div.attrs = mkOption { - type = - with types; - nullOr (submodule { - options = global-attrs; - }); - default = null; - }; - before = mkOption { - type = with types; listOf (attrTag categories.scripting); - default = [ ]; - }; - terms = mkOption { - type = with types; nonEmptyListOf (submodule dt); - }; - between = mkOption { - type = with types; listOf (attrTag categories.scripting); - default = [ ]; - }; - descriptions = mkOption { - type = with types; nonEmptyListOf (submodule dd); - }; - after = mkOption { - type = with types; listOf (attrTag categories.scripting); - default = [ ]; - }; - }; - } - ) - ); - }; - }; - # XXX: here we can't express the spec requirement that `dl` is palpable if the list of term-description-pairs is nonempty. - # the reason is that we have to specify a child's *type* in the parent, but being palpable is a property of the value in this case. - # and while the module system does have some dependent typing capabilities, we can't say "the type is X but only if its value has property Y". - # but since the "palpable" category isn't used in any structural requirement in the spec, this is not a loss of fidelity on our side. - # TODO: the whole notion of content categories may be a red herring for this implementation after all, reconsider it. - # it does help to concisely express type constraints on an element's children, but it seems that most of the categories in the spec can be ignored entirely in this implementation. - # the cleanup task would be to identify which categories are really helpful, and document the rationale for using that mechanism as well as the specific choice of categories to keep. - config.categories = [ "flow" ]; - config.__toString = - self: - with lib; - let - content = map ( - entry: - let - list = squash '' - ${join "\n" entry.before} - ${join "\n" entry.terms} - ${join "\n" entry.between} - ${join "\n" entry.descriptions} - ${join "\n" entry.after} - ''; - in - if !isNull entry.div.attrs then print-element "div" entry.div.attrs list else list - ) self.content; - in - print-element name self.attrs (join "\n" content); - }; - - dt = - { config, ... }: - { - imports = [ element ]; - options = { - attrs = mkAttrs { }; - dt = mkOption { - type = - with types; - either str ( - submodule ( - attrTag ( - # TODO: test - with lib; - removeAttrs - (filterAttrs ( - _name: value: - !any ( - c: - elem c [ - "sectioning" - "heading" - ] - ) value.categories - ) categories.flow) - [ - "header" - "footer" - ] - ) - ) - ); - }; - }; - config.categories = [ ]; - config.__toString = self: print-element "dt" self.attrs self.dt; - }; - - dd = - { config, ... }: - { - imports = [ element ]; - options = { - attrs = mkAttrs { }; - dd = mkOption { - type = with types; either str (submodule (attrTag categories.flow)); - }; - }; - config.categories = [ ]; - config.__toString = self: print-element "dd" self.attrs self.dd; - }; - }; -in -{ - imports = [ element ]; - options = { - inherit (element-types) html; - }; - - config.categories = [ ]; - config.__toString = self: '' - - ${self.html} - ''; -} diff --git a/website/presentation/favicon.png b/website/presentation/favicon.png deleted file mode 100644 index 2bf02a99..00000000 Binary files a/website/presentation/favicon.png and /dev/null differ diff --git a/website/presentation/ngi-fediversity.svg b/website/presentation/ngi-fediversity.svg deleted file mode 100644 index 8640e921..00000000 --- a/website/presentation/ngi-fediversity.svg +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/website/presentation/style.css b/website/presentation/style.css deleted file mode 100644 index 2bb22d57..00000000 --- a/website/presentation/style.css +++ /dev/null @@ -1,222 +0,0 @@ -:root { - /* XXX: maybe use light-dark() once it's more widely supported */ - color-scheme: light dark; - --highlight: rgb(255, 110, 0); - --background: white; - --text-color: black; - --shadow: rgba(0,0,0,0.1); - scrollbar-gutter: stable; -} - -@media (prefers-color-scheme: dark) { - :root { - --background: black; - --text-color: #f0f0f0; - --shadow: rgba(255,255,255,0.2); - } -} - -body { - font-family: Heebo, sans-serif; - color: var(--text-color); - background-color: var(--background); - padding: 1em; -} - -section { - max-width: 50em; - margin: auto; - margin-top: 1em; -} - -h1, h2, h3, h4, h5, h6 { - font-family: Signika, sans-serif; - margin-top: 0; -} - -h1 { - font-size: 2em; -} - -header > nav { - font-family: Signika, sans-serif; - margin-bottom: 2em; -} - -a:visited, -a -{ - color: var(--highlight); - text-decoration: none; -} - -header a:visited, -header a -{ - color: var(--text-color); -} - -header a { - text-decoration: none; -} - -header a:hover, -header li:hover -{ - color: var(--highlight); -} - -header nav ul { - padding: 0; -} - -header > nav ul li { - list-style-type: none; -} - -header > nav > ul { - display: flex; - justify-content: space-between; - align-items: center; - max-width: 60em; - margin: auto; -} - -header > nav > ul > li:first-child a { - content: url('ngi-fediversity.svg'); - display: inline-block; - height: 2em; - margin-right: 5vw; -} - -header > nav > ul > li:last-child > a { - border: 1pt solid var(--text-color); - padding: 0.5em 1em 0.5em 1em; - border-radius: 3pt; - margin-left: 5vw; -} - -header > nav > ul > li:last-child:hover > a { - color: var(--background); - background-color: var(--highlight); - border-color: var(--background); -} - -header > nav > ul > li > details > nav { - position: absolute; - /*top: 2em;*/ - background: var(--background); - min-width: max-content; - margin-top: 1em; - padding: 1em; - box-shadow: 0 0 1em var(--shadow); - z-index: 0; -} - -header > nav > ul > li > details { - display: block; - /*padding: 1em 0;*/ - cursor: pointer; -} - -header > nav > ul > li > details[open] > summary { - color: var(--highlight); -} - -header > nav > ul > li > details > nav ul li { - padding: 0.25em 0; -} - -#menu-toggle, -#menu-toggle + label { - display: none; - appearance: none; -} - -@media (max-width: 50em) { - #menu-toggle:checked ~ nav > ul > li { - display: block; - } - - #menu-toggle ~ label { - position: absolute; - right: 0; - padding: 0.5em; - cursor: pointer; - display: block; - } - - .menu-close, - .menu-open { - cursor: pointer; - } - .menu-close { display: none; } - #menu-toggle:checked + label .menu-close { display: block; } - #menu-toggle:checked + label .menu-open { display: none; } - - header > nav { - margin-bottom: 1em; - }; - - header > nav > ul > li:not(:first-child) { - display: none; - } - - header > nav > ul { - flex-direction: column; - } - - header > nav > ul > li { - margin: 0; - padding: 0; - text-align: center; - font-size: 1.3em; - } - - header > nav > ul > li > details{ - /* compensate for collapse triangle */ - margin-left: -1rem; - } - - header > nav > ul > li > details > nav { - position: relative; - margin: 0; - padding: 0 0 0.5em 0; - box-shadow: none; - /* compensate back for container's collapse triangle compensation */ - margin-left: 1rem; - } - - header > nav > ul > li > details > nav ul li { - padding: 0; - font-size: 1.15rem; - } - - header > nav > ul::before { - content: ""; - display: flex; - justify-content: space-between; - align-items: center; - } - - header > nav > ul > li:first-child { - display: block; - } - - header > nav > ul > li:first-child a { - margin: 0 0 0.5em 0; - height: 2.5em; - } - - header > nav > ul > li:last-child { - margin: 1em 0 0 0; - } - - header > nav > ul > li:last-child a { - margin: 0; - } - - header { - position: relative; - } -} diff --git a/website/presentation/style.nix b/website/presentation/style.nix deleted file mode 100644 index df65ff33..00000000 --- a/website/presentation/style.nix +++ /dev/null @@ -1,82 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: -{ - config.assets."style.css".path = ./style.css; - config.assets."ngi-fediversity.svg".path = ./ngi-fediversity.svg; - # TODO: auto-generate a bunch from SVG - config.assets."favicon.png".path = ./favicon.png; - config.assets."fonts.css".path = - with lib; - builtins.toFile "fonts.css" ( - join "\n" ( - map - (font: '' - @font-face { - font-family: '${font.name}'; - font-style: normal; - font-weight: ${toString font.weight}; - src: url(/${head config.assets.${font.file}.locations}) format('woff2'); - } - '') - ( - (crossLists (name: file: weight: { inherit name file weight; }) [ - [ "Signika" ] - [ - "signika-extended.woff2" - "signika.woff2" - ] - [ - 500 - 700 - ] - ]) - ++ (crossLists (name: file: weight: { inherit name file weight; }) [ - [ "Heebo" ] - [ - "heebo-extended.woff2" - "heebo.woff2" - ] - [ - 400 - 600 - ] - ]) - ) - ) - ); - - # TODO: get directly from https://github.com/google/fonts - # and compress with https://github.com/fonttools/fonttools - config.assets."signika-extended.woff2" = { - path = pkgs.fetchurl { - url = "https://fonts.gstatic.com/s/signika/v25/vEFO2_JTCgwQ5ejvMV0Ox_Kg1UwJ0tKfX6bOjM7sfA.woff2"; - hash = "sha256-6xM7cHYlTKNf1b0gpqhPJjwOoZfxx9+u1e4JPYG2lKk="; - name = "signika-extended.woff2"; - }; - }; - config.assets."signika.woff2" = { - path = pkgs.fetchurl { - url = "https://fonts.gstatic.com/s/signika/v25/vEFO2_JTCgwQ5ejvMV0Ox_Kg1UwJ0tKfX6bBjM4.woff2"; - hash = "sha256-Yu0kGT3seb8Qtulu84wvY6nLyPXsRBO/JvTD2BQBtHg="; - name = "signika.woff2"; - }; - }; - config.assets."heebo-extended.woff2" = { - path = pkgs.fetchurl { - url = "https://fonts.gstatic.com/s/heebo/v26/NGS6v5_NC0k9P9H2TbE.woff2"; - hash = "sha256-lk3+fFEqYWbHHGyXkdhKnOOMGS9m5ZbbxQcRQCSlxDE="; - name = "heebo-extended.woff2"; - }; - }; - config.assets."heebo.woff2" = { - path = pkgs.fetchurl { - url = "https://fonts.gstatic.com/s/heebo/v26/NGS6v5_NC0k9P9H4TbFzsQ.woff2"; - hash = "sha256-JWnjYlbcNsg6KCJnRRjECL2HnZGJOBTMtdutWBNza4Q="; - name = "heebo.woff2"; - }; - }; -} diff --git a/website/presentation/templates.nix b/website/presentation/templates.nix deleted file mode 100644 index 4fcd88b5..00000000 --- a/website/presentation/templates.nix +++ /dev/null @@ -1,87 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: - -{ - config.templates.html = { - dom = - document: - let - eval = lib.evalModules { - class = "DOM"; - modules = [ - document - (import ./dom.nix) - ]; - }; - in - { - __toString = _: toString eval.config; - value = eval.config; - }; - - markdown = - { name, body }: - let - commonmark = - pkgs.runCommand "${name}.html" - { - buildInputs = [ pkgs.cmark ]; - } - '' - cmark ${builtins.toFile "${name}.md" body} > $out - ''; - in - builtins.readFile commonmark; - nav = - { menu, page }: - let - render-item = - item: - if item ? menu then - '' -
  • ${item.menu.label} - ${lib.indent " " (item.menu.outputs.html page)} -
  • - '' - else if item ? page then - ''
  • ${item.page.title}
  • '' - else - ''
  • ${item.link.label}
  • ''; - in - '' - - ''; - }; - - config.templates.files = - fs: - with lib; - foldl' - # TODO: create static redirects from `tail .locations` - ( - acc: elem: - acc - // - (mapAttrs' ( - type: value: { - name = head elem.locations + optionalString (type != "") ".${type}"; - value = - if isStorePath value then - value - else - builtins.toFile (elem.name + optionalString (type != "") ".${type}") (toString value); - } - )) - elem.outputs - ) - { } - fs; -} diff --git a/website/shell.nix b/website/shell.nix deleted file mode 100644 index a6bdf202..00000000 --- a/website/shell.nix +++ /dev/null @@ -1 +0,0 @@ -(import ./. { }).shell diff --git a/website/structure/article.nix b/website/structure/article.nix deleted file mode 100644 index 68694a52..00000000 --- a/website/structure/article.nix +++ /dev/null @@ -1,62 +0,0 @@ -{ - config, - options, - lib, - ... -}: -let - inherit (lib) - mkOption - types - ; - cfg = config; -in -{ - content-types.article = - { config, collection, ... }: - { - imports = [ cfg.content-types.page ]; - options = { - collection = mkOption { - description = "Collection this article belongs to"; - type = options.collections.type.nestedTypes.elemType; - default = collection; - }; - date = mkOption { - description = "Publication date"; - type = with types; str; - default = null; - }; - author = mkOption { - description = "Page author"; - type = with types; either str (nonEmptyListOf str); - default = null; - }; - }; - config.name = with lib; mkDefault (slug config.title); - config.outputs.html = lib.mkForce ( - (cfg.templates.html.page config).override ( - _final: prev: { - html = { - # TODO: make authors always a list - head.meta.authors = if lib.isList config.author then config.author else [ config.author ]; - body.content = - with lib; - map ( - e: - if isAttrs e && e ? section then - recursiveUpdate e { - section.heading = { - before = [ { p.content = "Published ${config.date}"; } ]; - after = [ { p.content = "Written by ${config.author}"; } ]; - }; - } - else - e - ) prev.html.body.content; - }; - } - ) - ); - }; -} diff --git a/website/structure/assets.nix b/website/structure/assets.nix deleted file mode 100644 index a30e5f27..00000000 --- a/website/structure/assets.nix +++ /dev/null @@ -1,44 +0,0 @@ -{ config, lib, ... }: -let - inherit (lib) - mkOption - types - ; - cfg = config; -in -{ - options.assets = mkOption { - description = '' - Collection of assets, i.e. static files that can be linked to from within documents - ''; - type = - with types; - attrsOf ( - submodule ( - { config, ... }: - { - imports = [ cfg.content-types.document ]; - options.path = mkOption { - type = types.path; - }; - config.outputs."" = if lib.isStorePath config.path then config.path else "${config.path}"; - } - ) - ); - default = { }; - }; - - config.files = - with lib; - let - flatten = - attrs: - mapAttrsToList ( - _name: value: - # HACK: we somehow have to distinguish a module value from regular attributes. - # arbitrary choice: the outputs attribute - if value ? outputs then value else mapAttrsToList value - ) attrs; - in - cfg.templates.files (flatten cfg.assets); -} diff --git a/website/structure/collections.nix b/website/structure/collections.nix deleted file mode 100644 index 4eb32db6..00000000 --- a/website/structure/collections.nix +++ /dev/null @@ -1,99 +0,0 @@ -{ - config, - options, - lib, - ... -}: - -let - inherit (lib) - mkOption - types - ; - cfg = config; -in - -{ - options.collections = mkOption { - description = '' - Named collections of unnamed pages - - Define the content type of a new collection `example` to be `article`: - - ```nix - config.collections.example.type = config.types.article; - ``` - - Add a new entry to the `example` collection: - - ```nix - config.collections.example.entry = { - # contents here - } - ``` - ''; - type = - with types; - attrsOf ( - submodule ( - { name, config, ... }: - { - options = { - type = mkOption { - description = "Type of entries in the collection"; - type = types.deferredModule; - }; - name = mkOption { - description = "Symbolic name, used as a human-readable identifier"; - type = types.str; - default = name; - }; - prefixes = mkOption { - description = '' - List of historic output locations for files in the collection - - The first element is the canonical location. - All other elements are used to create redirects to the canonical location. - - The default entry is the symbolic name of the collection. - When changing the symbolic name, append the old one to your custom list and use `lib.mkForce` to make sure the default element will be overridden. - ''; - type = with types; nonEmptyListOf str; - example = [ "." ]; - default = [ config.name ]; - }; - entry = mkOption { - description = "An entry in the collection"; - type = - with types; - collection (submodule ({ - imports = [ config.type ]; - _module.args.collection = config; - process-locations = ls: with lib; concatMap (l: map (p: "${p}/${l}") config.prefixes) ls; - })); - }; - by-name = mkOption { - description = "Entries accessible by symbolic name"; - type = with types; attrsOf attrs; - default = - with lib; - listToAttrs ( - map (e: { - name = e.name; - value = e; - }) config.entry - ); - }; - }; - } - ) - ); - }; - - config.files = - with lib; - let - collections = concatMap (collection: collection.entry) (attrValues config.collections); - in - cfg.templates.files collections; -} diff --git a/website/structure/default.nix b/website/structure/default.nix deleted file mode 100644 index 225a9120..00000000 --- a/website/structure/default.nix +++ /dev/null @@ -1,98 +0,0 @@ -{ - config, - options, - lib, - ... -}: -let - inherit (lib) - mkOption - types - ; -in -{ - imports = lib.nixFiles ./.; - - options.content-types = mkOption { - description = "Content types"; - type = with types; attrsOf deferredModule; - }; - - config.content-types.document = - { - name, - config, - options, - link, - ... - }: - { - config._module.args.link = config.link; - options = { - name = mkOption { - description = "Symbolic name, used as a human-readable identifier"; - type = types.str; - default = name; - }; - locations = mkOption { - description = '' - List of historic output locations for the resulting file - - Elements are relative paths to output files, without suffix. - The suffix will be added depending on output file type. - - The first element is the canonical location. - All other elements are used to create redirects to the canonical location. - - The default entry is the symbolic name of the document. - When changing the symbolic name, append the old one to your custom list and use `lib.mkForce` to make sure the default element will be overridden. - ''; - type = with types; nonEmptyListOf str; - apply = config.process-locations; - example = [ - "about/overview" - "index" - ]; - default = [ config.name ]; - }; - process-locations = mkOption { - description = "Function to post-process the output locations of contained document"; - type = types.functionTo options.locations.type; - default = lib.id; - }; - link = mkOption { - description = "Helper function for transparent linking to other pages"; - type = with types; functionTo attrs; - # TODO: we may want links to other representations, - # and currently the mapping of output types to output file - # names is soft. - default = - with lib; - target: - let - path = relativePath (head config.locations) (head target.locations); - links = mapAttrs ( - type: _output: path + optionalString (type != "") ".${type}" - # ^^^^^^^^^^^^ - # convention for raw files - ) target.outputs; - in - if length (attrValues links) == 0 then - throw "no output to link to for '${target.name}'" - else if length (attrValues links) == 1 then - links - // { - __toString = _: head (attrValues links); - } - else - links; - }; - outputs = mkOption { - description = '' - Representations of the document in different formats - ''; - type = with types; attrsOf (either attrs pathInStore); - }; - }; - }; -} diff --git a/website/structure/event.nix b/website/structure/event.nix deleted file mode 100644 index 2d729047..00000000 --- a/website/structure/event.nix +++ /dev/null @@ -1,96 +0,0 @@ -{ - config, - options, - lib, - ... -}: -let - inherit (lib) - mkOption - types - ; - cfg = config; -in -{ - content-types.event = - { config, collection, ... }: - { - imports = [ cfg.content-types.page ]; - options = { - collection = mkOption { - description = "Collection this event belongs to"; - type = options.collections.type.nestedTypes.elemType; - default = collection; - }; - start-date = mkOption { - description = "Start date of the event"; - type = with types; str; - }; - start-time = mkOption { - description = "Start time of the event"; - type = with types; str; - default = null; - }; - end-date = mkOption { - description = "End date of the event"; - type = with types; str; - default = null; - }; - end-time = mkOption { - description = "End time of the event"; - type = with types; str; - default = null; - }; - location = mkOption { - description = "Location of the event"; - type = with types; str; - }; - }; - config.name = with lib; mkDefault (slug config.title); - config.summary = lib.mkDefault config.description; - config.outputs.html = lib.mkForce ( - (cfg.templates.html.page config).override ( - _final: prev: { - html.body.content = - with lib; - map ( - e: - if isAttrs e && e ? section then - recursiveUpdate e { - section.content = [ - { - dl.content = - [ - { - terms = [ { dt = "Location"; } ]; - descriptions = [ { dd = config.location; } ]; - } - { - terms = [ { dt = "Start"; } ]; - descriptions = [ - { - dd = config.start-date + lib.optionalString (!isNull config.start-time) " ${config.start-time}"; - } - ]; - } - ] - ++ lib.optional (!isNull config.end-date) { - terms = [ { dt = "End"; } ]; - descriptions = [ - { - dd = config.end-date + lib.optionalString (!isNull config.end-time) " ${config.end-time}"; - } - ]; - }; - } - ] ++ e.section.content; - } - else - e - ) prev.html.body.content; - - } - ) - ); - }; -} diff --git a/website/structure/navigation.nix b/website/structure/navigation.nix deleted file mode 100644 index 80112e71..00000000 --- a/website/structure/navigation.nix +++ /dev/null @@ -1,88 +0,0 @@ -{ - config, - options, - lib, - ... -}: -let - inherit (lib) - mkOption - types - ; - cfg = config; - subtype = - baseModule: - types.submodule [ - baseModule - { - _module.freeformType = types.attrs; - # XXX: this is supposed to be used with a finished value, - # and we don't want to process locations again. - process-locations = lib.mkForce lib.id; - } - ]; -in -{ - options.menus = mkOption { - description = '' - Collection navigation menus - ''; - type = with types; attrsOf (submodule config.content-types.navigation); - }; - - config.content-types.named-link = - { ... }: - { - options = { - label = mkOption { - description = "Link label"; - type = types.str; - }; - url = mkOption { - description = "Link URL"; - type = types.str; - }; - }; - }; - - config.content-types.navigation = - { name, config, ... }: - { - options = { - name = mkOption { - description = "Symbolic name, used as a human-readable identifier"; - type = types.str; - default = name; - }; - label = mkOption { - description = "Menu label"; - type = types.str; - default = name; - }; - items = mkOption { - description = "List of menu items"; - type = - with types; - listOf (attrTag { - menu = mkOption { type = submodule cfg.content-types.navigation; }; - page = mkOption { type = subtype cfg.content-types.page; }; - link = mkOption { type = submodule cfg.content-types.named-link; }; - }); - }; - outputs = mkOption { - description = '' - Representations of the navigation structure in different formats - - It must be a function that takes the page on which the navigation is to be shown, such that relative links get computed correctly. - ''; - type = with types; attrsOf (functionTo str); - default.html = - page: - cfg.templates.html.nav { - menu = config; - inherit page; - }; - }; - }; - }; -} diff --git a/website/structure/page.nix b/website/structure/page.nix deleted file mode 100644 index 14ff619d..00000000 --- a/website/structure/page.nix +++ /dev/null @@ -1,92 +0,0 @@ -{ config, lib, ... }: -let - inherit (lib) - mkOption - types - ; - cfg = config; -in -{ - # TODO: enable i18n, e.g. via a nested attribute for language-specific content - options.pages = mkOption { - description = '' - Collection of pages on the site - ''; - type = with types; attrsOf (submodule config.content-types.page); - }; - - config.files = with lib; cfg.templates.files (attrValues config.pages); - - config.content-types.page = - { name, config, ... }: - { - imports = [ cfg.content-types.document ]; - options = { - title = mkOption { - description = "Page title"; - type = types.str; - default = name; - }; - description = mkOption { - description = '' - One-sentence description of page contents - ''; - type = types.str; - }; - summary = mkOption { - description = '' - One-paragraph summary of page contents - ''; - type = types.str; - }; - body = mkOption { - description = '' - Page contents in CommonMark - ''; - type = types.str; - }; - }; - - config.outputs.html = cfg.templates.html.page config; - }; - - config.templates.html.page = lib.template cfg.templates.html.dom (page: { - html = { - head = { - title.text = page.title; - meta.description = page.description; - link.canonical = lib.head page.locations; - link.stylesheets = [ - # TODO: allow enabling preload with a flag - { href = "${page.link cfg.assets."style.css"}"; } - { href = "${page.link cfg.assets."fonts.css"}"; } - ]; - }; - body.content = [ - '' -
    - - - ${lib.indent " " (cfg.menus.main.outputs.html page)} -
    - '' - { - section = { - attrs = { }; - heading.content = page.title; - content = [ - (cfg.templates.html.markdown { inherit (page) name body; }) - ]; - }; - } - ]; - }; - }); -} diff --git a/website/tests.nix b/website/tests.nix deleted file mode 100644 index 00f32bbb..00000000 --- a/website/tests.nix +++ /dev/null @@ -1,42 +0,0 @@ -# tests written for running with `nix-unit` -# https://github.com/nix-community/nix-unit -let - inherit (import ./. { }) lib; -in -{ - test-relativePath = - with lib; - let - testData = [ - { - from = "bar"; - to = "baz"; - expected = "./baz"; - } - { - from = "foo/bar"; - to = "foo/baz"; - expected = "./baz"; - } - { - from = "foo"; - to = "bar/baz"; - expected = "./bar/baz"; - } - { - from = "foo/bar"; - to = "baz"; - expected = "./../baz"; - } - { - from = "foo/bar/baz"; - to = "foo"; - expected = "./../../foo"; - } - ]; - in - { - expr = map (case: relativePath case.from case.to) testData; - expected = map (case: case.expected) testData; - }; -}