This commit is contained in:
2026-05-03 23:21:13 +02:00
15 changed files with 327 additions and 82 deletions
-45
View File
@@ -1,45 +0,0 @@
{ pkgs, ... }:
let
keyFile = "/run/livekit/livekit.key";
domain = "cyperpunk.de";
synapseUrl = "http://100.109.179.25:8008"; # Tailscale IP of cyper-controller
in
{
services.livekit = {
enable = true;
openFirewall = true;
inherit keyFile;
settings.room.auto_create = false;
};
services.lk-jwt-service = {
enable = true;
livekitUrl = "wss://${domain}/livekit/sfu";
inherit keyFile;
};
systemd.services.livekit-key = {
before = [
"lk-jwt-service.service"
"livekit.service"
];
wantedBy = [ "multi-user.target" ];
path = with pkgs; [
livekit
coreutils
gawk
];
script = ''
mkdir -p /run/livekit
echo "lk-jwt-service: $(livekit-server generate-keys | tail -1 | awk '{print $3}')" > "${keyFile}"
'';
serviceConfig.Type = "oneshot";
unitConfig.ConditionPathExists = "!${keyFile}";
};
systemd.services.lk-jwt-service.environment = {
LIVEKIT_FULL_ACCESS_HOMESERVERS = domain;
MATRIX_BASE_URL = synapseUrl; # tells lk-jwt-service where to validate tokens
};
}
+40 -2
View File
@@ -126,8 +126,14 @@ let
preferred_domain = "jitsi.cyperpunk.de";
};
element_call = {
url = "https://cyperpunk.de/livekit/jwt";
url = "https://element-call.cyperpunk.de";
use_exclusively = true;
participant_limit = 8;
brand = "Cyperpunk Call";
encryption = "None";
};
livekit = {
livekit_service_url = "https://cyperpunk.de/livekit/jwt/";
};
setting_defaults = {
custom_themes = catppuccinThemes;
@@ -135,6 +141,8 @@ let
};
features = {
feature_group_calls = true;
"feature_disable_call_per_sender_encryption" = true;
"feature_sliding_sync" = true;
};
}
);
@@ -143,10 +151,30 @@ let
cp ${elementConfig} $out/config.json
'';
});
synapseAdmin = pkgs.synapse-admin-etkecc.withConfig {
synapseAdmin = pkgs.ketesa.withConfig {
restrictBaseUrl = [ "https://matrix.cyperpunk.de" ];
loginFlows = [ "password" ];
};
elementCallConfigured = pkgs.element-call.overrideAttrs (old: {
postInstall = (old.postInstall or "") + ''
cp ${
builtins.toFile "element-call-config.json" (
builtins.toJSON {
default_server_config = {
"m.homeserver" = {
base_url = "https://matrix.cyperpunk.de";
server_name = "cyperpunk.de";
};
};
livekit_service_url = "https://cyperpunk.de/livekit/jwt/";
e2ee = {
default = false;
};
}
)
} $out/config.json
'';
});
in
{
@@ -155,6 +183,7 @@ in
8010 # Element
8011 # Synapse Admin
8012 # FluffyChat
8013 # Element Call
];
services.nginx.virtualHosts = {
@@ -196,6 +225,15 @@ in
];
root = "${synapseAdmin}";
};
"element-call.cyperpunk.de" = {
listen = [
{
addr = "0.0.0.0";
port = 8013;
}
];
root = "${elementCallConfigured}";
};
};
virtualisation.oci-containers.containers.fluffychat = {
+1 -1
View File
@@ -4,8 +4,8 @@
{
imports = [
./synapse.nix
# ./coturn.nix
./clients.nix
./lk-jwt.nix
];
#networking.firewall = {
+54
View File
@@ -0,0 +1,54 @@
{ config, lib, ... }:
{
sops.secrets.livekit_key_sfu = { };
services.livekit = {
enable = true;
openFirewall = true;
keyFile = config.sops.secrets.livekit_key_sfu.path;
settings = {
rtc = {
tcp_port = 7881;
#udp_port = 7882;
port_range_start = 50000;
port_range_end = 60000;
use_external_ip = true;
node_ip = "178.254.8.35";
};
room = {
auto_create = false;
enabled_codecs = [
{ mime = "video/VP8"; }
{ mime = "video/VP9"; }
{ mime = "video/H264"; }
{ mime = "audio/opus"; }
];
enable_remote_unmute = true;
};
};
};
networking.firewall.allowedTCPPorts = [ 7881 ];
systemd.services.livekit.serviceConfig = {
PrivateUsers = lib.mkForce false;
DynamicUser = lib.mkForce false;
User = "livekit";
Group = "livekit";
RestrictAddressFamilies = lib.mkForce [
"AF_INET"
"AF_INET6"
"AF_NETLINK"
"AF_UNIX"
];
SystemCallFilter = lib.mkForce [ "@system-service" ];
};
users = {
users.livekit = {
isSystemUser = true;
group = "livekit";
};
groups.livekit = { };
};
}
+24
View File
@@ -0,0 +1,24 @@
{ config, lib, ... }:
let
domain = "cyperpunk.de";
synapseUrl = "http://100.109.179.25:8008";
in
{
sops.secrets.livekit_key_jwt = { };
networking.firewall.allowedTCPPorts = [ 18080 ];
services.lk-jwt-service = {
enable = true;
keyFile = config.sops.secrets.livekit_key_jwt.path;
livekitUrl = "wss://cyperpunk.de/livekit/sfu";
};
systemd.services.lk-jwt-service = {
environment = {
LIVEKIT_FULL_ACCESS_HOMESERVERS = domain;
MATRIX_BASE_URL = synapseUrl;
LIVEKIT_JWT_BIND = lib.mkForce ":18080";
};
};
}
+14 -1
View File
@@ -33,6 +33,10 @@
experimental_features = {
"msc3266_enabled" = true;
"msc3779_enabled" = true;
"msc3401_enabled" = true;
"msc4143_enabled" = true;
"msc4195_enabled" = true;
"msc4222_enabled" = true;
};
listeners = [
{
@@ -46,6 +50,7 @@
names = [
"client"
"federation"
"openid"
];
compress = false;
}
@@ -59,7 +64,15 @@
resources = [ ];
}
];
matrix_rtc = {
enabled = true;
transports = [
{
type = "livekit";
livekit_service_url = "https://cyperpunk.de/livekit/jwt/";
}
];
};
enable_metrics = true;
};
};
+1
View File
@@ -19,6 +19,7 @@ let
"cyper-desktop" = "192.168.2.40";
"cyper-node-1" = "192.168.2.30";
"cyper-node-2" = "192.168.2.31";
"cyper-proxy" = "178.254.8.35";
};
mkWeatherScrapeConfigs =
+73 -5
View File
@@ -34,7 +34,17 @@ let
extraConfig = ''
default_type application/json;
add_header Access-Control-Allow-Origin *;
return 200 '{"m.homeserver":{"base_url":"https://matrix.cyperpunk.de"},"org.matrix.msc4143.rtc_foci":[{"type":"livekit","livekit_service_url":"https://cyperpunk.de/livekit/jwt"}]}';
return 200 '{
"m.homeserver":{
"base_url":"https://matrix.cyperpunk.de"
},
"org.matrix.msc4143.rtc_foci":[
{
"type":"livekit",
"livekit_service_url":"https://cyperpunk.de/livekit/jwt/"
}
]
}';
'';
};
"/.well-known/matrix/server" = {
@@ -68,6 +78,7 @@ in
"git.cyperpunk.de" = mkProxy 9000;
"search.cyperpunk.de" = mkProxy 11080;
"file.cyperpunk.de" = mkProxy 10000;
"ngx.cyperpunk.de" = mkWsProxy 28101;
"vault.cyperpunk.de" = mkWsProxy 8222;
"fluffy.cyperpunk.de" = mkWsProxy 8012;
@@ -89,7 +100,46 @@ in
"calvin.cyperpunk.de" = mkWsProxy 15006;
"cinny.cyperpunk.de" = mkWsProxy 8009;
"element.cyperpunk.de" = mkWsProxy 8010;
"element-call.cyperpunk.de" = {
forceSSL = true;
enableACME = true;
locations."/" = {
proxyPass = "http://${upstream}:8013";
proxyWebsockets = true;
extraConfig = ''
add_header Cross-Origin-Opener-Policy "same-origin";
add_header Cross-Origin-Embedder-Policy "require-corp";
add_header Cross-Origin-Resource-Policy "cross-origin";
'';
};
};
"element.cyperpunk.de" = {
forceSSL = true;
enableACME = true;
locations = {
"/" = {
proxyPass = "http://${upstream}:8010";
proxyWebsockets = true;
};
"/widgets/element-call/config.json" = {
extraConfig = ''
default_type application/json;
add_header Access-Control-Allow-Origin *;
return 200 '{
"livekit_service_url": "https://cyperpunk.de/livekit/jwt/",
"default_server_config": {
"m.homeserver": {
"base_url": "https://matrix.cyperpunk.de",
"server_name":"cyperpunk.de"
}
}
}';
'';
};
};
};
"cyperpunk.de" = {
forceSSL = true;
@@ -104,12 +154,30 @@ in
};
"^~ /livekit/jwt/" = {
priority = 400;
proxyPass = "http://127.0.0.1:8080";
proxyPass = "http://${upstream}:18080/";
};
"^~ /livekit/sfu" = {
"^~ /livekit/sfu/" = {
priority = 400;
proxyPass = "http://127.0.0.1:7880";
proxyPass = "http://127.0.0.1:7880/";
proxyWebsockets = true;
extraConfig = ''
proxy_set_header Host $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;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
'';
};
"/_matrix/client/unstable/org.matrix.msc4143/rtc/transports" = {
extraConfig = ''
default_type application/json;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers "Authorization, Content-Type";
add_header Access-Control-Allow-Methods "GET, OPTIONS";
return 200 '{"rtc_transports":[{"type":"livekit","livekit_service_url":"https://cyperpunk.de/livekit/jwt/"}]}';
'';
};
};
};
+62
View File
@@ -0,0 +1,62 @@
{ lib, pkgs, ... }:
let
octoprint-overlay = self: super: {
octoprint = super.octoprint.override {
packageOverrides = pyself: pysuper: {
octoprint-customcss = pyself.buildPythonPackage {
pname = "OctoPrint-CustomCSS";
version = "20201210";
format = "setuptools";
src = pkgs.fetchFromGitHub {
owner = "crankeye";
repo = "OctoPrint-CustomCSS";
rev = "7a042b11055592b42b59298ad8d579b731081acd";
sha256 = "sha256-N5DjaZ2KzSi1xfmvhS8gWKAMyXz5btYqU1QSRIMkFZY=";
};
propagatedBuildInputs = [ pysuper.octoprint ];
doCheck = false;
meta = with lib; {
description = "A simple plugin for adding custom CSS to OctoPrint";
homepage = "https://github.com/crankeye/OctoPrint-CustomCSS";
license = licenses.agpl3Only;
};
};
octoprint-bedlevelvisualizer = pyself.buildPythonPackage {
pname = "OctoPrint-BedLevelVisualizer";
version = "1.1.1";
format = "setuptools";
src = pkgs.fetchFromGitHub {
owner = "jneilliii";
repo = "OctoPrint-BedLevelVisualizer";
rev = "1.1.1";
sha256 = "1v7gqyp605z3hyc1w8a2h6ir6k0vp2ccby1wwxlri6h4i2yii5z8";
};
propagatedBuildInputs = [ pysuper.octoprint ];
doCheck = false;
meta = with lib; {
description = "Visualize your bed leveling via a 3D mesh";
homepage = "https://github.com/jneilliii/OctoPrint-BedLevelVisualizer";
license = licenses.mit;
};
};
};
};
};
in
{
nixpkgs.overlays = [ octoprint-overlay ];
services.octoprint = {
enable = true;
host = "0.0.0.0";
openFirewall = true;
port = 5000;
plugins =
ps: with ps; [
octoprint-customcss
octoprint-bedlevelvisualizer
];
};
}
+30 -24
View File
@@ -1,44 +1,50 @@
{ pkgs, ... }:
{ config, ... }:
{
sops.secrets.paperless_admin = {
owner = "paperless";
};
services.paperless = {
enable = true;
package = pkgs.paperless-ngx;
address = "0.0.0.0";
port = 28101;
domain = "ngx.cyperpunk.de";
consumptionDir = "/storage/fast/paperless/consume";
dataDir = "/storage/fast/paperless";
configureTika = true;
passwordFile = config.sops.secrets.paperless_admin.path;
settings = {
# Da der Proxy auf einem anderen Server (via Tailscale) liegt:
# Erlaubt Paperless, die 'X-Forwarded-*' Header zu akzeptieren
PAPERLESS_USE_X_FORWARDED_HOST = "true";
PAPERLESS_USE_X_FORWARDED_PORT = "true";
# Erlaubt den Zugriff über die Domain UND die Tailscale-IP
# Der Stern '*' ist die einfachste Lösung für private Server
PAPERLESS_USE_X_FORWARDED_HOST = true;
PAPERLESS_USE_X_FORWARDED_PORT = true;
PAPERLESS_ALLOWED_HOSTS = "ngx.cyperpunk.de,100.109.179.25,localhost";
# Füge die IP auch zu den vertrauenswürdigen Ursprüngen hinzu (für CSRF)
PAPERLESS_CSRF_TRUSTED_ORIGINS = [
"https://ngx.cyperpunk.de"
"http://100.109.179.25:28101"
];
# Restliche Einstellungen bleiben gleich
PAPERLESS_OCR_LANGUAGE = "deu+eng";
PAPERLESS_CONSUMPTION_DIR = "/var/lib/paperless/consume"; # Falls du den Bind-Mount nutzt
PAPERLESS_URL = "https://ngx.cyperpunk.de";
PAPERLESS_CONSUMER_POLLING = 60;
};
exporter = {
enable = true;
directory = "/storage/backup/paperless";
};
};
# Gruppe und Berechtigungen wie besprochen
users.users.paperless.extraGroups = [ "users" ];
systemd.tmpfiles.rules = [
"d /storage/internal/paperless 0775 root users -"
"z /storage/internal/paperless 0775 root users -"
];
systemd = {
tmpfiles.rules = [
"d /storage/fast/paperless 0775 paperless paperless -"
"d /storage/fast/paperless/media 0775 paperless paperless -"
"d /storage/fast/paperless/consume 0775 paperless paperless -"
"d /storage/backup/paperless 0775 root users -"
];
# Öffne den Port für Tailscale (oder das lokale Netz)
services.paperless-scheduler = {
after = [ "systemd-tmpfiles-setup.service" ];
requires = [ "systemd-tmpfiles-setup.service" ];
};
};
networking.firewall.allowedTCPPorts = [ 28101 ];
}