diff --git a/host/Rory-ovh/configuration.nix b/host/Rory-ovh/configuration.nix
new file mode 100755
index 0000000..3ded494
--- /dev/null
+++ b/host/Rory-ovh/configuration.nix
@@ -0,0 +1,122 @@
+{
+ pkgs,
+ lib,
+ nixpkgs-Draupnir,
+ nixpkgs-DraupnirPkg,
+ ...
+}:
+
+{
+ imports = [
+ ../../modules/base-server.nix
+ ../../modules/users/levi.nix
+ ../../modules/users/db2k.nix
+ ../../modules/users/ks.nix
+ ../../modules/users/Alice.nix
+
+ ./services/prometheus.nix
+
+ ./services/nginx/nginx.nix
+ ./services/cgit.nix
+ ./services/postgres.nix
+ ./services/matrix/synapse/synapse-main.nix
+ ./services/matrix/draupnir.nix
+ ./services/email/root.nix
+ #./services/wireguard/wireguard.nix
+ ./services/safensound.nix
+ ];
+
+ users.groups.ocp = { };
+ boot.loader.grub.devices = lib.mkForce [ "nodev" ];
+ networking = {
+ hostName = "Rory-ovh";
+ nat = {
+ enable = true;
+ internalInterfaces = [
+ "ve-+"
+ "vb-+"
+ ];
+ externalInterface = "enp98s0f0";
+ enableIPv6 = false;
+ };
+ enableIPv6 = lib.mkForce false;
+ nameservers = lib.mkForce [ "1.1.1.1" ];
+ firewall.enable = lib.mkForce true;
+ resolvconf.enable = false;
+ defaultGateway = lib.mkForce null;
+ defaultGateway6 = lib.mkForce null;
+ };
+
+ systemd.network = {
+ enable = true;
+ networks.enp98s0f0 = {
+ name = "enp98s0f0";
+ DHCP = "no";
+ #gateway = [ "51.210.113.254" ];
+ routes = [
+ {
+ Gateway = "51.210.113.254";
+ GatewayOnLink = true;
+ }
+ ];
+ address = [ "51.210.113.110/32" ];
+ };
+ };
+
+ monitoring = {
+ monitorAll = true;
+ localPrometheus = true;
+ exposePrometheus = true;
+ localGrafana = true;
+ exposeGrafana = true;
+ nginxHost = "monitoring.rory.gay";
+ nginxSsl = true;
+ };
+
+ nixpkgs.config.permittedInsecurePackages = [
+ "olm-3.2.16"
+ "dotnet-runtime-wrapped-7.0.20"
+ "dotnet-runtime-7.0.20"
+ "dotnet-sdk-7.0.20"
+ ];
+ services.irqbalance.enable = true;
+
+ environment.memoryAllocator.provider = "jemalloc";
+
+ containers."draupnir-cme" = import ./services/containers/draupnir-cme/container.nix {
+ inherit
+ pkgs
+ lib
+ nixpkgs-Draupnir
+ nixpkgs-DraupnirPkg
+ ;
+ };
+
+ containers."draupnir-fedora" = import ./services/containers/draupnir-fedora/container.nix {
+ inherit
+ pkgs
+ lib
+ nixpkgs-Draupnir
+ nixpkgs-DraupnirPkg
+ ;
+ };
+
+ containers."draupnir-ansible" = import ./services/containers/draupnir-ansible/container.nix {
+ inherit
+ pkgs
+ lib
+ nixpkgs-Draupnir
+ nixpkgs-DraupnirPkg
+ ;
+ };
+
+ system.stateVersion = "22.11"; # DO NOT EDIT!
+
+ environment.systemPackages = with pkgs; [ waypipe ];
+
+ nix.nrBuildUsers = 128;
+ services.owncast = {
+ enable = true;
+ port = 1934;
+ };
+}
diff --git a/host/Rory-ovh/hooks/post-rebuild.sh b/host/Rory-ovh/hooks/post-rebuild.sh
new file mode 100755
index 0000000..f4f5896
--- /dev/null
+++ b/host/Rory-ovh/hooks/post-rebuild.sh
@@ -0,0 +1,30 @@
+#!/usr/bin/env nix-shell
+#!nix-shell -i bash -p curl gnused nix coreutils jq openssl
+#set -x
+exit
+REG_KEY=`cat /var/lib/matrix-synapse/registration_shared_secret.txt`
+LOCALPART='rory.gay'
+REACHABLE_DOMAIN='http://localhost:8008'
+
+# -- LICENSE: CNPL v7+ - https://thufie.lain.haus/files/CNPLv7.md
+# Modified from Nyaaori (https://nyaaori.cat) <+@nyaaori.cat>
+# Explicit authorisation to use the code has been granted by the original author
+# for use by members of the Rory& system (https://rory.gay)
+
+# the magic function:
+register(){
+ echo "Registering $1"
+ _nonce=`curl -s http://localhost:8008/_synapse/admin/v1/register | jq -r .nonce`
+ #data: nonce, domain, username, password
+ _hmac=`printf '%s\0%s\0%s\0%s' "$_nonce" "$1" "$2" "admin" | openssl dgst -sha1 -hmac "$REG_KEY" | awk '{print $2}'`
+ curl -s -XPOST -d '{"nonce": "'"$_nonce"'", "username": "'"$1"'", "displayname": "'"$1"'", "password": "'"$2"'", "admin": true, "mac": "'"$_hmac"'"}' $REACHABLE_DOMAIN/_synapse/admin/v1/register | tee -a matrix-user-tokens.txt
+ echo
+}
+
+# -- END OF LICENSED CODE
+
+#PASSWD=`cat /etc/matrix-user-pass`
+#for u in {draupnir,Alicia,Emma,Rory,root,Quetzelle}
+#do
+# register $u $PASSWD
+#done
diff --git a/host/Rory-ovh/services/cgit.nix b/host/Rory-ovh/services/cgit.nix
new file mode 100644
index 0000000..cbdc350
--- /dev/null
+++ b/host/Rory-ovh/services/cgit.nix
@@ -0,0 +1,62 @@
+{ pkgs, lib, cgit-magenta, ... }:
+
+let
+ pkg = cgit-magenta.packages.${pkgs.stdenv.hostPlatform.system}.default;
+ base_cgit_config = {
+ enable = true;
+ nginx.virtualHost = "cgit.rory.gay";
+ #package = pkgs.cgit-pink;
+ package = pkg;
+ scanPath = "/data/git";
+ settings = {
+ css = "/cgit.css";
+ logo = "/cgit.png";
+ favicon = "/favicon.ico";
+ readme = ":README.MD";
+ about-filter = "${pkg}/lib/cgit/filters/about-formatting.sh";
+ source-filter = "${pkg}/lib/cgit/filters/syntax-highlighting.py";
+ clone-url = (
+ lib.concatStringsSep " " [
+ "https://cgit.rory.gay/$CGIT_REPO_URL"
+ "ssh://<user>@git.rory.gay:$CGIT_REPO_URL"
+ ]
+ );
+ enable-log-filecount = 1;
+ enable-log-linecount = 1;
+ enable-git-config = 1;
+ #testing
+ enable-blame = 1;
+ enable-commit-graph = 1;
+ enable-follow-links = 1;
+ enable-http-clone = 1;
+ enable-index-links = 1;
+ enable-remote-branches = 1;
+ enable-subject-links = 1;
+ enable-tree-linenumbers = 1;
+ max-atom-items = 100;
+ max-commit-count = 250;
+ max-repo-count = 500;
+ snapshots = "tar.xz";
+ #side-by-side-diffs = 1;
+
+ root-title = "cgit.rory.gay";
+ root-desc = "Rory&s Git Repositories";
+ };
+ };
+in
+{
+ services.cgit."main" = base_cgit_config;
+ services.fcgiwrap.instances."cgit-main".process.prefork = 32;
+
+ services.cgit."ocp" = lib.attrsets.recursiveUpdate base_cgit_config {
+ scanPath = "/data/git/.ocp";
+ nginx.location = "/.ocp/";
+ settings.clone-url = (
+ lib.concatStringsSep " " [
+ "https://cgit.rory.gay/.ocp/$CGIT_REPO_URL"
+ "ssh://<user>@git.rory.gay:.ocp/$CGIT_REPO_URL"
+ ]
+ );
+ };
+ services.fcgiwrap.instances."cgit-ocp".process.prefork = 32;
+}
diff --git a/host/Rory-ovh/services/containers/draupnir-ansible/container.nix b/host/Rory-ovh/services/containers/draupnir-ansible/container.nix
new file mode 100644
index 0000000..5ab1aed
--- /dev/null
+++ b/host/Rory-ovh/services/containers/draupnir-ansible/container.nix
@@ -0,0 +1,37 @@
+{
+# nixpkgs-Draupnir,
+# nixpkgs-DraupnirPkg,
+ ...
+}:
+
+{
+ privateNetwork = true;
+ autoStart = true;
+ specialArgs = {
+# inherit nixpkgs-Draupnir;
+# inherit nixpkgs-DraupnirPkg;
+ };
+ config =
+ { lib, pkgs, ... }:
+ {
+ imports = [
+ ../shared.nix
+ ./root.nix
+ ./services/draupnir.nix
+# "${nixpkgs-Draupnir}/nixos/modules/services/matrix/draupnir.nix"
+ ];
+# nixpkgs.overlays = [
+# (final: prev: {
+# draupnir = nixpkgs-DraupnirPkg.legacyPackages.${pkgs.stdenv.hostPlatform.system}.draupnir;
+# })
+# ];
+ };
+ hostAddress = "192.168.100.1";
+ localAddress = "192.168.100.19";
+
+ bindMounts."draupnir-access-token" = {
+ hostPath = "/data/secrets/draupnir-ansible-access-token";
+ mountPoint = "/etc/draupnir-access-token";
+ isReadOnly = true;
+ };
+}
diff --git a/host/Rory-ovh/services/containers/draupnir-ansible/root.nix b/host/Rory-ovh/services/containers/draupnir-ansible/root.nix
new file mode 100644
index 0000000..0ebce9e
--- /dev/null
+++ b/host/Rory-ovh/services/containers/draupnir-ansible/root.nix
@@ -0,0 +1,16 @@
+{ ... }:
+
+{
+ networking.useHostResolvConf = true;
+
+ networking.hosts = {
+ "192.168.100.1" = [
+ "matrix.rory.gay"
+ "rory.gay"
+ ];
+ };
+
+ networking.firewall = {
+ enable = true;
+ };
+}
diff --git a/host/Rory-ovh/services/containers/draupnir-ansible/services/draupnir.nix b/host/Rory-ovh/services/containers/draupnir-ansible/services/draupnir.nix
new file mode 100644
index 0000000..c05b170
--- /dev/null
+++ b/host/Rory-ovh/services/containers/draupnir-ansible/services/draupnir.nix
@@ -0,0 +1,30 @@
+{ ... }:
+
+{
+ services.draupnir = {
+ enable = true;
+ secrets.accessToken = "/etc/draupnir-access-token";
+
+ settings = {
+ homeserverUrl = "https://matrix.rory.gay";
+ managementRoom = "#draupnir-ansible-mgmt:rory.gay";
+ recordIgnoredInvites = true; # We want to be aware of invites
+ autojoinOnlyIfManager = true; # ... but we don't want the bot to be invited to eg. Matrix HQ...
+ automaticallyRedactForReasons = [ "*" ]; # Always autoredact
+ fasterMembershipChecks = true;
+
+ backgroundDelayMS = 10; # delay isn't needed, I don't mind the performance hit
+ pollReports = false;
+
+ admin.enableMakeRoomAdminCommand = false;
+ commands.ban.defaultReasons = [ "spam" ];
+
+ protections = {
+ wordlist = {
+ words = [ "https://postimg.cc/" ];
+ minutesBeforeTrusting = 0;
+ };
+ };
+ };
+ };
+}
diff --git a/host/Rory-ovh/services/containers/draupnir-cme/container.nix b/host/Rory-ovh/services/containers/draupnir-cme/container.nix
new file mode 100755
index 0000000..b1ee74b
--- /dev/null
+++ b/host/Rory-ovh/services/containers/draupnir-cme/container.nix
@@ -0,0 +1,37 @@
+{
+ #nixpkgs-Draupnir,
+ #nixpkgs-DraupnirPkg,
+ ...
+}:
+
+{
+ privateNetwork = true;
+ autoStart = true;
+ specialArgs = {
+ #inherit nixpkgs-Draupnir;
+ #inherit nixpkgs-DraupnirPkg;
+ };
+ config =
+ { lib, pkgs, ... }:
+ {
+ imports = [
+ ../shared.nix
+ ./root.nix
+ ./services/draupnir.nix
+ #"${nixpkgs-Draupnir}/nixos/modules/services/matrix/draupnir.nix"
+ ];
+# nixpkgs.overlays = [
+# (final: prev: {
+# draupnir = nixpkgs-DraupnirPkg.legacyPackages.${pkgs.stdenv.hostPlatform.system}.draupnir;
+# })
+# ];
+ };
+ hostAddress = "192.168.100.1";
+ localAddress = "192.168.100.17";
+
+ bindMounts."draupnir-access-token" = {
+ hostPath = "/data/secrets/draupnir-cme-access-token";
+ mountPoint = "/etc/draupnir-access-token";
+ isReadOnly = true;
+ };
+}
diff --git a/host/Rory-ovh/services/containers/draupnir-cme/root.nix b/host/Rory-ovh/services/containers/draupnir-cme/root.nix
new file mode 100755
index 0000000..0ebce9e
--- /dev/null
+++ b/host/Rory-ovh/services/containers/draupnir-cme/root.nix
@@ -0,0 +1,16 @@
+{ ... }:
+
+{
+ networking.useHostResolvConf = true;
+
+ networking.hosts = {
+ "192.168.100.1" = [
+ "matrix.rory.gay"
+ "rory.gay"
+ ];
+ };
+
+ networking.firewall = {
+ enable = true;
+ };
+}
diff --git a/host/Rory-ovh/services/containers/draupnir-cme/services/draupnir.nix b/host/Rory-ovh/services/containers/draupnir-cme/services/draupnir.nix
new file mode 100755
index 0000000..4b3cd57
--- /dev/null
+++ b/host/Rory-ovh/services/containers/draupnir-cme/services/draupnir.nix
@@ -0,0 +1,23 @@
+{ ... }:
+
+{
+ services.draupnir = {
+ enable = true;
+ secrets.accessToken = "/etc/draupnir-access-token";
+
+ settings = {
+ homeserverUrl = "https://matrix.rory.gay";
+ managementRoom = "#draupnir-cme:rory.gay";
+ recordIgnoredInvites = true; # We want to be aware of invites
+ autojoinOnlyIfManager = true; # ... but we don't want the bot to be invited to eg. Matrix HQ...
+ automaticallyRedactForReasons = [ "*" ]; # Always autoredact
+ fasterMembershipChecks = true;
+
+ backgroundDelayMS = 10; # delay isn't needed, I don't mind the performance hit
+ pollReports = false;
+
+ admin.enableMakeRoomAdminCommand = false;
+ commands.ban.defaultReasons = [ "spam" ];
+ };
+ };
+}
diff --git a/host/Rory-ovh/services/containers/draupnir-fedora/container.nix b/host/Rory-ovh/services/containers/draupnir-fedora/container.nix
new file mode 100644
index 0000000..5ba9765
--- /dev/null
+++ b/host/Rory-ovh/services/containers/draupnir-fedora/container.nix
@@ -0,0 +1,37 @@
+{
+# nixpkgs-Draupnir,
+# nixpkgs-DraupnirPkg,
+ ...
+}:
+
+{
+ privateNetwork = true;
+ autoStart = true;
+ specialArgs = {
+# inherit nixpkgs-Draupnir;
+# inherit nixpkgs-DraupnirPkg;
+ };
+ config =
+ { lib, pkgs, ... }:
+ {
+ imports = [
+ ../shared.nix
+ ./root.nix
+ ./services/draupnir.nix
+# "${nixpkgs-Draupnir}/nixos/modules/services/matrix/draupnir.nix"
+ ];
+# nixpkgs.overlays = [
+# (final: prev: {
+# draupnir = nixpkgs-DraupnirPkg.legacyPackages.${pkgs.stdenv.hostPlatform.system}.draupnir;
+# })
+# ];
+ };
+ hostAddress = "192.168.100.1";
+ localAddress = "192.168.100.18";
+
+ bindMounts."draupnir-access-token" = {
+ hostPath = "/data/secrets/draupnir-fedora-access-token";
+ mountPoint = "/etc/draupnir-access-token";
+ isReadOnly = true;
+ };
+}
diff --git a/host/Rory-ovh/services/containers/draupnir-fedora/root.nix b/host/Rory-ovh/services/containers/draupnir-fedora/root.nix
new file mode 100644
index 0000000..0ebce9e
--- /dev/null
+++ b/host/Rory-ovh/services/containers/draupnir-fedora/root.nix
@@ -0,0 +1,16 @@
+{ ... }:
+
+{
+ networking.useHostResolvConf = true;
+
+ networking.hosts = {
+ "192.168.100.1" = [
+ "matrix.rory.gay"
+ "rory.gay"
+ ];
+ };
+
+ networking.firewall = {
+ enable = true;
+ };
+}
diff --git a/host/Rory-ovh/services/containers/draupnir-fedora/services/draupnir.nix b/host/Rory-ovh/services/containers/draupnir-fedora/services/draupnir.nix
new file mode 100644
index 0000000..a39b3a9
--- /dev/null
+++ b/host/Rory-ovh/services/containers/draupnir-fedora/services/draupnir.nix
@@ -0,0 +1,30 @@
+{ ... }:
+
+{
+ services.draupnir = {
+ enable = true;
+ secrets.accessToken = "/etc/draupnir-access-token";
+
+ settings = {
+ homeserverUrl = "https://matrix.rory.gay";
+ managementRoom = "#draupnir-fedora-mgmt:rory.gay";
+ recordIgnoredInvites = true; # We want to be aware of invites
+ autojoinOnlyIfManager = true; # ... but we don't want the bot to be invited to eg. Matrix HQ...
+ automaticallyRedactForReasons = [ "*" ]; # Always autoredact
+ fasterMembershipChecks = true;
+
+ backgroundDelayMS = 10; # delay isn't needed, I don't mind the performance hit
+ pollReports = false;
+
+ admin.enableMakeRoomAdminCommand = false;
+ commands.ban.defaultReasons = [ "spam" ];
+
+ protections = {
+ wordlist = {
+ words = [ "https://postimg.cc/" ];
+ minutesBeforeTrusting = 0;
+ };
+ };
+ };
+ };
+}
diff --git a/host/Rory-ovh/services/containers/shared.nix b/host/Rory-ovh/services/containers/shared.nix
new file mode 100644
index 0000000..f267ff0
--- /dev/null
+++ b/host/Rory-ovh/services/containers/shared.nix
@@ -0,0 +1,17 @@
+{ pkgs, ... }:
+{
+ environment.systemPackages = with pkgs; [
+ neofetch
+ lnav
+ zsh
+ git
+ lsd
+ htop
+ btop
+ duf
+ kitty.terminfo
+ neovim
+ jq
+ dig
+ ];
+}
diff --git a/host/Rory-ovh/services/email/autoconfig.nix b/host/Rory-ovh/services/email/autoconfig.nix
new file mode 100644
index 0000000..5f3bce2
--- /dev/null
+++ b/host/Rory-ovh/services/email/autoconfig.nix
@@ -0,0 +1,18 @@
+{ config, ... }:
+{
+ services.go-autoconfig = {
+ enable = !config.virtualisation.isVmVariant;
+ settings = {
+ service_addr = ":1323";
+ domain = "autoconfig.rory.gay";
+ imap = {
+ server = "rory.gay";
+ port = 993;
+ };
+ smtp = {
+ server = "rory.gay";
+ port = 587;
+ };
+ };
+ };
+}
diff --git a/host/Rory-ovh/services/email/maddy.conf b/host/Rory-ovh/services/email/maddy.conf
new file mode 100644
index 0000000..1d3eb2f
--- /dev/null
+++ b/host/Rory-ovh/services/email/maddy.conf
@@ -0,0 +1,124 @@
+
+# Minimal configuration with TLS disabled, adapted from upstream example
+# configuration here https://github.com/foxcpp/maddy/blob/master/maddy.conf
+# Do not use this in production!
+
+auth.pass_table local_authdb {
+ table sql_table {
+ driver sqlite3
+ dsn credentials.db
+ table_name passwords
+ }
+}
+
+storage.imapsql local_mailboxes {
+ driver sqlite3
+ dsn imapsql.db
+}
+
+table.chain local_rewrites {
+ optional_step regexp "(.+)\+(.+)@(.+)" "$1@$3"
+ optional_step static {
+ entry postmaster root@$(primary_domain)
+ }
+ optional_step file /etc/maddy/aliases
+}
+
+msgpipeline local_routing {
+ destination postmaster $(local_domains) {
+ modify {
+ replace_rcpt &local_rewrites
+ }
+ deliver_to &local_mailboxes
+ }
+ default_destination {
+ reject 550 5.1.1 "User doesn't exist"
+ }
+}
+
+smtp tcp://0.0.0.0:25 {
+ limits {
+ all rate 20 1s
+ all concurrency 10
+ }
+ dmarc yes
+ check {
+ require_mx_record
+ dkim
+ spf
+ }
+ source $(local_domains) {
+ reject 501 5.1.8 "Use Submission for outgoing SMTP"
+ }
+ default_source {
+ destination postmaster $(local_domains) {
+ deliver_to &local_routing
+ }
+ default_destination {
+ reject 550 5.1.1 "User doesn't exist"
+ }
+ }
+}
+
+submission tls://0.0.0.0:465 tcp://0.0.0.0:587 {
+ limits {
+ all rate 50 1s
+ }
+ auth &local_authdb
+ source $(local_domains) {
+ check {
+ authorize_sender {
+ prepare_email &local_rewrites
+ user_to_email identity
+ }
+ }
+ destination postmaster $(local_domains) {
+ deliver_to &local_routing
+ }
+ default_destination {
+ modify {
+ dkim $(primary_domain) $(local_domains) default
+ }
+ deliver_to &remote_queue
+ }
+ }
+ default_source {
+ reject 501 5.1.8 "Non-local sender domain"
+ }
+}
+
+target.remote outbound_delivery {
+ limits {
+ destination rate 20 1s
+ destination concurrency 10
+ }
+ mx_auth {
+ dane
+ mtasts {
+ cache fs
+ fs_dir mtasts_cache/
+ }
+ local_policy {
+ min_tls_level encrypted
+ min_mx_level none
+ }
+ }
+}
+
+target.queue remote_queue {
+ target &outbound_delivery
+ autogenerated_msg_domain $(primary_domain)
+ bounce {
+ destination postmaster $(local_domains) {
+ deliver_to &local_routing
+ }
+ default_destination {
+ reject 550 5.0.0 "Refusing to send DSNs to non-local addresses"
+ }
+ }
+}
+
+imap tls://0.0.0.0:993 tcp://0.0.0.0:143 {
+ auth &local_authdb
+ storage &local_mailboxes
+}
\ No newline at end of file
diff --git a/host/Rory-ovh/services/email/maddy.nix b/host/Rory-ovh/services/email/maddy.nix
new file mode 100644
index 0000000..548cb1a
--- /dev/null
+++ b/host/Rory-ovh/services/email/maddy.nix
@@ -0,0 +1,71 @@
+{
+ lib,
+ pkgs,
+ options,
+ config,
+ ...
+}:
+{
+ config = lib.mkIf (!config.virtualisation.isVmVariant) {
+ services.maddy = {
+ enable = true;
+ primaryDomain = "rory.gay";
+ hostname = "mail.rory.gay";
+ ensureAccounts = [
+ "root@rory.gay"
+ ];
+ ensureCredentials = {
+ "root@rory.gay".passwordFile = "/var/lib/maddy/passwd/root";
+ };
+ config = builtins.readFile ./maddy.conf;
+ # builtins.replaceStrings
+ # [
+ # "imap tcp://0.0.0.0:143"
+ # "submission tcp://0.0.0.0:587"
+ # "entry postmaster postmaster@$(primary_domain)"
+ # ]
+ # [
+ # "imap tls://0.0.0.0:993 tcp://0.0.0.0:143"
+ # "submission tls://0.0.0.0:465 tcp://0.0.0.0:587"
+ # "entry postmaster root@$(primary_domain)"
+ # ]
+ # options.services.maddy.config.default;
+
+ tls = {
+ loader = "file";
+ certificates = [
+ {
+ # certPath = "/var/lib/acme/mail.rory.gay/fullchain.pem";
+ # keyPath = "/var/lib/acme/mail.rory.gay/key.pem";
+ certPath = "/run/credentials/maddy.service/acme-fullchain.pem";
+ keyPath = "/run/credentials/maddy.service/acme-key.pem";
+ }
+ ];
+ };
+ };
+
+ networking.firewall.allowedTCPPorts = [
+ 25
+ 143
+ 465
+ 587
+ 993
+ ];
+
+ users.users.maddy.extraGroups = [ "nginx" ];
+
+ fileSystems."/var/lib/maddy" = {
+ depends = [ "/" ];
+ device = "/data/maddy";
+ fsType = "none";
+ options = [ "bind" ];
+ };
+
+ systemd.services.maddy.serviceConfig = {
+ LoadCredential = [
+ "acme-fullchain.pem:/var/lib/acme/rory.gay/fullchain.pem"
+ "acme-key.pem:/var/lib/acme/rory.gay/key.pem"
+ ];
+ };
+ };
+}
diff --git a/host/Rory-ovh/services/email/nginx.nix b/host/Rory-ovh/services/email/nginx.nix
new file mode 100644
index 0000000..5b04612
--- /dev/null
+++ b/host/Rory-ovh/services/email/nginx.nix
@@ -0,0 +1,32 @@
+{ config, ... }:
+{
+ services.nginx.virtualHosts = {
+ "mta-sts.rory.gay" = {
+ enableACME = !config.virtualisation.isVmVariant;
+ forceSSL = !config.virtualisation.isVmVariant;
+ locations = {
+ "/.well-known/mta-sts.txt" = {
+ # age 604800
+ return = ''
+ 200 "version: STSv1
+ mode: enforce
+ max_age: 120
+ mx: mail.rory.gay
+ "'';
+ };
+ };
+ };
+ "mail.rory.gay" = {
+ enableACME = !config.virtualisation.isVmVariant;
+ forceSSL = !config.virtualisation.isVmVariant;
+ locations = {
+ "/".return = "200 'OK'";
+ };
+ };
+ "autoconfig.rory.gay" = {
+ enableACME = !config.virtualisation.isVmVariant;
+ forceSSL = !config.virtualisation.isVmVariant;
+ locations."/".proxyPass = "http://localhost:1323";
+ };
+ };
+}
diff --git a/host/Rory-ovh/services/email/root.nix b/host/Rory-ovh/services/email/root.nix
new file mode 100644
index 0000000..7db85d8
--- /dev/null
+++ b/host/Rory-ovh/services/email/root.nix
@@ -0,0 +1,8 @@
+{ ... }:
+{
+ imports = [
+ ./autoconfig.nix
+ ./maddy.nix
+ ./nginx.nix
+ ];
+}
diff --git a/host/Rory-ovh/services/mastodon.nix b/host/Rory-ovh/services/mastodon.nix
new file mode 100644
index 0000000..56f1808
--- /dev/null
+++ b/host/Rory-ovh/services/mastodon.nix
@@ -0,0 +1,12 @@
+{ ... }:
+
+{
+ services.mastodon = {
+ enable = true;
+ webProcesses = 8;
+ webThreads = 4;
+
+ streamingProcesses = 63;
+ localDomain = "rory.gay";
+ };
+}
diff --git a/host/Rory-ovh/services/matrix/coturn.nix b/host/Rory-ovh/services/matrix/coturn.nix
new file mode 100755
index 0000000..805faa9
--- /dev/null
+++ b/host/Rory-ovh/services/matrix/coturn.nix
@@ -0,0 +1,52 @@
+{ ... }:
+
+{
+ # coturn (WebRTC)
+ services.coturn = {
+ enable = false; # Alicia - figure out secret first...
+ no-cli = true;
+ no-tcp-relay = true;
+ min-port = 49000;
+ max-port = 50000;
+ use-auth-secret = true;
+ static-auth-secret = "will be world readable for local users :(";
+ realm = "turn.example.com";
+ # Alicia - figure out how to get this to work, since nginx runs on separate machine...
+ #cert = "${config.security.acme.certs.${realm}.directory}/full.pem";
+ #pkey = "${config.security.acme.certs.${realm}.directory}/key.pem";
+ extraConfig = ''
+ # for debugging
+ verbose
+ # ban private IP ranges
+ no-multicast-peers
+ denied-peer-ip=0.0.0.0-0.255.255.255
+ denied-peer-ip=10.0.0.0-10.255.255.255
+ denied-peer-ip=100.64.0.0-100.127.255.255
+ denied-peer-ip=127.0.0.0-127.255.255.255
+ denied-peer-ip=169.254.0.0-169.254.255.255
+ denied-peer-ip=172.16.0.0-172.31.255.255
+ denied-peer-ip=192.0.0.0-192.0.0.255
+ denied-peer-ip=192.0.2.0-192.0.2.255
+ denied-peer-ip=192.88.99.0-192.88.99.255
+ denied-peer-ip=192.168.0.0-192.168.255.255
+ denied-peer-ip=198.18.0.0-198.19.255.255
+ denied-peer-ip=198.51.100.0-198.51.100.255
+ denied-peer-ip=203.0.113.0-203.0.113.255
+ denied-peer-ip=240.0.0.0-255.255.255.255
+ denied-peer-ip=::1
+ denied-peer-ip=64:ff9b::-64:ff9b::ffff:ffff
+ denied-peer-ip=::ffff:0.0.0.0-::ffff:255.255.255.255
+ denied-peer-ip=100::-100::ffff:ffff:ffff:ffff
+ denied-peer-ip=2001::-2001:1ff:ffff:ffff:ffff:ffff:ffff:ffff
+ denied-peer-ip=2002::-2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff
+ denied-peer-ip=fc00::-fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
+ denied-peer-ip=fe80::-febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff
+ '';
+ };
+ #services.matrix-synapse = with config.services.coturn; {
+ # turn_uris = ["turn:${realm}:3478?transport=udp" "turn:${realm}:3478?transport=tcp"];
+ # turn_shared_secret = static-auth-secret;
+ # turn_user_lifetime = "1h";
+ #};
+
+}
diff --git a/host/Rory-ovh/services/matrix/draupnir.nix b/host/Rory-ovh/services/matrix/draupnir.nix
new file mode 100755
index 0000000..3f6d89a
--- /dev/null
+++ b/host/Rory-ovh/services/matrix/draupnir.nix
@@ -0,0 +1,43 @@
+{ pkgs, draupnirSrc, ... }:
+
+{
+ services.draupnir = {
+
+ enable = true;
+ secrets.accessToken = "/data/secrets/draupnir-access-token";
+
+ settings = {
+ homeserverUrl = "https://matrix.rory.gay";
+ managementRoom = "#draupnir-mgmt:rory.gay";
+ recordIgnoredInvites = true; # Let's log ignored invites, just incase
+ autojoinOnlyIfManager = true; # Let's not open ourselves up to DoS attacks
+ automaticallyRedactForReasons = [ "*" ]; # I always want autoredact
+ fasterMembershipChecks = true;
+ logLevel = "DEBUG";
+ #roomStateBackingStore.enabled = true; # broken under nix.
+
+ backgroundDelayMS = 10; # delay isn't needed, I don't mind the performance hit
+ pollReports = false; # this is a single person homeserver... let's save ourself the work
+
+ admin.enableMakeRoomAdminCommand = true;
+ commands.ban.defaultReasons = [
+ "spam"
+ "harassment"
+ "transphobia"
+ "scam"
+ ];
+ protections = {
+ wordlist = {
+ words = [
+ "tranny"
+ "faggot"
+ "ywnbaw"
+ "nigger"
+ "https://postimg.cc/"
+ ];
+ minutesBeforeTrusting = 0;
+ };
+ };
+ };
+ };
+}
diff --git a/host/Rory-ovh/services/matrix/grapevine.nix b/host/Rory-ovh/services/matrix/grapevine.nix
new file mode 100755
index 0000000..7368c2a
--- /dev/null
+++ b/host/Rory-ovh/services/matrix/grapevine.nix
@@ -0,0 +1,31 @@
+{ ... }:
+
+{
+ services.grapevine = {
+ enable = true;
+ settings = {
+ conduit_compat = true;
+ server_name = "conduit.rory.gay";
+ #trusted_servers = [ "rory.gay" ];
+ federation.self_test = false;
+
+ listen = [
+ {
+ type = "tcp";
+ address = "127.0.0.1";
+ port = 6167;
+ }
+ ];
+ server_discovery.client.base_url = "https://conduit.rory.gay"; # This is required for some reason
+
+ database = {
+ backend = "rocksdb";
+ };
+ allow_registration = false;
+
+ #log = "info";
+ #log_format = "full";
+ #log = "debug";
+ };
+ };
+}
diff --git a/host/Rory-ovh/services/matrix/matrix-appservice-discord.nix b/host/Rory-ovh/services/matrix/matrix-appservice-discord.nix
new file mode 100755
index 0000000..3041aaa
--- /dev/null
+++ b/host/Rory-ovh/services/matrix/matrix-appservice-discord.nix
@@ -0,0 +1,25 @@
+{ ... }:
+
+{
+ # Discord bridge
+ services.matrix-appservice-discord = {
+ enable = false; # Alicia - figure out secret first...
+ environmentFile = /etc/keyring/matrix-appservice-discord/tokens.env;
+ # The appservice is pre-configured to use SQLite by default.
+ # It's also possible to use PostgreSQL.
+ settings = {
+ bridge = {
+ domain = "rory.gay";
+ homeserverUrl = "https://matrix.rory.gay";
+ };
+
+ # The service uses SQLite by default, but it's also possible to use
+ # PostgreSQL instead:
+ database = {
+ # filename = ""; # empty value to disable sqlite
+ connString = "postgres://postgres@127.0.0.1/matrix-appservice-discord";
+ };
+ };
+ };
+
+}
diff --git a/host/Rory-ovh/services/matrix/ooye.nix b/host/Rory-ovh/services/matrix/ooye.nix
new file mode 100644
index 0000000..7b9c403
--- /dev/null
+++ b/host/Rory-ovh/services/matrix/ooye.nix
@@ -0,0 +1,10 @@
+{ ... }:
+
+{
+ services.matrix-ooye = {
+ enable = true;
+ homeserver = "https://matrix.rory.gay";
+ homeserverName = "rory.gay";
+ enableSynapseIntegration = true;
+ };
+}
diff --git a/host/Rory-ovh/services/matrix/root.nix b/host/Rory-ovh/services/matrix/root.nix
new file mode 100755
index 0000000..d32cc54
--- /dev/null
+++ b/host/Rory-ovh/services/matrix/root.nix
@@ -0,0 +1,13 @@
+{ ... }:
+
+{
+ imports = [
+ ./synapse/synapse-main.nix
+ ./coturn.nix
+ ./matrix-appservice-discord.nix
+ ./draupnir.nix
+ ./grapevine.nix
+ ./ooye.nix
+ ];
+
+}
diff --git a/host/Rory-ovh/services/matrix/synapse/caches.nix b/host/Rory-ovh/services/matrix/synapse/caches.nix
new file mode 100644
index 0000000..f00c78c
--- /dev/null
+++ b/host/Rory-ovh/services/matrix/synapse/caches.nix
@@ -0,0 +1,25 @@
+{
+ gc_min_interval = [
+ "15m"
+ "30m"
+ "60m"
+ ];
+ gc_thresholds = [
+ 10000
+
+ 5000
+ 2500
+ ];
+ event_cache_size = "12000K"; # defaults to 10K
+ caches = {
+ global_factor = 500000.0;
+ cache_entry_ttl = "24h";
+ expire_caches = true;
+ sync_response_cache_duration = "15m";
+ cache_autotuning = {
+ max_cache_memory_usage = "65536M";
+ target_cache_memory_usage = "32768M";
+ min_cache_ttl = "6h";
+ };
+ };
+}
diff --git a/host/Rory-ovh/services/matrix/synapse/db.nix b/host/Rory-ovh/services/matrix/synapse/db.nix
new file mode 100644
index 0000000..409c039
--- /dev/null
+++ b/host/Rory-ovh/services/matrix/synapse/db.nix
@@ -0,0 +1,49 @@
+{
+ workerName ? null,
+ dbGroup ? null,
+}:
+{
+ name = "psycopg2";
+ args = {
+ user = "matrix-synapse-rory-gay";
+ password = "somepassword";
+ database = "matrix-synapse-rory-gay";
+ host = "/run/postgresql";
+ application_name = "matrix-synapse (rory.gay) - ${if workerName == null then throw "synapse/db.nix: workerName unspecified" else workerName}";
+ cp_min =
+ if dbGroup == "solo" then
+ 1
+ else if dbGroup == "small" then
+ 2
+ else if dbGroup == "medium" then
+ 5
+ else if dbGroup == "large" then
+ 10
+ else
+ throw "synapse/db.nix: Invalid dbGroup: ${if dbGroup == null then "null" else dbGroup}";
+ cp_max =
+ if dbGroup == "solo" then
+ 1
+ else if dbGroup == "small" then
+ 2
+ else if dbGroup == "medium" then
+ 10
+ else if dbGroup == "large" then
+ 10
+ else
+ throw "synapse/db.nix: Invalid dbGroup: ${if dbGroup == null then "null" else dbGroup}";
+
+ # cp_reconnect - default=True - https://github.com/element-hq/synapse/blob/develop/synapse/storage/database.py#L129
+ # cp_noisy - default=False - https://docs.twisted.org/en/stable/api/twisted.enterprise.adbapi.ConnectionPool.html#__init__ - info logs during operation
+ # check_same_thread - default=False - https://github.com/element-hq/synapse/blob/develop/synapse/config/database.py#L65 - can this even be set?
+ };
+
+ # synchronous_commit - default=True - https://github.com/element-hq/synapse/blob/develop/synapse/storage/engines/postgres.py#L56
+ # statement_timeout - default=60 * 60 * 1000 ms - https://github.com/element-hq/synapse/blob/develop/synapse/storage/engines/postgres.py#L63
+ # allow_unsafe_locale - default=False - https://github.com/element-hq/synapse/blob/develop/synapse/storage/engines/postgres.py#L99
+ # allow_outdated_version - default=False - https://github.com/element-hq/synapse/blob/develop/synapse/storage/engines/postgres.py#L92 - needs source link
+ # txn_limit - default=0 - https://github.com/element-hq/synapse/blob/develop/synapse/storage/database.py#L564
+
+ statement_timeout = 24 * 60 * 60 * 1000; # 24 hours, good for bg jobs
+ txn_limit = 500; # maybe dropping old data from pg caches helps?
+}
diff --git a/host/Rory-ovh/services/matrix/synapse/ratelimits.nix b/host/Rory-ovh/services/matrix/synapse/ratelimits.nix
new file mode 100644
index 0000000..85f51f2
--- /dev/null
+++ b/host/Rory-ovh/services/matrix/synapse/ratelimits.nix
@@ -0,0 +1,97 @@
+{
+ # messages
+ rc_message = {
+ per_second = 1000000;
+ burst_count = 1000000;
+ };
+ rc_admin_redaction = {
+ per_second = 10000000;
+ burst_count = 10000000;
+ };
+
+ # room joins
+ rc_joins = {
+ local = {
+ per_second = 1000;
+ burst_count = 1000;
+ };
+ remote = {
+ per_second = 1000;
+ burst_count = 1000;
+ };
+ };
+ rc_joins_per_room = {
+ per_second = 1000;
+ burst_count = 1000;
+ };
+
+ # room invites
+ rc_invites = {
+ per_room = {
+ per_second = 1000;
+ burst_count = 1000;
+ };
+ per_user = {
+ per_second = 1000;
+ burst_count = 1000;
+ };
+ per_issuer = {
+ per_second = 1000;
+ burst_count = 1000;
+ };
+ };
+ rc_third_party_invite = {
+ per_second = 1000;
+ burst_count = 1000;
+ };
+
+ # federation
+ rc_federation = {
+ window_size = 10;
+ sleep_limit = 1000;
+ sleep_delay = 100;
+ reject_limit = 1000;
+ concurrent = 100;
+ };
+ federation_rr_transactions_per_room_per_second = 100;
+
+ # media
+ rc_media_create = {
+ per_second = 1000;
+ burst_count = 1000;
+ };
+ remote_media_download_burst_count = "512G";
+ remote_media_download_per_second = "512G";
+
+ # authentication
+ rc_login = {
+ address = {
+ per_second = 1000;
+ burst_count = 1000;
+ };
+ account = {
+ per_second = 1000;
+ burst_count = 1000;
+ };
+ failed_attempts = {
+ per_second = 0.1;
+ burst_count = 3;
+ };
+ };
+ rc_3pid_validation = {
+ per_second = 1000;
+ burst_count = 1000;
+ };
+
+ #presence
+ rc_presence.per_user = {
+ per_second = 1;
+ burst_count = 2;
+ };
+
+ #delayed events
+ rc_delayed_event_mgmt = {
+ per_second = 1000;
+ burst_count = 1000;
+ };
+}
diff --git a/host/Rory-ovh/services/matrix/synapse/synapse-main.nix b/host/Rory-ovh/services/matrix/synapse/synapse-main.nix
new file mode 100755
index 0000000..7907927
--- /dev/null
+++ b/host/Rory-ovh/services/matrix/synapse/synapse-main.nix
@@ -0,0 +1,283 @@
+{ config, pkgs, ... }:
+
+{
+ # Worker plumbing examples: https://github.com/element-hq/synapse/blob/master/docker/configure_workers_and_start.py
+ # Documentation: https://github.com/element-hq/synapse/blob/develop/docs/workers.md
+ services.matrix-synapse = {
+ enable = true;
+ withJemalloc = true;
+ dataDir = "/data/matrix-synapse";
+
+ nginxVirtualHostName = "matrix.rory.gay";
+ enableWorkers = true;
+
+ federationSenders = if config.virtualisation.isVmVariant then 0 else 16; # 16
+ pushers = if config.virtualisation.isVmVariant then 1 else 1;
+ mediaRepoWorkers = if config.virtualisation.isVmVariant then 1 else 2; # 4
+ clientReaders = if config.virtualisation.isVmVariant then 2 else 2; # 4
+ syncWorkers = if config.virtualisation.isVmVariant then 2 else 2; # 4
+ #authWorkers = 0;
+
+ eventCreators = if config.virtualisation.isVmVariant then 2 else 16;
+
+ federationReaders = if config.virtualisation.isVmVariant then 0 else 8; # 8
+ federationInboundWorkers = if config.virtualisation.isVmVariant then 0 else 16; # 8
+
+ enableAppserviceWorker = if config.virtualisation.isVmVariant then true else true;
+ enableBackgroundWorker = if config.virtualisation.isVmVariant then true else true;
+ enableUserDirWorker = if config.virtualisation.isVmVariant then true else true;
+
+ accountDataStreamWriters = 1;
+ eventStreamWriters = 2; # 8
+ presenceStreamWriters = 1;
+ pushRuleStreamWriters = 1;
+ receiptStreamWriters = 1;
+ toDeviceStreamWriters = 1;
+ typingStreamWriters = 1;
+
+ plugins = with pkgs.matrix-synapse-plugins; [
+ synapse-http-antispam
+ ];
+
+ #untested:
+ #sharedStreamWriters = 1;
+
+ # https://matrix-org.github.io/synapse/latest/usage/configuration/config_documentation.html
+ settings =
+ {
+ server_name = "rory.gay";
+
+ # use_frozen_dicts = true;
+ # user_agent_suffix = " (rory.gay)";
+
+ # look into later: replication_torture_level - https://github.com/element-hq/synapse/blob/develop/synapse/config/server.py#L560
+ # limit_remote_rooms ???
+ # cleanup_extremities_with_dummy_events - default=True
+ # dummy_events_threshold - default=10 - required forward extremities to send dummy event
+ # enable_ephemeral_messages - default=False - ???
+ # rooms_to_exclude_from_sync - default=[] - room ids...
+ # third_party_event_rules - https://github.com/element-hq/synapse/blob/develop/synapse/config/third_party_event_rules.py - ???
+ # default_power_level_content_override - default=None - https://github.com/element-hq/synapse/blob/develop/synapse/config/room.py#L73
+
+ dummy_events_threshold = 5;
+ cleanup_extremities_with_dummy_events = true;
+
+ enable_registration = true;
+ registration_requires_token = true;
+
+ require_membership_for_aliases = false;
+ redaction_retention_period = null;
+ user_ips_max_age = null;
+ allow_device_name_lookup_over_federation = true;
+
+ federation = {
+ client_timeout = "90s"; # 30 # default=60s
+ max_short_retries = 6; # 12
+ max_short_retry_delay = "10s"; # 5
+ max_long_retries = 5;
+ max_long_retry_delay = "30s";
+
+ # rapid retry, small increments
+ destination_min_retry_interval = "1m"; # default=10m
+ destination_max_retry_interval = "12h"; # default=7d
+ destination_retry_multiplier = 1.1; # 1.2 # default=2
+ };
+
+ registration_shared_secret_path = "/data/secrets/synapse-shared-secret";
+
+ listeners = [
+ {
+ port = 8008;
+ bind_addresses = [ "127.0.0.1" ];
+ type = "http";
+ tls = false;
+ x_forwarded = true;
+ resources = [
+ {
+ names = [
+ "client"
+ "federation"
+ ];
+ compress = false;
+ }
+ ];
+ }
+ {
+ type = "http";
+ path = "/run/matrix-synapse/main.sock";
+ resources = [
+ {
+ names = [ "replication" ];
+ compress = false;
+ }
+ ];
+ }
+ ];
+ presence = {
+ enable = true;
+ update_interval = 60;
+ };
+ database = (
+ import ./db.nix {
+ workerName = "main";
+ dbGroup = "medium";
+ }
+ );
+ app_service_config_files = [
+ #"/etc/matrix-synapse/appservice-registration.yaml"
+ #"/var/lib/matrix-synapse/modas-registration.yaml"
+ ];
+
+ #region Media
+ max_upload_size = "512M";
+
+ max_avatar_size = "512M";
+ max_image_pixels = "250M";
+
+ max_pending_media_uploads = 512;
+ dynamic_thumbnails = true;
+
+ prevent_media_downloads_from = [
+ # none, give me all the media
+ ];
+ enable_authenticated_media = false;
+
+ url_preview_enabled = true;
+ max_spider_size = "50M";
+
+ #endregion
+
+ ui_auth = {
+ session_timeout = "1m";
+ };
+
+ login_via_existing_session = {
+ enabled = true;
+ require_ui_auth = true;
+ token_timeout = "1y";
+ };
+
+ report_stats = false;
+
+ user_directory = {
+ enabled = true;
+ search_all_users = true;
+ prefer_local_users = true;
+ };
+
+ # https://github.com/element-hq/synapse/blob/master/synapse/config/experimental.py
+ experimental_features = {
+ "msc2409_to_device_messages_enabled" = true;
+ "msc2815_enabled" = true; # Redacted event content
+ "msc3026_enabled" = true; # Busy presence
+ "msc3202_transaction_extensions" = true; # appservice transaction extensions (device list/keys)
+ "msc3266_enabled" = true; # Room summary API
+ "msc3391_enabled" = true; # Remove account data
+ "msc3823_account_suspension" = true; # Account suspension
+ "msc3852_enabled" = true; # Last seen on /devices (CS-API/admin)
+ "msc3874_enabled" = true; # filtering /messages with rel_types / not_rel_types
+ "msc3890_enabled" = true; # communicate account data deletion to clients
+ "msc3912_enabled" = true; # /messages with rel_types / not_rel_types and event id
+ "msc3916_authenticated_media_enabled" = true; # Authenticated media
+ "msc4069_profile_inhibit_propagation" = true; # Inhibit profile update propagation
+ "msc4133_enabled" = true; # Custom profile fields
+ "msc4151_enabled" = true; # Report room API (CS-API)
+ "msc4210_enabled" = false; # Remove legacy mentions -- we want this *disabled* for moderation reasons
+ "msc4222_enabled" = true; # state_after in sync
+ };
+
+ redis = {
+ enabled = true;
+ path = "/run/redis-matrix-synapse/redis.sock";
+ };
+
+ instance_map = {
+ main = {
+ # replication listener
+ path = "/run/matrix-synapse/main.sock";
+ };
+ };
+ }
+ // import ./ratelimits.nix
+ // import ./caches.nix;
+ };
+
+ #systemd.services.matrix-synapse-reg-token = {
+ # description = "Random registration token for Synapse.";
+ # before = [ "matrix-synapse.service" ]; # So the registration can be used by Synapse
+ # wantedBy = [ "multi-user.target" ];
+ # after = [ "network.target" ];
+#
+ # script = ''
+ # set -e -x -o pipefail
+ # echo "Starting key generation"
+ # if [ ! -f "registration_shared_secret.txt" ]
+ # then
+ # echo "Generating new key"
+ # strace cat /dev/urandom | tr -dc a-zA-Z0-9 | fold -w 256 | head -n 1 > registration_shared_secret.txt
+ # echo "Key generation complete"
+ # else
+ # echo "Not generating key, key exists"
+ # fi
+ # echo "Script complete"
+ # '';
+ # serviceConfig = {
+ # User = "matrix-synapse";
+ # Group = "matrix-synapse";
+ # WorkingDirectory = "/var/lib/matrix-synapse";
+ # RemainAfterExit = true;
+ # };
+ #};
+
+ services.redis = {
+ package = pkgs.valkey;
+ servers.matrix-synapse = {
+ enable = true;
+ user = "matrix-synapse";
+ };
+ };
+
+ systemd.tmpfiles.rules = [ "D /run/redis-matrix-synapse 0755 matrix-synapse matrix-synapse" ];
+
+ virtualisation.vmVariant = {
+ systemd.tmpfiles.rules = [ "D /run/secrets 0755 nobody nobody" ];
+ systemd.services."matrix-synapse-generate-token" = {
+ # generate /data/secrets/synapse-shared-secret
+ description = "Generate Synapse shared secret";
+ wantedBy = [ "multi-user.target" ];
+ after = [ "network.target" ];
+ before = [ "matrix-synapse.service" ];
+ script = ''
+ set -e -x -o pipefail
+ echo "Starting key generation"
+ if [ ! -f "/data/secrets/synapse-shared-secret" ]
+ then
+ echo "Generating new key"
+ ${pkgs.openssl}/bin/openssl rand -base64 32 > /data/secrets/synapse-shared-secret
+ echo "Key generation complete"
+ else
+ echo "Not generating key, key exists"
+ fi
+ echo "Script complete"
+ '';
+ };
+ systemd.services."matrix-synapse-postgres-init" = {
+ description = "Generate synapse postgres user";
+ wantedBy = [ "multi-user.target" ];
+ after = [ "network.target" "postgresql.service" ];
+ before = [ "matrix-synapse.service" ];
+
+ script = ''
+ set -e -x -o pipefail
+ ${pkgs.postgresql}/bin/createuser ${config.services.matrix-synapse.settings.database.args.user} || true
+ ${pkgs.postgresql}/bin/createdb --encoding=UTF8 --locale=C --template=template0 --owner=${config.services.matrix-synapse.settings.database.args.user} ${config.services.matrix-synapse.settings.database.args.database} || true
+ '';
+ serviceConfig = {
+ User = "postgres";
+ Group = "postgres";
+ WorkingDirectory = config.services.postgresql.dataDir;
+ RemainAfterExit = true;
+ };
+ };
+ };
+}
diff --git a/host/Rory-ovh/services/nginx/nginx.nix b/host/Rory-ovh/services/nginx/nginx.nix
new file mode 100755
index 0000000..d422cc8
--- /dev/null
+++ b/host/Rory-ovh/services/nginx/nginx.nix
@@ -0,0 +1,95 @@
+{ config, pkgs, ... }:
+let
+ serveDir = config: {
+ enableACME = if config ? ssl then config.ssl else !config.virtualisation.isVmVariant;
+ addSSL = if config ? ssl then config.ssl else true;
+ root = if config ? path then config.path else builtins.throw "path is required";
+ locations = {
+ "/" = {
+ index = "index.html";
+ };
+ };
+ };
+in
+{
+ services = {
+ nginx = {
+ enable = true;
+ package = pkgs.nginxQuic;
+ recommendedProxySettings = true;
+ recommendedTlsSettings = true;
+ recommendedZstdSettings = true;
+ #recommendedGzipSettings = true;
+ recommendedBrotliSettings = true;
+ recommendedOptimisation = true;
+ defaultMimeTypes = ../../../../packages/nginx/mime.types;
+ appendConfig = ''
+ worker_processes 16;
+ '';
+ eventsConfig = ''
+ #use kqueue;
+ worker_connections 512;
+ '';
+ appendHttpConfig = ''
+ #sendfile on;
+ disable_symlinks off;
+ log_format combined_vhosts '$remote_addr - $remote_user [$time_local] {host="$host",server_name="$server_name",upstream=$upstream_addr,t=$request_time[u_conn=$upstream_connect_time,u_hdr=$upstream_header_time,u_resp=$upstream_response_time]} "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"';
+ access_log /var/log/nginx/access.log combined_vhosts;
+ '';
+ additionalModules = with pkgs.nginxModules; [ moreheaders ];
+ virtualHosts = {
+ #"boorunav.com" = serveDir { path = "/data/nginx/html_boorunav"; };
+ # "catgirlsaresexy.com" = serveDir { path = "/data/nginx/html_catgirlsaresexy"; };
+ # "sugarcanemc.org" = serveDir { path = "/data/nginx/html_sugarcanemc"; };
+#
+ #"siliconheaven.thearcanebrony.net" = serveDir { path = "/data/nginx/html_siliconheaven"; };
+ #"lfs.thearcanebrony.net" = serveDir { path = "/data/nginx/html_lfs"; };
+ #"git.thearcanebrony.net" = serveDir { path = "/data/nginx/html_git"; };
+ #"files.thearcanebrony.net" = serveDir { path = "/data/nginx/html_files"; };
+ #"spigotav.thearcanebrony.net" = serveDir { path = "/data/nginx/html_spigotav"; };
+ #"terra.thearcanebrony.net" = serveDir { path = "/data/nginx/html_terrarchive"; };
+ #"vives.thearcanebrony.net" = serveDir { path = "/data/nginx/html_vives"; };
+#
+ # "git.rory.gay" = serveDir { path = "/data/nginx/html_git"; };
+ # "wad.rory.gay" = serveDir { path = "/data/nginx/html_wad"; } // {
+ # locations."/".extraConfig = "autoindex on; try_files $uri $uri/ /index.html;";
+ # };
+ # "wad-api.rory.gay" = import ./rory.gay/wad-api.nix;
+#
+ #"thearcanebrony.net" = import ./thearcanebrony.net/root.nix;
+ # "sentry.thearcanebrony.net" = import ./thearcanebrony.net/sentry.nix;
+ # "search.thearcanebrony.net" = import ./thearcanebrony.net/search.nix;
+#
+ "rory.gay" = import ./rory.gay/root.nix { inherit config; };
+ # "lfs.rory.gay" = serveDir { path = "/data/nginx/html_lfs"; };
+#
+ # "awooradio.thearcanebrony.net" = import ./thearcanebrony.net/awooradio.nix;
+ "cgit.rory.gay" = import ./rory.gay/cgit.nix { inherit config; };
+ # #"jitsi.rory.gay" = import ./rory.gay/jitsi.nix;
+#
+ # #matrix...
+ # "conduit.rory.gay" = import ./rory.gay/conduit.nix;
+ "matrix.rory.gay" = import ./rory.gay/matrix.nix { inherit config; };
+ "libmatrix-fed-test.rory.gay" = import ./rory.gay/libmatrix-fed-test.nix { inherit config; };
+ "safensound.rory.gay" = import ./rory.gay/safensound.nix { inherit config; };
+ "demo.safensound.rory.gay" = import ./rory.gay/demo.safensound.nix { inherit config; };
+ "api.safensound.rory.gay" = import ./rory.gay/api.safensound.nix { inherit config; };
+ "stream.rory.gay" = import ./rory.gay/stream.nix { inherit config; };
+ # "pcpoc.rory.gay" = import ./rory.gay/pcpoc.nix;
+ # "matrixunittests.rory.gay" = import ./rory.gay/matrixunittests.nix;
+ # "conduit.matrixunittests.rory.gay" = import ./rory.gay/conduit.matrixunittests.nix;
+ "mru.rory.gay" = import ./rory.gay/mru.nix { inherit config; };
+ "ec.rory.gay" = import ./rory.gay/ec.nix { inherit config; };
+ };
+ };
+ };
+ systemd.services.nginx.serviceConfig = {
+ LimitNOFILE = 5000000;
+ };
+ security.acme.acceptTerms = true;
+ security.acme.defaults.email = "root@rory.gay";
+
+ networking.hosts."127.0.0.1" = builtins.attrNames config.services.nginx.virtualHosts;
+ networking.firewall.allowedTCPPorts = [ 80 443 ];
+ networking.firewall.allowedUDPPorts = [ 443 ];
+}
diff --git a/host/Rory-ovh/services/nginx/rory.gay/api.safensound.nix b/host/Rory-ovh/services/nginx/rory.gay/api.safensound.nix
new file mode 100755
index 0000000..b0ff075
--- /dev/null
+++ b/host/Rory-ovh/services/nginx/rory.gay/api.safensound.nix
@@ -0,0 +1,72 @@
+{ config }:
+{
+ enableACME = !config.virtualisation.isVmVariant;
+ addSSL = !config.virtualisation.isVmVariant;
+ locations."/" = {
+ #proxyPass = "http://127.0.0.1:9001";
+ proxyPass = "http://localhost:7645";
+ extraConfig = ''
+ if ($request_method = 'OPTIONS') {
+ more_set_headers 'Access-Control-Allow-Origin: *';
+ more_set_headers 'Access-Control-Allow-Methods: *';
+ #
+ # Custom headers and headers various browsers *should* be OK with but aren't
+ #
+ more_set_headers 'Access-Control-Allow-Headers: *, Authorization';
+ #
+ # Tell client that this pre-flight info is valid for 20 days
+ #
+ more_set_headers 'Access-Control-Max-Age: 1728000';
+ more_set_headers 'Content-Type: text/plain; charset=utf-8';
+ more_set_headers 'Content-Length: 0';
+ return 204;
+ }
+ '';
+ };
+
+ locations."= /.well-known/matrix/server".extraConfig = ''
+ more_set_headers 'Content-Type application/json';
+ more_set_headers 'Access-Control-Allow-Origin *';
+ return 200 '${builtins.toJSON { "m.server" = "matrix.rory.gay:443"; }}';
+ '';
+ locations."= /.well-known/matrix/client".extraConfig = ''
+ more_set_headers 'Content-Type application/json';
+ more_set_headers 'Access-Control-Allow-Origin *';
+ return 200 '${
+ builtins.toJSON {
+ "m.homeserver".base_url = "https://matrix.rory.gay";
+ "org.matrix.msc3575.proxy".url = "https://matrix.rory.gay";
+ }
+ }';
+ '';
+ locations."= /.well-known/matrix/support".extraConfig = ''
+ more_set_headers 'Content-Type application/json';
+ more_set_headers 'Access-Control-Allow-Origin *';
+ return 200 '${
+ builtins.toJSON {
+ admins = [
+ {
+ matrix_id = "@emma:rory.gay";
+ role = "admin";
+ }
+ {
+ matrix_id = "@alicia:rory.gay";
+ role = "admin";
+ }
+ {
+ matrix_id = "@root:rory.gay";
+ role = "admin";
+ }
+ {
+ matrix_id = "@rory:rory.gay";
+ role = "admin";
+ }
+ ];
+ }
+ }';
+ '';
+
+ locations."~ ^/(client/|_matrix/client/unstable/org.matrix.msc3575/sync)" = {
+ proxyPass = "http://localhost:8100";
+ };
+}
diff --git a/host/Rory-ovh/services/nginx/rory.gay/cgit.nix b/host/Rory-ovh/services/nginx/rory.gay/cgit.nix
new file mode 100755
index 0000000..7b49a42
--- /dev/null
+++ b/host/Rory-ovh/services/nginx/rory.gay/cgit.nix
@@ -0,0 +1,14 @@
+{ config }:
+{
+ enableACME = !config.virtualisation.isVmVariant;
+ addSSL = !config.virtualisation.isVmVariant;
+ root = "/data/git";
+ extraConfig = ''
+ autoindex on;
+ more_set_headers 'Access-Control-Allow-Origin: *';
+ more_set_headers 'Access-Control-Allow-Methods: GET, POST, OPTIONS';
+ more_set_headers 'Access-Control-Allow-Headers: DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
+ more_set_headers 'Access-Control-Expose-Headers: Content-Length,Content-Range';
+ more_set_headers 'Access-Control-Allow-Credentials: true';
+ '';
+}
diff --git a/host/Rory-ovh/services/nginx/rory.gay/conduit.matrixunittests.nix b/host/Rory-ovh/services/nginx/rory.gay/conduit.matrixunittests.nix
new file mode 100755
index 0000000..231d5e3
--- /dev/null
+++ b/host/Rory-ovh/services/nginx/rory.gay/conduit.matrixunittests.nix
@@ -0,0 +1,16 @@
+{ config }:
+{
+ enableACME = !config.virtualisation.isVmVariant;
+ addSSL = !config.virtualisation.isVmVariant;
+ http3 = true;
+ http3_hq = true;
+ kTLS = true;
+ extraConfig = ''
+ brotli off;
+ '';
+ locations = {
+ "/" = {
+ proxyPass = "http://192.168.100.15:80";
+ };
+ };
+}
diff --git a/host/Rory-ovh/services/nginx/rory.gay/demo.safensound.nix b/host/Rory-ovh/services/nginx/rory.gay/demo.safensound.nix
new file mode 100755
index 0000000..f75c78b
--- /dev/null
+++ b/host/Rory-ovh/services/nginx/rory.gay/demo.safensound.nix
@@ -0,0 +1,30 @@
+{ config }:
+{
+ enableACME = !config.virtualisation.isVmVariant;
+ addSSL = !config.virtualisation.isVmVariant;
+# quic = true;
+ http3 = !config.virtualisation.isVmVariant;
+ http3_hq = !config.virtualisation.isVmVariant;
+ kTLS = !config.virtualisation.isVmVariant;
+ root = "/data/nginx/html_safensound_demo";
+# reuseport = true;
+ extraConfig = ''
+ brotli off;
+ brotli_static off;
+ '';
+ locations = {
+ "/" = {
+ index = "index.html";
+ extraConfig = ''
+ more_set_headers 'Access-Control-Allow-Origin: *';
+ more_set_headers 'Access-Control-Allow-Methods: *';
+ more_set_headers 'Access-Control-Allow-Headers: *';
+ more_set_headers 'Access-Control-Expose-Headers: *';
+ more_set_headers 'Access-Control-Max-Age' 1728000;
+
+ # default to /index.html if file not found
+ try_files $uri $uri/ /index.html;
+ '';
+ };
+ };
+}
diff --git a/host/Rory-ovh/services/nginx/rory.gay/ec.nix b/host/Rory-ovh/services/nginx/rory.gay/ec.nix
new file mode 100755
index 0000000..c50b1f9
--- /dev/null
+++ b/host/Rory-ovh/services/nginx/rory.gay/ec.nix
@@ -0,0 +1,26 @@
+{ config }:
+{
+ enableACME = !config.virtualisation.isVmVariant;
+ addSSL = !config.virtualisation.isVmVariant;
+ root = "/data/nginx/html_ec";
+ reuseport = true;
+ extraConfig = ''
+ brotli off;
+ brotli_static off;
+ '';
+ locations = {
+ "/" = {
+ index = "index.html";
+ extraConfig = ''
+ more_set_headers 'Access-Control-Allow-Origin: *';
+ more_set_headers 'Access-Control-Allow-Methods: *';
+ more_set_headers 'Access-Control-Allow-Headers: *';
+ more_set_headers 'Access-Control-Expose-Headers: *';
+ more_set_headers 'Access-Control-Max-Age' 1728000;
+
+ # default to /index.html if file not found
+ try_files $uri $uri/ /index.html;
+ '';
+ };
+ };
+}
diff --git a/host/Rory-ovh/services/nginx/rory.gay/jitsi.nix b/host/Rory-ovh/services/nginx/rory.gay/jitsi.nix
new file mode 100755
index 0000000..9469087
--- /dev/null
+++ b/host/Rory-ovh/services/nginx/rory.gay/jitsi.nix
@@ -0,0 +1,51 @@
+{
+ config,
+ pkgs,
+ lib,
+ ...
+}:
+
+let
+ overrideJs =
+ filePath: varName: newContent: appendExtra:
+ let
+ oldContent = builtins.readFile filePath;
+ regex = "var ${varName} = {[^}]*};";
+ newJs = builtins.replaceStrings [ regex ] [ "var ${varName} = ${newContent};" ] oldContent;
+ in
+ builtins.writeFile filePath newJs;
+
+ cfg = config.services.jitsi-meet;
+in
+{
+ enableACME = true;
+ addSSL = true;
+ extraConfig = ''
+ ssi on;
+ '';
+ locations."@root_path".extraConfig = ''
+ rewrite ^/(.*)$ / break;
+ '';
+ locations."~ ^/([^/\\?&:'\"]+)$".tryFiles = "$uri @root_path";
+ locations."^~ /xmpp-websocket" = {
+ priority = 100;
+ proxyPass = "http://localhost:5280/xmpp-websocket";
+ proxyWebsockets = true;
+ };
+ locations."=/http-bind" = {
+ proxyPass = "http://localhost:5280/http-bind";
+ extraConfig = ''
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header Host $host;
+ '';
+ };
+ locations."=/external_api.js" = lib.mkDefault {
+ alias = "${pkgs.jitsi-meet}/libs/external_api.min.js";
+ };
+ locations."=/config.js" = lib.mkDefault {
+ alias = overrideJs "${pkgs.jitsi-meet}/config.js" "config" (lib.recursiveUpdate defaultCfg cfg.config) cfg.extraConfig;
+ };
+ locations."=/interface_config.js" = lib.mkDefault {
+ alias = overrideJs "${pkgs.jitsi-meet}/interface_config.js" "interfaceConfig" cfg.interfaceConfig "";
+ };
+}
diff --git a/host/Rory-ovh/services/nginx/rory.gay/libmatrix-fed-test.nix b/host/Rory-ovh/services/nginx/rory.gay/libmatrix-fed-test.nix
new file mode 100755
index 0000000..c2909d6
--- /dev/null
+++ b/host/Rory-ovh/services/nginx/rory.gay/libmatrix-fed-test.nix
@@ -0,0 +1,26 @@
+{ config }:
+{
+ enableACME = !config.virtualisation.isVmVariant;
+ addSSL = !config.virtualisation.isVmVariant;
+ locations."/" = {
+ #proxyPass = "http://127.0.0.1:9001";
+ proxyPass = "http://localhost:6500";
+ extraConfig = ''
+ if ($request_method = 'OPTIONS') {
+ more_set_headers 'Access-Control-Allow-Origin: *';
+ more_set_headers 'Access-Control-Allow-Methods: *';
+ #
+ # Custom headers and headers various browsers *should* be OK with but aren't
+ #
+ more_set_headers 'Access-Control-Allow-Headers: *, Authorization';
+ #
+ # Tell client that this pre-flight info is valid for 20 days
+ #
+ more_set_headers 'Access-Control-Max-Age: 1728000';
+ more_set_headers 'Content-Type: text/plain; charset=utf-8';
+ more_set_headers 'Content-Length: 0';
+ return 204;
+ }
+ '';
+ };
+}
diff --git a/host/Rory-ovh/services/nginx/rory.gay/matrix-bak.nix b/host/Rory-ovh/services/nginx/rory.gay/matrix-bak.nix
new file mode 100755
index 0000000..1af3669
--- /dev/null
+++ b/host/Rory-ovh/services/nginx/rory.gay/matrix-bak.nix
@@ -0,0 +1,26 @@
+{ config }:
+{
+ enableACME = !config.virtualisation.isVmVariant;
+ addSSL = !config.virtualisation.isVmVariant;
+ locations."/_matrix" = {
+ proxyPass = "http://192.168.1.5:8008";
+ extraConfig = ''
+ if ($request_method = 'OPTIONS') {
+ more_set_headers 'Access-Control-Allow-Origin: *';
+ more_set_headers 'Access-Control-Allow-Methods: *';
+ #
+ # Custom headers and headers various browsers *should* be OK with but aren't
+ #
+ more_set_headers 'Access-Control-Allow-Headers: *';
+ #
+ # Tell client that this pre-flight info is valid for 20 days
+ #
+ more_set_headers 'Access-Control-Max-Age: 1728000';
+ more_set_headers 'Content-Type: text/plain; charset=utf-8';
+ more_set_headers 'Content-Length: 0';
+ return 204;
+ }
+ '';
+ };
+ locations."/_synapse/client".proxyPass = "http://192.168.1.5:8008";
+}
diff --git a/host/Rory-ovh/services/nginx/rory.gay/matrix.nix b/host/Rory-ovh/services/nginx/rory.gay/matrix.nix
new file mode 100755
index 0000000..45a507f
--- /dev/null
+++ b/host/Rory-ovh/services/nginx/rory.gay/matrix.nix
@@ -0,0 +1,72 @@
+{ config }:
+{
+ enableACME = !config.virtualisation.isVmVariant;
+ addSSL = !config.virtualisation.isVmVariant;
+ locations."/" = {
+ #proxyPass = "http://127.0.0.1:9001";
+ proxyPass = "http://localhost:8008";
+ extraConfig = ''
+ if ($request_method = 'OPTIONS') {
+ more_set_headers 'Access-Control-Allow-Origin: *';
+ more_set_headers 'Access-Control-Allow-Methods: *';
+ #
+ # Custom headers and headers various browsers *should* be OK with but aren't
+ #
+ more_set_headers 'Access-Control-Allow-Headers: *, Authorization';
+ #
+ # Tell client that this pre-flight info is valid for 20 days
+ #
+ more_set_headers 'Access-Control-Max-Age: 1728000';
+ more_set_headers 'Content-Type: text/plain; charset=utf-8';
+ more_set_headers 'Content-Length: 0';
+ return 204;
+ }
+ '';
+ };
+
+ locations."= /.well-known/matrix/server".extraConfig = ''
+ more_set_headers 'Content-Type application/json';
+ more_set_headers 'Access-Control-Allow-Origin *';
+ return 200 '${builtins.toJSON { "m.server" = "matrix.rory.gay:443"; }}';
+ '';
+ locations."= /.well-known/matrix/client".extraConfig = ''
+ more_set_headers 'Content-Type application/json';
+ more_set_headers 'Access-Control-Allow-Origin *';
+ return 200 '${
+ builtins.toJSON {
+ "m.homeserver".base_url = "https://matrix.rory.gay";
+ "org.matrix.msc3575.proxy".url = "https://matrix.rory.gay";
+ }
+ }';
+ '';
+ locations."= /.well-known/matrix/support".extraConfig = ''
+ more_set_headers 'Content-Type application/json';
+ more_set_headers 'Access-Control-Allow-Origin *';
+ return 200 '${
+ builtins.toJSON {
+ admins = [
+ {
+ matrix_id = "@emma:rory.gay";
+ role = "admin";
+ }
+ {
+ matrix_id = "@alicia:rory.gay";
+ role = "admin";
+ }
+ {
+ matrix_id = "@root:rory.gay";
+ role = "admin";
+ }
+ {
+ matrix_id = "@rory:rory.gay";
+ role = "admin";
+ }
+ ];
+ }
+ }';
+ '';
+
+ locations."~ ^/(client/|_matrix/client/unstable/org.matrix.msc3575/sync)" = {
+ proxyPass = "http://localhost:8100";
+ };
+}
diff --git a/host/Rory-ovh/services/nginx/rory.gay/matrixunittests.nix b/host/Rory-ovh/services/nginx/rory.gay/matrixunittests.nix
new file mode 100755
index 0000000..f23f0dd
--- /dev/null
+++ b/host/Rory-ovh/services/nginx/rory.gay/matrixunittests.nix
@@ -0,0 +1,16 @@
+{ config }:
+{
+ enableACME = !config.virtualisation.isVmVariant;
+ addSSL = !config.virtualisation.isVmVariant;
+ http3 = !config.virtualisation.isVmVariant;
+ http3_hq = !config.virtualisation.isVmVariant;
+ kTLS = !config.virtualisation.isVmVariant;
+ extraConfig = ''
+ brotli off;
+ '';
+ locations = {
+ "/" = {
+ proxyPass = "http://192.168.100.13:80";
+ };
+ };
+}
diff --git a/host/Rory-ovh/services/nginx/rory.gay/mru.nix b/host/Rory-ovh/services/nginx/rory.gay/mru.nix
new file mode 100755
index 0000000..6e685de
--- /dev/null
+++ b/host/Rory-ovh/services/nginx/rory.gay/mru.nix
@@ -0,0 +1,30 @@
+{ config }:
+{
+ enableACME = !config.virtualisation.isVmVariant;
+ addSSL = !config.virtualisation.isVmVariant;
+# quic = true;
+ http3 = !config.virtualisation.isVmVariant;
+ http3_hq = !config.virtualisation.isVmVariant;
+ kTLS = !config.virtualisation.isVmVariant;
+ root = "/data/nginx/html_mru";
+# reuseport = true;
+ extraConfig = ''
+ brotli off;
+ brotli_static off;
+ '';
+ locations = {
+ "/" = {
+ index = "index.html";
+ extraConfig = ''
+ more_set_headers 'Access-Control-Allow-Origin: *';
+ more_set_headers 'Access-Control-Allow-Methods: *';
+ more_set_headers 'Access-Control-Allow-Headers: *';
+ more_set_headers 'Access-Control-Expose-Headers: *';
+ more_set_headers 'Access-Control-Max-Age' 1728000;
+
+ # default to /index.html if file not found
+ try_files $uri $uri/ /index.html;
+ '';
+ };
+ };
+}
diff --git a/host/Rory-ovh/services/nginx/rory.gay/pcpoc.nix b/host/Rory-ovh/services/nginx/rory.gay/pcpoc.nix
new file mode 100755
index 0000000..b62c5fe
--- /dev/null
+++ b/host/Rory-ovh/services/nginx/rory.gay/pcpoc.nix
@@ -0,0 +1,15 @@
+{
+ enableACME = true;
+ addSSL = true;
+ http3 = true;
+ http3_hq = true;
+ kTLS = true;
+ extraConfig = ''
+ brotli off;
+ '';
+ locations = {
+ "/" = {
+ proxyPass = "http://192.168.100.11:80";
+ };
+ };
+}
diff --git a/host/Rory-ovh/services/nginx/rory.gay/root.nix b/host/Rory-ovh/services/nginx/rory.gay/root.nix
new file mode 100755
index 0000000..a7720ec
--- /dev/null
+++ b/host/Rory-ovh/services/nginx/rory.gay/root.nix
@@ -0,0 +1,49 @@
+{ config }:
+{
+ enableACME = !config.virtualisation.isVmVariant;
+ addSSL = !config.virtualisation.isVmVariant;
+ root = "/data/nginx/html_rory_gay";
+ extraConfig = ''autoindex on;'';
+
+ locations."= /.well-known/matrix/server".extraConfig = ''
+ more_set_headers 'Content-Type application/json';
+ more_set_headers 'Access-Control-Allow-Origin *';
+ return 200 '${builtins.toJSON { "m.server" = "matrix.rory.gay:443"; }}';
+ '';
+ locations."= /.well-known/matrix/client".extraConfig = ''
+ more_set_headers 'Content-Type application/json';
+ more_set_headers 'Access-Control-Allow-Origin *';
+ return 200 '${
+ builtins.toJSON {
+ "m.homeserver".base_url = "https://matrix.rory.gay";
+ "org.matrix.msc3575.proxy".url = "https://matrix.rory.gay";
+ }
+ }';
+ '';
+ locations."= /.well-known/matrix/support".extraConfig = ''
+ more_set_headers 'Content-Type application/json';
+ more_set_headers 'Access-Control-Allow-Origin *';
+ return 200 '${
+ builtins.toJSON {
+ admins = [
+ {
+ matrix_id = "@emma:rory.gay";
+ role = "admin";
+ }
+ {
+ matrix_id = "@alicia:rory.gay";
+ role = "admin";
+ }
+ {
+ matrix_id = "@root:rory.gay";
+ role = "admin";
+ }
+ {
+ matrix_id = "@rory:rory.gay";
+ role = "admin";
+ }
+ ];
+ }
+ }';
+ '';
+}
diff --git a/host/Rory-ovh/services/nginx/rory.gay/safensound.nix b/host/Rory-ovh/services/nginx/rory.gay/safensound.nix
new file mode 100755
index 0000000..9208129
--- /dev/null
+++ b/host/Rory-ovh/services/nginx/rory.gay/safensound.nix
@@ -0,0 +1,30 @@
+{ config }:
+{
+ enableACME = !config.virtualisation.isVmVariant;
+ addSSL = !config.virtualisation.isVmVariant;
+# quic = true;
+ http3 = !config.virtualisation.isVmVariant;
+ http3_hq = !config.virtualisation.isVmVariant;
+ kTLS = !config.virtualisation.isVmVariant;
+ root = "/data/nginx/html_safensound";
+# reuseport = true;
+ extraConfig = ''
+ brotli off;
+ brotli_static off;
+ '';
+ locations = {
+ "/" = {
+ index = "index.html";
+ extraConfig = ''
+ more_set_headers 'Access-Control-Allow-Origin: *';
+ more_set_headers 'Access-Control-Allow-Methods: *';
+ more_set_headers 'Access-Control-Allow-Headers: *';
+ more_set_headers 'Access-Control-Expose-Headers: *';
+ more_set_headers 'Access-Control-Max-Age' 1728000;
+
+ # default to /index.html if file not found
+ try_files $uri $uri/ /index.html;
+ '';
+ };
+ };
+}
diff --git a/host/Rory-ovh/services/nginx/rory.gay/stream.nix b/host/Rory-ovh/services/nginx/rory.gay/stream.nix
new file mode 100755
index 0000000..caed22f
--- /dev/null
+++ b/host/Rory-ovh/services/nginx/rory.gay/stream.nix
@@ -0,0 +1,34 @@
+{ config }:
+{
+ enableACME = !config.virtualisation.isVmVariant;
+ addSSL = !config.virtualisation.isVmVariant;
+ locations = {
+ "/" = {
+ proxyPass = "http://localhost:1934";
+ proxyWebsockets = true;
+ recommendedProxySettings = true;
+ extraConfig = ''
+ proxy_ssl_verify off;
+# proxy_set_header Host youthapp.inuits.dev;
+ proxy_ssl_server_name on;
+
+ more_set_headers 'Access-Control-Allow-Origin: *';
+ more_set_headers 'Access-Control-Allow-Methods: *';
+ #
+ # Custom headers and headers various browsers *should* be OK with but aren't
+ #
+ more_set_headers 'Access-Control-Allow-Headers: *, Authorization';
+ #
+ # Tell client that this pre-flight info is valid for 20 days
+ #
+ more_set_headers 'Access-Control-Max-Age: 1728000';
+
+ if ($request_method = 'OPTIONS') {
+ more_set_headers 'Content-Type: text/plain; charset=utf-8';
+ more_set_headers 'Content-Length: 0';
+ return 204;
+ }
+ '';
+ };
+ };
+}
diff --git a/host/Rory-ovh/services/nginx/rory.gay/wad-api.nix b/host/Rory-ovh/services/nginx/rory.gay/wad-api.nix
new file mode 100755
index 0000000..ac07547
--- /dev/null
+++ b/host/Rory-ovh/services/nginx/rory.gay/wad-api.nix
@@ -0,0 +1,32 @@
+{
+ enableACME = !config.virtualisation.isVmVariant;
+ addSSL = true;
+ locations = {
+ "/" = {
+ proxyPass = "https://youthapp.inuits.dev";
+ recommendedProxySettings = false;
+ extraConfig = ''
+ proxy_ssl_verify off;
+ proxy_set_header Host youthapp.inuits.dev;
+ proxy_ssl_server_name on;
+
+ more_set_headers 'Access-Control-Allow-Origin: *';
+ more_set_headers 'Access-Control-Allow-Methods: *';
+ #
+ # Custom headers and headers various browsers *should* be OK with but aren't
+ #
+ more_set_headers 'Access-Control-Allow-Headers: *, Authorization';
+ #
+ # Tell client that this pre-flight info is valid for 20 days
+ #
+ more_set_headers 'Access-Control-Max-Age: 1728000';
+
+ if ($request_method = 'OPTIONS') {
+ more_set_headers 'Content-Type: text/plain; charset=utf-8';
+ more_set_headers 'Content-Length: 0';
+ return 204;
+ }
+ '';
+ };
+ };
+}
diff --git a/host/Rory-ovh/services/nginx/thearcanebrony.net/awooradio.nix b/host/Rory-ovh/services/nginx/thearcanebrony.net/awooradio.nix
new file mode 100755
index 0000000..c0ca8b0
--- /dev/null
+++ b/host/Rory-ovh/services/nginx/thearcanebrony.net/awooradio.nix
@@ -0,0 +1,13 @@
+{ config }:
+{
+ enableACME = !config.virtualisation.isVmVariant;
+ addSSL = true;
+ locations = {
+ "/" = {
+ extraConfig = ''
+ rewrite ^/api/(.*) /$1 break;
+ return 200 $request_uri;'';
+ proxyPass = "http://localhost:4998";
+ };
+ };
+}
diff --git a/host/Rory-ovh/services/nginx/thearcanebrony.net/root.nix b/host/Rory-ovh/services/nginx/thearcanebrony.net/root.nix
new file mode 100755
index 0000000..59cba43
--- /dev/null
+++ b/host/Rory-ovh/services/nginx/thearcanebrony.net/root.nix
@@ -0,0 +1,41 @@
+{ config }:
+{
+ enableACME = !config.virtualisation.isVmVariant;
+ addSSL = true;
+ root = "/data/nginx/html_thearcanebrony";
+ extraConfig = ''autoindex on;'';
+ locations = {
+ "/" = {
+ #index = "index.html";
+ };
+ "/destroy" = {
+ return = "301 https://gitlab.com/KinoshitaProductions/SecureDestroyer/-/raw/master/run";
+ };
+ "= /.well-known/matrix/support".extraConfig = ''
+ more_set_headers 'Content-Type application/json';
+ more_set_headers 'Access-Control-Allow-Origin *';
+ return 200 '${
+ builtins.toJSON {
+ admins = [
+ {
+ matrix_id = "@emma:rory.gay";
+ role = "admin";
+ }
+ {
+ matrix_id = "@alicia:rory.gay";
+ role = "admin";
+ }
+ {
+ matrix_id = "@root:rory.gay";
+ role = "admin";
+ }
+ {
+ matrix_id = "@rory:rory.gay";
+ role = "admin";
+ }
+ ];
+ }
+ }';
+ '';
+ };
+}
diff --git a/host/Rory-ovh/services/nginx/thearcanebrony.net/search.nix b/host/Rory-ovh/services/nginx/thearcanebrony.net/search.nix
new file mode 100755
index 0000000..cfb4e1c
--- /dev/null
+++ b/host/Rory-ovh/services/nginx/thearcanebrony.net/search.nix
@@ -0,0 +1,10 @@
+{ config }:
+{
+ enableACME = !config.virtualisation.isVmVariant;
+ addSSL = true;
+ locations = {
+ "/" = {
+ extraConfig = ''rewrite ^ https://thearcanebrony.net/unavailable.html break;'';
+ };
+ };
+}
diff --git a/host/Rory-ovh/services/nginx/thearcanebrony.net/sentry.nix b/host/Rory-ovh/services/nginx/thearcanebrony.net/sentry.nix
new file mode 100755
index 0000000..8cd0826
--- /dev/null
+++ b/host/Rory-ovh/services/nginx/thearcanebrony.net/sentry.nix
@@ -0,0 +1,10 @@
+{ config }:
+{
+ enableACME = !config.virtualisation.isVmVariant;
+ addSSL = true;
+ locations = {
+ "/" = {
+ proxyPass = "http://192.168.1.4:9000";
+ };
+ };
+}
diff --git a/host/Rory-ovh/services/postgres.nix b/host/Rory-ovh/services/postgres.nix
new file mode 100755
index 0000000..10d1cb7
--- /dev/null
+++ b/host/Rory-ovh/services/postgres.nix
@@ -0,0 +1,99 @@
+{ config, pkgs, ... }:
+
+{
+ systemd.tmpfiles.rules = [ "d /data/dedicated/postgres 0750 postgres postgres" ];
+
+ services.postgresql = {
+ enable = true;
+ package = pkgs.postgresql_17_jit;
+ enableTCPIP = true;
+ authentication = pkgs.lib.mkOverride 10 ''
+ # TYPE, DATABASE, USER, ADDRESS, METHOD
+ local all all trust
+ host all all 127.0.0.1/32 trust
+ host all all ::1/128 trust
+ host discordbots discordbots 192.168.1.2/32 trust
+ host matrix-synapse-rory-gay matrix-synapse-rory-gay 192.168.1.5/32 trust
+ host all all 0.0.0.0/0 md5
+ '';
+ # initialScript = pkgs.writeText "backend-initScript" ''
+ # CREATE ROLE nixcloud WITH LOGIN PASSWORD 'nixcloud' CREATEDB;
+ # CREATE DATABASE nixcloud;
+ # GRANT ALL PRIVILEGES ON DATABASE nixcloud TO nixcloud;
+ # '';
+ dataDir = "/data/dedicated/postgres";
+ settings = {
+ # https://pgconfigurator.cybertec.at/
+ max_connections = 2500;
+ superuser_reserved_connections = 3;
+
+ shared_buffers = if config.virtualisation.isVmVariant then "128MB" else "64GB";
+ work_mem = if config.virtualisation.isVmVariant then "64MB" else "32GB";
+ maintenance_work_mem = if config.virtualisation.isVmVariant then "512MB" else "8GB";
+ huge_pages = "try";
+ effective_cache_size = if config.virtualisation.isVmVariant then "1GB" else "64GB"; # was 22
+ effective_io_concurrency = 100;
+ random_page_cost = 1.1;
+
+ # can use this to view stats: SELECT query, total_time, calls, rows FROM pg_stat_statements ORDER BY total_time DESC LIMIT 10;
+ shared_preload_libraries = "pg_stat_statements";
+ track_io_timing = "on";
+ track_functions = "pl";
+ "pg_stat_statements.max" = "10000"; # additional
+ "pg_stat_statements.track" = "all"; # additional
+
+ wal_level = "replica";
+ max_wal_senders = 0;
+ synchronous_commit = "on"; # was ond3
+
+ checkpoint_timeout = "15min";
+ checkpoint_completion_target = "0.9";
+ max_wal_size = "2GB";
+ min_wal_size = "1GB";
+
+ wal_compression = "off";
+ wal_buffers = "-1";
+ wal_writer_delay = "500ms"; # was 100
+ wal_writer_flush_after = "32MB"; # was 1
+ #checkpoint_segments = "64"; # additional
+ default_statistics_target = "250"; # additional
+
+ bgwriter_delay = "200ms";
+ bgwriter_lru_maxpages = "100";
+ bgwriter_lru_multiplier = "2.0";
+ bgwriter_flush_after = "0";
+
+ max_worker_processes = "64"; # was 14
+ max_parallel_workers_per_gather = "32"; # was 7
+ max_parallel_maintenance_workers = "32"; # was 7
+ max_parallel_workers = "64"; # was 14
+ parallel_leader_participation = "on";
+
+ enable_partitionwise_join = "on";
+ enable_partitionwise_aggregate = "on";
+ jit = "on";
+ max_slot_wal_keep_size = "1GB";
+ track_wal_io_timing = "on";
+ maintenance_io_concurrency = "4";
+ wal_recycle = "on";
+
+ };
+ };
+
+ # services.prometheus.exporters.postgres = {
+ # enable = true;
+ # port = 9187;
+ # extraFlags = [
+ # "--collector.database_wraparound"
+ # "--collector.long_running_transactions"
+ # "--collector.postmaster"
+ # "--collector.process_idle"
+ # "--collector.stat_activity_autovacuum"
+ # "--collector.stat_statements"
+ # #"--collector.stat_wal_receiver" #we dont have WAL receivers
+ # "--collector.statio_user_indexes"
+ # "--collector.xlog_location"
+ # ];
+ # };
+
+}
diff --git a/host/Rory-ovh/services/prometheus.nix b/host/Rory-ovh/services/prometheus.nix
new file mode 100644
index 0000000..9409529
--- /dev/null
+++ b/host/Rory-ovh/services/prometheus.nix
@@ -0,0 +1,8 @@
+{ ... }:
+
+{
+ services.prometheus = {
+ enable = true;
+ port = 9001;
+ };
+}
diff --git a/host/Rory-ovh/services/safensound.nix b/host/Rory-ovh/services/safensound.nix
new file mode 100644
index 0000000..69f301a
--- /dev/null
+++ b/host/Rory-ovh/services/safensound.nix
@@ -0,0 +1,28 @@
+{
+ config,
+ pkgs,
+ lib,
+ ...
+}:
+
+{
+ services.mongodb = {
+ enable = true;
+ package = pkgs.mongodb-ce;
+ enableAuth = true;
+ initialRootPasswordFile = "/etc/mongo-pass";
+ #bind_ip = "/run/mongodb.sock";
+ extraConfig = ''
+ net.unixDomainSocket.filePermissions: 0777
+ '';
+ };
+
+ services.safensound = {
+ enable = true;
+ dbCredentialsPath = "/data/secrets/safensound-mongodb";
+ port = 7645;
+ logRequests = "-";
+ logQueries = true;
+ logAuth = true;
+ };
+}
diff --git a/host/Rory-ovh/services/wireguard/wireguard.nix b/host/Rory-ovh/services/wireguard/wireguard.nix
new file mode 100644
index 0000000..af69f66
--- /dev/null
+++ b/host/Rory-ovh/services/wireguard/wireguard.nix
@@ -0,0 +1,39 @@
+{ pkgs, ... }:
+{
+ networking.nat.internalInterfaces = [ "wg0" ];
+ networking.firewall = {
+ allowedUDPPorts = [ 51820 ];
+ };
+
+ systemd.network = {
+ enable = true;
+ netdevs = {
+ "50-wg0" = {
+ netdevConfig = {
+ Kind = "wireguard";
+ Name = "wg0";
+ MTUBytes = "1300";
+ };
+ wireguardConfig = {
+ PrivateKeyFile = "/data/secrets/wireguard-keys/private";
+ ListenPort = 51820;
+ RouteTable = "main"; # wg-quick creates routing entries automatically but we must use use this option in systemd.
+ };
+ wireguardPeers = [
+ {
+ PublicKey = "WLHEyWxEXRn/T0b9xk/8XJnuoCX0fXxWKHUjZ+AORGQ=";
+ AllowedIPs = [ "10.100.0.2" ];
+ }
+ ];
+ };
+ };
+ networks.wg0 = {
+ matchConfig.Name = "wg0";
+ address = [ "10.100.0.1/24" ];
+ networkConfig = {
+ IPMasquerade = "ipv4";
+ IPv4Forwarding = true;
+ };
+ };
+ };
+}
|