Compare commits
6 Commits
3b23aea374
...
dfefec5baa
| Author | SHA1 | Date | |
|---|---|---|---|
|
dfefec5baa
|
|||
|
41b574a3c7
|
|||
|
f94c04a9c4
|
|||
|
a5f3af5ff3
|
|||
|
5ced648bd6
|
|||
|
fd3df23a76
|
@@ -98,6 +98,7 @@ Each service file in `services/` follows this structure:
|
|||||||
- **git-crypt**: `secrets/` directory and `usb-secrets/usb-secrets-key*` are encrypted (see `.gitattributes`)
|
- **git-crypt**: `secrets/` directory and `usb-secrets/usb-secrets-key*` are encrypted (see `.gitattributes`)
|
||||||
- **agenix**: secrets declared in `modules/age-secrets.nix`, decrypted at runtime to `/run/agenix/`
|
- **agenix**: secrets declared in `modules/age-secrets.nix`, decrypted at runtime to `/run/agenix/`
|
||||||
- **Identity**: USB drive at `/mnt/usb-secrets/usb-secrets-key`
|
- **Identity**: USB drive at `/mnt/usb-secrets/usb-secrets-key`
|
||||||
|
- **Encrypting new secrets**: The agenix encryption key is in `usb-secrets/usb-secrets-key` (SSH private key, git-crypt encrypted). To create a new secret: derive the age public key with `ssh-keygen -y -f usb-secrets/usb-secrets-key | ssh-to-age`, then encrypt with `age -r <public-key> -o secrets/<name>.age`.
|
||||||
- Never read or commit plaintext secrets. Never log secret values.
|
- Never read or commit plaintext secrets. Never log secret values.
|
||||||
|
|
||||||
### Important Patterns
|
### Important Patterns
|
||||||
|
|||||||
@@ -47,6 +47,7 @@
|
|||||||
./services/ups.nix
|
./services/ups.nix
|
||||||
|
|
||||||
./services/bitwarden.nix
|
./services/bitwarden.nix
|
||||||
|
./services/firefox-syncserver.nix
|
||||||
|
|
||||||
./services/matrix.nix
|
./services/matrix.nix
|
||||||
./services/coturn.nix
|
./services/coturn.nix
|
||||||
@@ -284,7 +285,7 @@
|
|||||||
openFirewall = true;
|
openFirewall = true;
|
||||||
welcometext = "meow meow meow meow meow :3 xd";
|
welcometext = "meow meow meow meow meow :3 xd";
|
||||||
password = builtins.readFile ./secrets/murmur_password;
|
password = builtins.readFile ./secrets/murmur_password;
|
||||||
port = service_configs.ports.murmur;
|
port = service_configs.ports.public.murmur.port;
|
||||||
};
|
};
|
||||||
|
|
||||||
# services.botamusique = {
|
# services.botamusique = {
|
||||||
|
|||||||
70
flake.nix
70
flake.nix
@@ -105,7 +105,19 @@
|
|||||||
|
|
||||||
service_configs = import ./service-configs.nix;
|
service_configs = import ./service-configs.nix;
|
||||||
|
|
||||||
pkgs = import nixpkgs {
|
# Bootstrap pkgs used only to apply patches to nixpkgs source.
|
||||||
|
bootstrapPkgs = import nixpkgs { inherit system; };
|
||||||
|
|
||||||
|
# Patch nixpkgs to add PostgreSQL backend support for firefox-syncserver.
|
||||||
|
patchedNixpkgsSrc = bootstrapPkgs.applyPatches {
|
||||||
|
name = "nixpkgs-patched";
|
||||||
|
src = nixpkgs;
|
||||||
|
patches = [
|
||||||
|
./patches/0001-firefox-syncserver-add-postgresql-backend-support.patch
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
pkgs = import patchedNixpkgsSrc {
|
||||||
inherit system;
|
inherit system;
|
||||||
targetPlatform = system;
|
targetPlatform = system;
|
||||||
buildPlatform = builtins.currentSystem;
|
buildPlatform = builtins.currentSystem;
|
||||||
@@ -130,19 +142,46 @@
|
|||||||
;
|
;
|
||||||
};
|
};
|
||||||
modules = [
|
modules = [
|
||||||
# SAFETY! make sure no ports collide
|
# SAFETY! port sanity checks
|
||||||
(
|
(
|
||||||
{ lib, ... }:
|
{ config, lib, ... }:
|
||||||
|
let
|
||||||
|
publicPorts = lib.attrValues service_configs.ports.public;
|
||||||
|
privatePorts = lib.attrValues service_configs.ports.private;
|
||||||
|
allPortNumbers = map (p: p.port) (publicPorts ++ privatePorts);
|
||||||
|
uniquePortNumbers = lib.unique allPortNumbers;
|
||||||
|
|
||||||
|
# Which public ports must be in each firewall list
|
||||||
|
publicTcp = map (p: p.port) (lib.filter (p: p.proto == "tcp" || p.proto == "both") publicPorts);
|
||||||
|
publicUdp = map (p: p.port) (lib.filter (p: p.proto == "udp" || p.proto == "both") publicPorts);
|
||||||
|
|
||||||
|
privatePortNumbers = map (p: p.port) privatePorts;
|
||||||
|
|
||||||
|
fwTcp = config.networking.firewall.allowedTCPPorts;
|
||||||
|
fwUdp = config.networking.firewall.allowedUDPPorts;
|
||||||
|
|
||||||
|
missingTcp = lib.filter (p: !(builtins.elem p fwTcp)) publicTcp;
|
||||||
|
missingUdp = lib.filter (p: !(builtins.elem p fwUdp)) publicUdp;
|
||||||
|
leakedTcp = lib.filter (p: builtins.elem p fwTcp) privatePortNumbers;
|
||||||
|
leakedUdp = lib.filter (p: builtins.elem p fwUdp) privatePortNumbers;
|
||||||
|
in
|
||||||
{
|
{
|
||||||
config.assertions = [
|
config.assertions = [
|
||||||
{
|
{
|
||||||
assertion =
|
assertion = (lib.length allPortNumbers) == (lib.length uniquePortNumbers);
|
||||||
let
|
message = "Duplicate port numbers detected in ports.public / ports.private";
|
||||||
ports = lib.attrValues service_configs.ports;
|
}
|
||||||
uniquePorts = lib.unique ports;
|
{
|
||||||
in
|
assertion = missingTcp == [ ];
|
||||||
(lib.length ports) == (lib.length uniquePorts);
|
message = "Public ports missing from allowedTCPPorts: ${builtins.toString missingTcp}";
|
||||||
message = "Duplicate ports detected in 'ports' configuration";
|
}
|
||||||
|
{
|
||||||
|
assertion = missingUdp == [ ];
|
||||||
|
message = "Public ports missing from allowedUDPPorts: ${builtins.toString missingUdp}";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
assertion = leakedTcp == [ ] && leakedUdp == [ ];
|
||||||
|
message = "Private ports leaked into firewall allow-lists — TCP: ${builtins.toString leakedTcp}, UDP: ${builtins.toString leakedUdp}";
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -157,10 +196,21 @@
|
|||||||
./disk-config.nix
|
./disk-config.nix
|
||||||
./configuration.nix
|
./configuration.nix
|
||||||
|
|
||||||
|
# Replace upstream firefox-syncserver module + package with patched
|
||||||
|
# versions that add PostgreSQL backend support.
|
||||||
{
|
{
|
||||||
|
disabledModules = [ "services/networking/firefox-syncserver.nix" ];
|
||||||
|
imports = [
|
||||||
|
"${patchedNixpkgsSrc}/nixos/modules/services/networking/firefox-syncserver.nix"
|
||||||
|
];
|
||||||
nixpkgs.overlays = [
|
nixpkgs.overlays = [
|
||||||
nix-minecraft.overlay
|
nix-minecraft.overlay
|
||||||
(import ./modules/overlays.nix)
|
(import ./modules/overlays.nix)
|
||||||
|
(_final: prev: {
|
||||||
|
syncstorage-rs =
|
||||||
|
prev.callPackage "${patchedNixpkgsSrc}/pkgs/by-name/sy/syncstorage-rs/package.nix"
|
||||||
|
{ };
|
||||||
|
})
|
||||||
];
|
];
|
||||||
nixpkgs.config.allowUnfreePredicate =
|
nixpkgs.config.allowUnfreePredicate =
|
||||||
pkg:
|
pkg:
|
||||||
|
|||||||
@@ -82,5 +82,11 @@
|
|||||||
owner = "root";
|
owner = "root";
|
||||||
group = "root";
|
group = "root";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Firefox Sync server secrets (SYNC_MASTER_SECRET)
|
||||||
|
firefox-syncserver-env = {
|
||||||
|
file = ../secrets/firefox-syncserver-env.age;
|
||||||
|
mode = "0400";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,379 @@
|
|||||||
|
From ab57092a60123e361cf0de1c1a314a9888c45219 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Simon Gardling <titaniumtown@proton.me>
|
||||||
|
Date: Sat, 21 Mar 2026 09:24:39 -0400
|
||||||
|
Subject: [PATCH] temp
|
||||||
|
|
||||||
|
---
|
||||||
|
.../services/networking/firefox-syncserver.md | 23 +++
|
||||||
|
.../networking/firefox-syncserver.nix | 140 ++++++++++++++----
|
||||||
|
pkgs/by-name/sy/syncstorage-rs/package.nix | 49 ++++--
|
||||||
|
3 files changed, 174 insertions(+), 38 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/nixos/modules/services/networking/firefox-syncserver.md b/nixos/modules/services/networking/firefox-syncserver.md
|
||||||
|
index 991e97f799d6..3bc45cfa5640 100644
|
||||||
|
--- a/nixos/modules/services/networking/firefox-syncserver.md
|
||||||
|
+++ b/nixos/modules/services/networking/firefox-syncserver.md
|
||||||
|
@@ -32,6 +32,29 @@ This configuration should never be used in production. It is not encrypted and
|
||||||
|
stores its secrets in a world-readable location.
|
||||||
|
:::
|
||||||
|
|
||||||
|
+## Database backends {#module-services-firefox-syncserver-database}
|
||||||
|
+
|
||||||
|
+The sync server supports MySQL/MariaDB (the default) and PostgreSQL as database
|
||||||
|
+backends. Set `database.type` to choose the backend:
|
||||||
|
+
|
||||||
|
+```nix
|
||||||
|
+{
|
||||||
|
+ services.firefox-syncserver = {
|
||||||
|
+ enable = true;
|
||||||
|
+ database.type = "postgresql";
|
||||||
|
+ secrets = "/run/secrets/firefox-syncserver";
|
||||||
|
+ singleNode = {
|
||||||
|
+ enable = true;
|
||||||
|
+ hostname = "localhost";
|
||||||
|
+ url = "http://localhost:5000";
|
||||||
|
+ };
|
||||||
|
+ };
|
||||||
|
+}
|
||||||
|
+```
|
||||||
|
+
|
||||||
|
+When `database.createLocally` is `true` (the default), the module will
|
||||||
|
+automatically enable and configure the corresponding database service.
|
||||||
|
+
|
||||||
|
## More detailed setup {#module-services-firefox-syncserver-configuration}
|
||||||
|
|
||||||
|
The `firefox-syncserver` service provides a number of options to make setting up
|
||||||
|
diff --git a/nixos/modules/services/networking/firefox-syncserver.nix b/nixos/modules/services/networking/firefox-syncserver.nix
|
||||||
|
index 6a50e49fc096..70a56314e323 100644
|
||||||
|
--- a/nixos/modules/services/networking/firefox-syncserver.nix
|
||||||
|
+++ b/nixos/modules/services/networking/firefox-syncserver.nix
|
||||||
|
@@ -13,7 +13,21 @@ let
|
||||||
|
defaultUser = "firefox-syncserver";
|
||||||
|
|
||||||
|
dbIsLocal = cfg.database.host == "localhost";
|
||||||
|
- dbURL = "mysql://${cfg.database.user}@${cfg.database.host}/${cfg.database.name}${lib.optionalString dbIsLocal "?socket=/run/mysqld/mysqld.sock"}";
|
||||||
|
+ dbIsMySQL = cfg.database.type == "mysql";
|
||||||
|
+ dbIsPostgreSQL = cfg.database.type == "postgresql";
|
||||||
|
+
|
||||||
|
+ dbURL =
|
||||||
|
+ if dbIsMySQL then
|
||||||
|
+ "mysql://${cfg.database.user}@${cfg.database.host}/${cfg.database.name}${lib.optionalString dbIsLocal "?socket=/run/mysqld/mysqld.sock"}"
|
||||||
|
+ else
|
||||||
|
+ "postgres://${cfg.database.user}@${cfg.database.host}/${cfg.database.name}${lib.optionalString dbIsLocal "?host=/run/postgresql"}";
|
||||||
|
+
|
||||||
|
+ # postgresql.target waits for postgresql-setup.service (which runs
|
||||||
|
+ # ensureDatabases / ensureUsers) to complete, avoiding race conditions
|
||||||
|
+ # where the syncserver starts before its database and role exist.
|
||||||
|
+ dbService = if dbIsMySQL then "mysql.service" else "postgresql.target";
|
||||||
|
+
|
||||||
|
+ syncserver = cfg.package.override { dbBackend = cfg.database.type; };
|
||||||
|
|
||||||
|
format = pkgs.formats.toml { };
|
||||||
|
settings = {
|
||||||
|
@@ -22,7 +36,7 @@ let
|
||||||
|
database_url = dbURL;
|
||||||
|
};
|
||||||
|
tokenserver = {
|
||||||
|
- node_type = "mysql";
|
||||||
|
+ node_type = if dbIsMySQL then "mysql" else "postgres";
|
||||||
|
database_url = dbURL;
|
||||||
|
fxa_email_domain = "api.accounts.firefox.com";
|
||||||
|
fxa_oauth_server_url = "https://oauth.accounts.firefox.com/v1";
|
||||||
|
@@ -41,7 +55,8 @@ let
|
||||||
|
};
|
||||||
|
};
|
||||||
|
configFile = format.generate "syncstorage.toml" (lib.recursiveUpdate settings cfg.settings);
|
||||||
|
- setupScript = pkgs.writeShellScript "firefox-syncserver-setup" ''
|
||||||
|
+
|
||||||
|
+ mysqlSetupScript = pkgs.writeShellScript "firefox-syncserver-setup" ''
|
||||||
|
set -euo pipefail
|
||||||
|
shopt -s inherit_errexit
|
||||||
|
|
||||||
|
@@ -79,6 +94,47 @@ let
|
||||||
|
echo "Single-node setup failed"
|
||||||
|
exit 1
|
||||||
|
'';
|
||||||
|
+
|
||||||
|
+ postgresqlSetupScript = pkgs.writeShellScript "firefox-syncserver-setup" ''
|
||||||
|
+ set -euo pipefail
|
||||||
|
+ shopt -s inherit_errexit
|
||||||
|
+
|
||||||
|
+ schema_configured() {
|
||||||
|
+ psql -d ${cfg.database.name} -tAc "SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = 'services')" | grep -q t
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ update_config() {
|
||||||
|
+ psql -d ${cfg.database.name} <<'EOF'
|
||||||
|
+ BEGIN;
|
||||||
|
+
|
||||||
|
+ INSERT INTO services (id, service, pattern)
|
||||||
|
+ VALUES (1, 'sync-1.5', '{node}/1.5/{uid}')
|
||||||
|
+ ON CONFLICT (id) DO UPDATE SET service = 'sync-1.5', pattern = '{node}/1.5/{uid}';
|
||||||
|
+ INSERT INTO nodes (id, service, node, available, current_load,
|
||||||
|
+ capacity, downed, backoff)
|
||||||
|
+ VALUES (1, 1, '${cfg.singleNode.url}', ${toString cfg.singleNode.capacity},
|
||||||
|
+ 0, ${toString cfg.singleNode.capacity}, 0, 0)
|
||||||
|
+ ON CONFLICT (id) DO UPDATE SET node = '${cfg.singleNode.url}', capacity = ${toString cfg.singleNode.capacity};
|
||||||
|
+
|
||||||
|
+ COMMIT;
|
||||||
|
+ EOF
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ for (( try = 0; try < 60; try++ )); do
|
||||||
|
+ if ! schema_configured; then
|
||||||
|
+ sleep 2
|
||||||
|
+ else
|
||||||
|
+ update_config
|
||||||
|
+ exit 0
|
||||||
|
+ fi
|
||||||
|
+ done
|
||||||
|
+
|
||||||
|
+ echo "Single-node setup failed"
|
||||||
|
+ exit 1
|
||||||
|
+ '';
|
||||||
|
+
|
||||||
|
+ setupScript = if dbIsMySQL then mysqlSetupScript else postgresqlSetupScript;
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
@@ -88,25 +144,26 @@ in
|
||||||
|
the Firefox Sync storage service.
|
||||||
|
|
||||||
|
Out of the box this will not be very useful unless you also configure at least
|
||||||
|
- one service and one nodes by inserting them into the mysql database manually, e.g.
|
||||||
|
- by running
|
||||||
|
-
|
||||||
|
- ```
|
||||||
|
- INSERT INTO `services` (`id`, `service`, `pattern`) VALUES ('1', 'sync-1.5', '{node}/1.5/{uid}');
|
||||||
|
- INSERT INTO `nodes` (`id`, `service`, `node`, `available`, `current_load`,
|
||||||
|
- `capacity`, `downed`, `backoff`)
|
||||||
|
- VALUES ('1', '1', 'https://mydomain.tld', '1', '0', '10', '0', '0');
|
||||||
|
- ```
|
||||||
|
+ one service and one nodes by inserting them into the database manually, e.g.
|
||||||
|
+ by running the equivalent SQL for your database backend.
|
||||||
|
|
||||||
|
{option}`${opt.singleNode.enable}` does this automatically when enabled
|
||||||
|
'';
|
||||||
|
|
||||||
|
package = lib.mkPackageOption pkgs "syncstorage-rs" { };
|
||||||
|
|
||||||
|
+ database.type = lib.mkOption {
|
||||||
|
+ type = lib.types.enum [
|
||||||
|
+ "mysql"
|
||||||
|
+ "postgresql"
|
||||||
|
+ ];
|
||||||
|
+ default = "mysql";
|
||||||
|
+ description = ''
|
||||||
|
+ Which database backend to use for storage.
|
||||||
|
+ '';
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
database.name = lib.mkOption {
|
||||||
|
- # the mysql module does not allow `-quoting without resorting to shell
|
||||||
|
- # escaping, so we restrict db names for forward compaitiblity should this
|
||||||
|
- # behavior ever change.
|
||||||
|
type = lib.types.strMatching "[a-z_][a-z0-9_]*";
|
||||||
|
default = defaultDatabase;
|
||||||
|
description = ''
|
||||||
|
@@ -117,9 +174,15 @@ in
|
||||||
|
|
||||||
|
database.user = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
- default = defaultUser;
|
||||||
|
+ default = if dbIsPostgreSQL then defaultDatabase else defaultUser;
|
||||||
|
+ defaultText = lib.literalExpression ''
|
||||||
|
+ if database.type == "postgresql" then "${defaultDatabase}" else "${defaultUser}"
|
||||||
|
+ '';
|
||||||
|
description = ''
|
||||||
|
- Username for database connections.
|
||||||
|
+ Username for database connections. When using PostgreSQL with
|
||||||
|
+ `createLocally`, this defaults to the database name so that
|
||||||
|
+ `ensureDBOwnership` works (it requires user and database names
|
||||||
|
+ to match).
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -137,7 +200,8 @@ in
|
||||||
|
default = true;
|
||||||
|
description = ''
|
||||||
|
Whether to create database and user on the local machine if they do not exist.
|
||||||
|
- This includes enabling unix domain socket authentication for the configured user.
|
||||||
|
+ This includes enabling the configured database service and setting up
|
||||||
|
+ authentication for the configured user.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -237,7 +301,7 @@ in
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
- services.mysql = lib.mkIf cfg.database.createLocally {
|
||||||
|
+ services.mysql = lib.mkIf (cfg.database.createLocally && dbIsMySQL) {
|
||||||
|
enable = true;
|
||||||
|
ensureDatabases = [ cfg.database.name ];
|
||||||
|
ensureUsers = [
|
||||||
|
@@ -250,16 +314,27 @@ in
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
+ services.postgresql = lib.mkIf (cfg.database.createLocally && dbIsPostgreSQL) {
|
||||||
|
+ enable = true;
|
||||||
|
+ ensureDatabases = [ cfg.database.name ];
|
||||||
|
+ ensureUsers = [
|
||||||
|
+ {
|
||||||
|
+ name = cfg.database.user;
|
||||||
|
+ ensureDBOwnership = true;
|
||||||
|
+ }
|
||||||
|
+ ];
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
systemd.services.firefox-syncserver = {
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
- requires = lib.mkIf dbIsLocal [ "mysql.service" ];
|
||||||
|
- after = lib.mkIf dbIsLocal [ "mysql.service" ];
|
||||||
|
+ requires = lib.mkIf dbIsLocal [ dbService ];
|
||||||
|
+ after = lib.mkIf dbIsLocal [ dbService ];
|
||||||
|
restartTriggers = lib.optional cfg.singleNode.enable setupScript;
|
||||||
|
environment.RUST_LOG = cfg.logLevel;
|
||||||
|
serviceConfig = {
|
||||||
|
- User = defaultUser;
|
||||||
|
- Group = defaultUser;
|
||||||
|
- ExecStart = "${cfg.package}/bin/syncserver --config ${configFile}";
|
||||||
|
+ User = cfg.database.user;
|
||||||
|
+ Group = cfg.database.user;
|
||||||
|
+ ExecStart = "${syncserver}/bin/syncserver --config ${configFile}";
|
||||||
|
EnvironmentFile = lib.mkIf (cfg.secrets != null) "${cfg.secrets}";
|
||||||
|
|
||||||
|
# hardening
|
||||||
|
@@ -303,10 +378,19 @@ in
|
||||||
|
|
||||||
|
systemd.services.firefox-syncserver-setup = lib.mkIf cfg.singleNode.enable {
|
||||||
|
wantedBy = [ "firefox-syncserver.service" ];
|
||||||
|
- requires = [ "firefox-syncserver.service" ] ++ lib.optional dbIsLocal "mysql.service";
|
||||||
|
- after = [ "firefox-syncserver.service" ] ++ lib.optional dbIsLocal "mysql.service";
|
||||||
|
- path = [ config.services.mysql.package ];
|
||||||
|
- serviceConfig.ExecStart = [ "${setupScript}" ];
|
||||||
|
+ requires = [ "firefox-syncserver.service" ] ++ lib.optional dbIsLocal dbService;
|
||||||
|
+ after = [ "firefox-syncserver.service" ] ++ lib.optional dbIsLocal dbService;
|
||||||
|
+ path =
|
||||||
|
+ if dbIsMySQL then [ config.services.mysql.package ] else [ config.services.postgresql.package ];
|
||||||
|
+ serviceConfig = {
|
||||||
|
+ ExecStart = [ "${setupScript}" ];
|
||||||
|
+ }
|
||||||
|
+ // lib.optionalAttrs dbIsPostgreSQL {
|
||||||
|
+ # PostgreSQL peer authentication requires the system user to match the
|
||||||
|
+ # database user. Run as the superuser so we can access all databases.
|
||||||
|
+ User = "postgres";
|
||||||
|
+ Group = "postgres";
|
||||||
|
+ };
|
||||||
|
};
|
||||||
|
|
||||||
|
services.nginx.virtualHosts = lib.mkIf cfg.singleNode.enableNginx {
|
||||||
|
diff --git a/pkgs/by-name/sy/syncstorage-rs/package.nix b/pkgs/by-name/sy/syncstorage-rs/package.nix
|
||||||
|
index 39b2b53ab03c..944ed72525af 100644
|
||||||
|
--- a/pkgs/by-name/sy/syncstorage-rs/package.nix
|
||||||
|
+++ b/pkgs/by-name/sy/syncstorage-rs/package.nix
|
||||||
|
@@ -1,14 +1,18 @@
|
||||||
|
{
|
||||||
|
fetchFromGitHub,
|
||||||
|
+ fetchurl,
|
||||||
|
rustPlatform,
|
||||||
|
pkg-config,
|
||||||
|
python3,
|
||||||
|
cmake,
|
||||||
|
libmysqlclient,
|
||||||
|
+ libpq,
|
||||||
|
+ openssl,
|
||||||
|
makeBinaryWrapper,
|
||||||
|
lib,
|
||||||
|
nix-update-script,
|
||||||
|
nixosTests,
|
||||||
|
+ dbBackend ? "mysql",
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
@@ -19,17 +23,23 @@ let
|
||||||
|
p.tokenlib
|
||||||
|
p.cryptography
|
||||||
|
]);
|
||||||
|
+ # utoipa-swagger-ui downloads Swagger UI assets at build time.
|
||||||
|
+ # Prefetch the archive for sandboxed builds.
|
||||||
|
+ swaggerUi = fetchurl {
|
||||||
|
+ url = "https://github.com/swagger-api/swagger-ui/archive/refs/tags/v5.17.14.zip";
|
||||||
|
+ hash = "sha256-SBJE0IEgl7Efuu73n3HZQrFxYX+cn5UU5jrL4T5xzNw=";
|
||||||
|
+ };
|
||||||
|
in
|
||||||
|
|
||||||
|
-rustPlatform.buildRustPackage rec {
|
||||||
|
+rustPlatform.buildRustPackage (finalAttrs: {
|
||||||
|
pname = "syncstorage-rs";
|
||||||
|
- version = "0.21.1-unstable-2026-01-26";
|
||||||
|
+ version = "0.21.1-unstable-2026-02-24";
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "mozilla-services";
|
||||||
|
repo = "syncstorage-rs";
|
||||||
|
- rev = "11659d98f9c69948a0aab353437ce2036c388711";
|
||||||
|
- hash = "sha256-G37QvxTNh/C3gmKG0UYHI6QBr0F+KLGRNI/Sx33uOsc=";
|
||||||
|
+ rev = "50a739b58dc9ec81995f86e71d992aa14ccc450e";
|
||||||
|
+ hash = "sha256-idq0RGdwoV6GVuq36IVVVCFbyMTe8i/EpVWE59D/dhM=";
|
||||||
|
};
|
||||||
|
|
||||||
|
nativeBuildInputs = [
|
||||||
|
@@ -39,16 +49,35 @@ rustPlatform.buildRustPackage rec {
|
||||||
|
python3
|
||||||
|
];
|
||||||
|
|
||||||
|
- buildInputs = [
|
||||||
|
- libmysqlclient
|
||||||
|
- ];
|
||||||
|
+ buildInputs =
|
||||||
|
+ lib.optional (dbBackend == "mysql") libmysqlclient
|
||||||
|
+ ++ lib.optionals (dbBackend == "postgresql") [
|
||||||
|
+ libpq
|
||||||
|
+ openssl
|
||||||
|
+ ];
|
||||||
|
+
|
||||||
|
+ buildNoDefaultFeatures = true;
|
||||||
|
+ # The syncserver "postgres" feature only enables syncstorage-db/postgres.
|
||||||
|
+ # tokenserver-db/postgres must be enabled separately so the tokenserver
|
||||||
|
+ # can also connect to PostgreSQL (it dispatches on the URL scheme at runtime).
|
||||||
|
+ buildFeatures =
|
||||||
|
+ let
|
||||||
|
+ cargoFeature = if dbBackend == "postgresql" then "postgres" else dbBackend;
|
||||||
|
+ in
|
||||||
|
+ [
|
||||||
|
+ cargoFeature
|
||||||
|
+ "tokenserver-db/${cargoFeature}"
|
||||||
|
+ "py_verifier"
|
||||||
|
+ ];
|
||||||
|
+
|
||||||
|
+ SWAGGER_UI_DOWNLOAD_URL = "file://${swaggerUi}";
|
||||||
|
|
||||||
|
preFixup = ''
|
||||||
|
wrapProgram $out/bin/syncserver \
|
||||||
|
--prefix PATH : ${lib.makeBinPath [ pyFxADeps ]}
|
||||||
|
'';
|
||||||
|
|
||||||
|
- cargoHash = "sha256-9Dcf5mDyK/XjsKTlCPXTHoBkIq+FFPDg1zfK24Y9nHQ=";
|
||||||
|
+ cargoHash = "sha256-80EztkSX+SnmqsRWIXbChUB8AeV1Tp9WXoWNbDY8rUE=";
|
||||||
|
|
||||||
|
# almost all tests need a DB to test against
|
||||||
|
doCheck = false;
|
||||||
|
@@ -60,10 +89,10 @@ rustPlatform.buildRustPackage rec {
|
||||||
|
meta = {
|
||||||
|
description = "Mozilla Sync Storage built with Rust";
|
||||||
|
homepage = "https://github.com/mozilla-services/syncstorage-rs";
|
||||||
|
- changelog = "https://github.com/mozilla-services/syncstorage-rs/releases/tag/${version}";
|
||||||
|
+ changelog = "https://github.com/mozilla-services/syncstorage-rs/releases/tag/${finalAttrs.version}";
|
||||||
|
license = lib.licenses.mpl20;
|
||||||
|
maintainers = [ ];
|
||||||
|
platforms = lib.platforms.linux;
|
||||||
|
mainProgram = "syncserver";
|
||||||
|
};
|
||||||
|
-}
|
||||||
|
+})
|
||||||
|
--
|
||||||
|
2.53.0
|
||||||
|
|
||||||
BIN
secrets/firefox-syncserver-env.age
Normal file
BIN
secrets/firefox-syncserver-env.age
Normal file
Binary file not shown.
@@ -9,41 +9,147 @@ rec {
|
|||||||
cpu_arch = "znver3";
|
cpu_arch = "znver3";
|
||||||
|
|
||||||
ports = {
|
ports = {
|
||||||
# public
|
# Ports exposed to the internet. The flake asserts every public port
|
||||||
http = 80; # TCP
|
# appears in the corresponding firewall allow-list (TCP, UDP, or both).
|
||||||
https = 443; # TCP+UDP (HTTP/3 QUIC)
|
public = {
|
||||||
minecraft = 25565; # TCP
|
http = {
|
||||||
syncthing_protocol = 22000; # TCP+UDP (QUIC)
|
port = 80;
|
||||||
syncthing_discovery = 21027; # UDP
|
proto = "tcp";
|
||||||
matrix_federation = 8448; # TCP+UDP (HTTP/3 QUIC)
|
};
|
||||||
coturn = 3478; # TCP+UDP
|
https = {
|
||||||
coturn_tls = 5349; # TCP+UDP
|
port = 443;
|
||||||
livekit = 7880; # TCP
|
proto = "both";
|
||||||
soulseek_listen = 50300; # TCP
|
}; # HTTP/3 QUIC
|
||||||
monero = 18080; # TCP
|
minecraft = {
|
||||||
p2pool_p2p = 37889; # TCP
|
port = 25565;
|
||||||
murmur = 64738; # TCP + UDP
|
proto = "tcp";
|
||||||
|
};
|
||||||
|
syncthing_protocol = {
|
||||||
|
port = 22000;
|
||||||
|
proto = "both";
|
||||||
|
}; # QUIC
|
||||||
|
syncthing_discovery = {
|
||||||
|
port = 21027;
|
||||||
|
proto = "udp";
|
||||||
|
};
|
||||||
|
matrix_federation = {
|
||||||
|
port = 8448;
|
||||||
|
proto = "both";
|
||||||
|
}; # HTTP/3 QUIC
|
||||||
|
coturn = {
|
||||||
|
port = 3478;
|
||||||
|
proto = "both";
|
||||||
|
};
|
||||||
|
coturn_tls = {
|
||||||
|
port = 5349;
|
||||||
|
proto = "both";
|
||||||
|
};
|
||||||
|
livekit = {
|
||||||
|
port = 7880;
|
||||||
|
proto = "tcp";
|
||||||
|
};
|
||||||
|
soulseek_listen = {
|
||||||
|
port = 50300;
|
||||||
|
proto = "tcp";
|
||||||
|
};
|
||||||
|
monero = {
|
||||||
|
port = 18080;
|
||||||
|
proto = "tcp";
|
||||||
|
};
|
||||||
|
monero_rpc = {
|
||||||
|
port = 18081;
|
||||||
|
proto = "tcp";
|
||||||
|
}; # restricted public RPC
|
||||||
|
p2pool_p2p = {
|
||||||
|
port = 37889;
|
||||||
|
proto = "tcp";
|
||||||
|
};
|
||||||
|
murmur = {
|
||||||
|
port = 64738;
|
||||||
|
proto = "both";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
# private
|
# Ports bound to localhost / VPN only. The flake asserts none of
|
||||||
jellyfin = 8096; # TCP - no services.jellyfin option for this
|
# these appear in the firewall allow-lists.
|
||||||
torrent = 6011; # TCP
|
private = {
|
||||||
bitmagnet = 3333; # TCP
|
jellyfin = {
|
||||||
gitea = 2283; # TCP
|
port = 8096;
|
||||||
immich = 2284; # TCP
|
proto = "tcp";
|
||||||
soulseek_web = 5030; # TCP
|
};
|
||||||
vaultwarden = 8222; # TCP
|
torrent = {
|
||||||
syncthing_gui = 8384; # TCP
|
port = 6011;
|
||||||
matrix = 6167; # TCP
|
proto = "tcp";
|
||||||
ntfy = 2586; # TCP
|
};
|
||||||
lk_jwt = 8081; # TCP
|
bitmagnet = {
|
||||||
prowlarr = 9696; # TCP
|
port = 3333;
|
||||||
sonarr = 8989; # TCP
|
proto = "tcp";
|
||||||
radarr = 7878; # TCP
|
};
|
||||||
bazarr = 6767; # TCP
|
gitea = {
|
||||||
jellyseerr = 5055; # TCP
|
port = 2283;
|
||||||
monero_rpc = 18081; # TCP
|
proto = "tcp";
|
||||||
monero_zmq = 18083; # TCP
|
};
|
||||||
p2pool_stratum = 3334; # TCP
|
immich = {
|
||||||
|
port = 2284;
|
||||||
|
proto = "tcp";
|
||||||
|
};
|
||||||
|
soulseek_web = {
|
||||||
|
port = 5030;
|
||||||
|
proto = "tcp";
|
||||||
|
};
|
||||||
|
vaultwarden = {
|
||||||
|
port = 8222;
|
||||||
|
proto = "tcp";
|
||||||
|
};
|
||||||
|
syncthing_gui = {
|
||||||
|
port = 8384;
|
||||||
|
proto = "tcp";
|
||||||
|
};
|
||||||
|
matrix = {
|
||||||
|
port = 6167;
|
||||||
|
proto = "tcp";
|
||||||
|
};
|
||||||
|
ntfy = {
|
||||||
|
port = 2586;
|
||||||
|
proto = "tcp";
|
||||||
|
};
|
||||||
|
lk_jwt = {
|
||||||
|
port = 8081;
|
||||||
|
proto = "tcp";
|
||||||
|
};
|
||||||
|
prowlarr = {
|
||||||
|
port = 9696;
|
||||||
|
proto = "tcp";
|
||||||
|
};
|
||||||
|
sonarr = {
|
||||||
|
port = 8989;
|
||||||
|
proto = "tcp";
|
||||||
|
};
|
||||||
|
radarr = {
|
||||||
|
port = 7878;
|
||||||
|
proto = "tcp";
|
||||||
|
};
|
||||||
|
bazarr = {
|
||||||
|
port = 6767;
|
||||||
|
proto = "tcp";
|
||||||
|
};
|
||||||
|
jellyseerr = {
|
||||||
|
port = 5055;
|
||||||
|
proto = "tcp";
|
||||||
|
};
|
||||||
|
monero_zmq = {
|
||||||
|
port = 18083;
|
||||||
|
proto = "tcp";
|
||||||
|
};
|
||||||
|
p2pool_stratum = {
|
||||||
|
port = 3334;
|
||||||
|
proto = "tcp";
|
||||||
|
};
|
||||||
|
firefox_syncserver = {
|
||||||
|
port = 5000;
|
||||||
|
proto = "tcp";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
https = {
|
https = {
|
||||||
@@ -70,7 +176,7 @@ rec {
|
|||||||
minecraft = {
|
minecraft = {
|
||||||
parent_dir = services_dir + "/minecraft";
|
parent_dir = services_dir + "/minecraft";
|
||||||
server_name = "main";
|
server_name = "main";
|
||||||
memory = rec {
|
memory = {
|
||||||
heap_size_m = 4000;
|
heap_size_m = 4000;
|
||||||
large_page_size_m = 2;
|
large_page_size_m = 2;
|
||||||
};
|
};
|
||||||
@@ -147,6 +253,10 @@ rec {
|
|||||||
dataDir = services_dir + "/recyclarr";
|
dataDir = services_dir + "/recyclarr";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
firefox_syncserver = {
|
||||||
|
domain = "firefox-sync.${https.domain}";
|
||||||
|
};
|
||||||
|
|
||||||
media = {
|
media = {
|
||||||
moviesDir = torrents_path + "/media/movies";
|
moviesDir = torrents_path + "/media/movies";
|
||||||
tvDir = torrents_path + "/media/tv";
|
tvDir = torrents_path + "/media/tv";
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ let
|
|||||||
radarrConfig = "${service_configs.radarr.dataDir}/config.xml";
|
radarrConfig = "${service_configs.radarr.dataDir}/config.xml";
|
||||||
sonarrConfig = "${service_configs.sonarr.dataDir}/config.xml";
|
sonarrConfig = "${service_configs.sonarr.dataDir}/config.xml";
|
||||||
|
|
||||||
radarrUrl = "http://localhost:${builtins.toString service_configs.ports.radarr}";
|
radarrUrl = "http://localhost:${builtins.toString service_configs.ports.private.radarr.port}";
|
||||||
sonarrUrl = "http://localhost:${builtins.toString service_configs.ports.sonarr}";
|
sonarrUrl = "http://localhost:${builtins.toString service_configs.ports.private.sonarr.port}";
|
||||||
|
|
||||||
curl = "${pkgs.curl}/bin/curl";
|
curl = "${pkgs.curl}/bin/curl";
|
||||||
jq = "${pkgs.jq}/bin/jq";
|
jq = "${pkgs.jq}/bin/jq";
|
||||||
|
|||||||
@@ -20,12 +20,12 @@
|
|||||||
|
|
||||||
services.bazarr = {
|
services.bazarr = {
|
||||||
enable = true;
|
enable = true;
|
||||||
listenPort = service_configs.ports.bazarr;
|
listenPort = service_configs.ports.private.bazarr.port;
|
||||||
};
|
};
|
||||||
|
|
||||||
services.caddy.virtualHosts."bazarr.${service_configs.https.domain}".extraConfig = ''
|
services.caddy.virtualHosts."bazarr.${service_configs.https.domain}".extraConfig = ''
|
||||||
import ${config.age.secrets.caddy_auth.path}
|
import ${config.age.secrets.caddy_auth.path}
|
||||||
reverse_proxy :${builtins.toString service_configs.ports.bazarr}
|
reverse_proxy :${builtins.toString service_configs.ports.private.bazarr.port}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
users.users.${config.services.bazarr.user}.extraGroups = [
|
users.users.${config.services.bazarr.user}.extraGroups = [
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
prowlarr = {
|
prowlarr = {
|
||||||
enable = true;
|
enable = true;
|
||||||
serviceName = "prowlarr";
|
serviceName = "prowlarr";
|
||||||
port = service_configs.ports.prowlarr;
|
port = service_configs.ports.private.prowlarr.port;
|
||||||
dataDir = service_configs.prowlarr.dataDir;
|
dataDir = service_configs.prowlarr.dataDir;
|
||||||
apiVersion = "v1";
|
apiVersion = "v1";
|
||||||
networkNamespacePath = "/run/netns/wg";
|
networkNamespacePath = "/run/netns/wg";
|
||||||
@@ -14,8 +14,8 @@
|
|||||||
name = "Sonarr";
|
name = "Sonarr";
|
||||||
implementation = "Sonarr";
|
implementation = "Sonarr";
|
||||||
configContract = "SonarrSettings";
|
configContract = "SonarrSettings";
|
||||||
prowlarrUrl = "http://localhost:${builtins.toString service_configs.ports.prowlarr}";
|
prowlarrUrl = "http://localhost:${builtins.toString service_configs.ports.private.prowlarr.port}";
|
||||||
baseUrl = "http://${config.vpnNamespaces.wg.bridgeAddress}:${builtins.toString service_configs.ports.sonarr}";
|
baseUrl = "http://${config.vpnNamespaces.wg.bridgeAddress}:${builtins.toString service_configs.ports.private.sonarr.port}";
|
||||||
apiKeyFrom = "${service_configs.sonarr.dataDir}/config.xml";
|
apiKeyFrom = "${service_configs.sonarr.dataDir}/config.xml";
|
||||||
syncCategories = [
|
syncCategories = [
|
||||||
5000
|
5000
|
||||||
@@ -33,8 +33,8 @@
|
|||||||
name = "Radarr";
|
name = "Radarr";
|
||||||
implementation = "Radarr";
|
implementation = "Radarr";
|
||||||
configContract = "RadarrSettings";
|
configContract = "RadarrSettings";
|
||||||
prowlarrUrl = "http://localhost:${builtins.toString service_configs.ports.prowlarr}";
|
prowlarrUrl = "http://localhost:${builtins.toString service_configs.ports.private.prowlarr.port}";
|
||||||
baseUrl = "http://${config.vpnNamespaces.wg.bridgeAddress}:${builtins.toString service_configs.ports.radarr}";
|
baseUrl = "http://${config.vpnNamespaces.wg.bridgeAddress}:${builtins.toString service_configs.ports.private.radarr.port}";
|
||||||
apiKeyFrom = "${service_configs.radarr.dataDir}/config.xml";
|
apiKeyFrom = "${service_configs.radarr.dataDir}/config.xml";
|
||||||
syncCategories = [
|
syncCategories = [
|
||||||
2000
|
2000
|
||||||
@@ -56,7 +56,7 @@
|
|||||||
sonarr = {
|
sonarr = {
|
||||||
enable = true;
|
enable = true;
|
||||||
serviceName = "sonarr";
|
serviceName = "sonarr";
|
||||||
port = service_configs.ports.sonarr;
|
port = service_configs.ports.private.sonarr.port;
|
||||||
dataDir = service_configs.sonarr.dataDir;
|
dataDir = service_configs.sonarr.dataDir;
|
||||||
healthChecks = true;
|
healthChecks = true;
|
||||||
rootFolders = [ service_configs.media.tvDir ];
|
rootFolders = [ service_configs.media.tvDir ];
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
serviceName = "qbittorrent";
|
serviceName = "qbittorrent";
|
||||||
fields = {
|
fields = {
|
||||||
host = config.vpnNamespaces.wg.namespaceAddress;
|
host = config.vpnNamespaces.wg.namespaceAddress;
|
||||||
port = service_configs.ports.torrent;
|
port = service_configs.ports.private.torrent.port;
|
||||||
useSsl = false;
|
useSsl = false;
|
||||||
tvCategory = "tvshows";
|
tvCategory = "tvshows";
|
||||||
};
|
};
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
radarr = {
|
radarr = {
|
||||||
enable = true;
|
enable = true;
|
||||||
serviceName = "radarr";
|
serviceName = "radarr";
|
||||||
port = service_configs.ports.radarr;
|
port = service_configs.ports.private.radarr.port;
|
||||||
dataDir = service_configs.radarr.dataDir;
|
dataDir = service_configs.radarr.dataDir;
|
||||||
healthChecks = true;
|
healthChecks = true;
|
||||||
rootFolders = [ service_configs.media.moviesDir ];
|
rootFolders = [ service_configs.media.moviesDir ];
|
||||||
@@ -91,7 +91,7 @@
|
|||||||
serviceName = "qbittorrent";
|
serviceName = "qbittorrent";
|
||||||
fields = {
|
fields = {
|
||||||
host = config.vpnNamespaces.wg.namespaceAddress;
|
host = config.vpnNamespaces.wg.namespaceAddress;
|
||||||
port = service_configs.ports.torrent;
|
port = service_configs.ports.private.torrent.port;
|
||||||
useSsl = false;
|
useSsl = false;
|
||||||
movieCategory = "movies";
|
movieCategory = "movies";
|
||||||
};
|
};
|
||||||
@@ -103,17 +103,17 @@
|
|||||||
services.bazarrInit = {
|
services.bazarrInit = {
|
||||||
enable = true;
|
enable = true;
|
||||||
dataDir = "/var/lib/bazarr";
|
dataDir = "/var/lib/bazarr";
|
||||||
port = service_configs.ports.bazarr;
|
port = service_configs.ports.private.bazarr.port;
|
||||||
sonarr = {
|
sonarr = {
|
||||||
enable = true;
|
enable = true;
|
||||||
dataDir = service_configs.sonarr.dataDir;
|
dataDir = service_configs.sonarr.dataDir;
|
||||||
port = service_configs.ports.sonarr;
|
port = service_configs.ports.private.sonarr.port;
|
||||||
serviceName = "sonarr";
|
serviceName = "sonarr";
|
||||||
};
|
};
|
||||||
radarr = {
|
radarr = {
|
||||||
enable = true;
|
enable = true;
|
||||||
dataDir = service_configs.radarr.dataDir;
|
dataDir = service_configs.radarr.dataDir;
|
||||||
port = service_configs.ports.radarr;
|
port = service_configs.ports.private.radarr.port;
|
||||||
serviceName = "radarr";
|
serviceName = "radarr";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
services.jellyseerr = {
|
services.jellyseerr = {
|
||||||
enable = true;
|
enable = true;
|
||||||
port = service_configs.ports.jellyseerr;
|
port = service_configs.ports.private.jellyseerr.port;
|
||||||
configDir = service_configs.jellyseerr.configDir;
|
configDir = service_configs.jellyseerr.configDir;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -38,6 +38,6 @@
|
|||||||
|
|
||||||
services.caddy.virtualHosts."jellyseerr.${service_configs.https.domain}".extraConfig = ''
|
services.caddy.virtualHosts."jellyseerr.${service_configs.https.domain}".extraConfig = ''
|
||||||
# import ${config.age.secrets.caddy_auth.path}
|
# import ${config.age.secrets.caddy_auth.path}
|
||||||
reverse_proxy :${builtins.toString service_configs.ports.jellyseerr}
|
reverse_proxy :${builtins.toString service_configs.ports.private.jellyseerr.port}
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,17 +10,17 @@
|
|||||||
(lib.serviceMountWithZpool "prowlarr" service_configs.zpool_ssds [
|
(lib.serviceMountWithZpool "prowlarr" service_configs.zpool_ssds [
|
||||||
service_configs.prowlarr.dataDir
|
service_configs.prowlarr.dataDir
|
||||||
])
|
])
|
||||||
(lib.vpnNamespaceOpenPort service_configs.ports.prowlarr "prowlarr")
|
(lib.vpnNamespaceOpenPort service_configs.ports.private.prowlarr.port "prowlarr")
|
||||||
];
|
];
|
||||||
|
|
||||||
services.prowlarr = {
|
services.prowlarr = {
|
||||||
enable = true;
|
enable = true;
|
||||||
dataDir = service_configs.prowlarr.dataDir;
|
dataDir = service_configs.prowlarr.dataDir;
|
||||||
settings.server.port = service_configs.ports.prowlarr;
|
settings.server.port = service_configs.ports.private.prowlarr.port;
|
||||||
};
|
};
|
||||||
|
|
||||||
services.caddy.virtualHosts."prowlarr.${service_configs.https.domain}".extraConfig = ''
|
services.caddy.virtualHosts."prowlarr.${service_configs.https.domain}".extraConfig = ''
|
||||||
import ${config.age.secrets.caddy_auth.path}
|
import ${config.age.secrets.caddy_auth.path}
|
||||||
reverse_proxy ${config.vpnNamespaces.wg.namespaceAddress}:${builtins.toString service_configs.ports.prowlarr}
|
reverse_proxy ${config.vpnNamespaces.wg.namespaceAddress}:${builtins.toString service_configs.ports.private.prowlarr.port}
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,13 +21,13 @@
|
|||||||
services.radarr = {
|
services.radarr = {
|
||||||
enable = true;
|
enable = true;
|
||||||
dataDir = service_configs.radarr.dataDir;
|
dataDir = service_configs.radarr.dataDir;
|
||||||
settings.server.port = service_configs.ports.radarr;
|
settings.server.port = service_configs.ports.private.radarr.port;
|
||||||
settings.update.mechanism = "external";
|
settings.update.mechanism = "external";
|
||||||
};
|
};
|
||||||
|
|
||||||
services.caddy.virtualHosts."radarr.${service_configs.https.domain}".extraConfig = ''
|
services.caddy.virtualHosts."radarr.${service_configs.https.domain}".extraConfig = ''
|
||||||
import ${config.age.secrets.caddy_auth.path}
|
import ${config.age.secrets.caddy_auth.path}
|
||||||
reverse_proxy :${builtins.toString service_configs.ports.radarr}
|
reverse_proxy :${builtins.toString service_configs.ports.private.radarr.port}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
users.users.${config.services.radarr.user}.extraGroups = [
|
users.users.${config.services.radarr.user}.extraGroups = [
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ in
|
|||||||
|
|
||||||
configuration = {
|
configuration = {
|
||||||
radarr.movies = {
|
radarr.movies = {
|
||||||
base_url = "http://localhost:${builtins.toString service_configs.ports.radarr}";
|
base_url = "http://localhost:${builtins.toString service_configs.ports.private.radarr.port}";
|
||||||
|
|
||||||
include = [
|
include = [
|
||||||
{ template = "radarr-quality-definition-movie"; }
|
{ template = "radarr-quality-definition-movie"; }
|
||||||
@@ -123,7 +123,7 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
sonarr.series = {
|
sonarr.series = {
|
||||||
base_url = "http://localhost:${builtins.toString service_configs.ports.sonarr}";
|
base_url = "http://localhost:${builtins.toString service_configs.ports.private.sonarr.port}";
|
||||||
|
|
||||||
include = [
|
include = [
|
||||||
{ template = "sonarr-quality-definition-series"; }
|
{ template = "sonarr-quality-definition-series"; }
|
||||||
|
|||||||
@@ -27,13 +27,13 @@
|
|||||||
services.sonarr = {
|
services.sonarr = {
|
||||||
enable = true;
|
enable = true;
|
||||||
dataDir = service_configs.sonarr.dataDir;
|
dataDir = service_configs.sonarr.dataDir;
|
||||||
settings.server.port = service_configs.ports.sonarr;
|
settings.server.port = service_configs.ports.private.sonarr.port;
|
||||||
settings.update.mechanism = "external";
|
settings.update.mechanism = "external";
|
||||||
};
|
};
|
||||||
|
|
||||||
services.caddy.virtualHosts."sonarr.${service_configs.https.domain}".extraConfig = ''
|
services.caddy.virtualHosts."sonarr.${service_configs.https.domain}".extraConfig = ''
|
||||||
import ${config.age.secrets.caddy_auth.path}
|
import ${config.age.secrets.caddy_auth.path}
|
||||||
reverse_proxy :${builtins.toString service_configs.ports.sonarr}
|
reverse_proxy :${builtins.toString service_configs.ports.private.sonarr.port}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
users.users.${config.services.sonarr.user}.extraGroups = [
|
users.users.${config.services.sonarr.user}.extraGroups = [
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
(lib.vpnNamespaceOpenPort service_configs.ports.bitmagnet "bitmagnet")
|
(lib.vpnNamespaceOpenPort service_configs.ports.private.bitmagnet.port "bitmagnet")
|
||||||
];
|
];
|
||||||
|
|
||||||
services.bitmagnet = {
|
services.bitmagnet = {
|
||||||
@@ -19,13 +19,13 @@
|
|||||||
};
|
};
|
||||||
http_server = {
|
http_server = {
|
||||||
# TODO! make issue about this being a string and not a `port` type
|
# TODO! make issue about this being a string and not a `port` type
|
||||||
port = ":" + (builtins.toString service_configs.ports.bitmagnet);
|
port = ":" + (builtins.toString service_configs.ports.private.bitmagnet.port);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
services.caddy.virtualHosts."bitmagnet.${service_configs.https.domain}".extraConfig = ''
|
services.caddy.virtualHosts."bitmagnet.${service_configs.https.domain}".extraConfig = ''
|
||||||
import ${config.age.secrets.caddy_auth.path}
|
import ${config.age.secrets.caddy_auth.path}
|
||||||
reverse_proxy ${config.vpnNamespaces.wg.namespaceAddress}:${builtins.toString service_configs.ports.bitmagnet}
|
reverse_proxy ${config.vpnNamespaces.wg.namespaceAddress}:${builtins.toString service_configs.ports.private.bitmagnet.port}
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,28 +9,23 @@
|
|||||||
imports = [
|
imports = [
|
||||||
(lib.serviceMountWithZpool "vaultwarden" service_configs.zpool_ssds [
|
(lib.serviceMountWithZpool "vaultwarden" service_configs.zpool_ssds [
|
||||||
service_configs.vaultwarden.path
|
service_configs.vaultwarden.path
|
||||||
config.services.vaultwarden.backupDir
|
|
||||||
])
|
|
||||||
(lib.serviceMountWithZpool "backup-vaultwarden" service_configs.zpool_ssds [
|
|
||||||
service_configs.vaultwarden.path
|
|
||||||
config.services.vaultwarden.backupDir
|
|
||||||
])
|
])
|
||||||
(lib.serviceFilePerms "vaultwarden" [
|
(lib.serviceFilePerms "vaultwarden" [
|
||||||
"Z ${service_configs.vaultwarden.path} 0700 vaultwarden vaultwarden"
|
"Z ${service_configs.vaultwarden.path} 0700 vaultwarden vaultwarden"
|
||||||
"Z ${config.services.vaultwarden.backupDir} 0700 vaultwarden vaultwarden"
|
|
||||||
])
|
])
|
||||||
];
|
];
|
||||||
|
|
||||||
services.vaultwarden = {
|
services.vaultwarden = {
|
||||||
enable = true;
|
enable = true;
|
||||||
backupDir = "/${service_configs.zpool_ssds}/bak/vaultwarden";
|
dbBackend = "postgresql";
|
||||||
|
configurePostgres = true;
|
||||||
config = {
|
config = {
|
||||||
# Refer to https://github.com/dani-garcia/vaultwarden/blob/main/.env.template
|
# Refer to https://github.com/dani-garcia/vaultwarden/blob/main/.env.template
|
||||||
DOMAIN = "https://bitwarden.${service_configs.https.domain}";
|
DOMAIN = "https://bitwarden.${service_configs.https.domain}";
|
||||||
SIGNUPS_ALLOWED = false;
|
SIGNUPS_ALLOWED = false;
|
||||||
|
|
||||||
ROCKET_ADDRESS = "127.0.0.1";
|
ROCKET_ADDRESS = "127.0.0.1";
|
||||||
ROCKET_PORT = service_configs.ports.vaultwarden;
|
ROCKET_PORT = service_configs.ports.private.vaultwarden.port;
|
||||||
ROCKET_LOG = "critical";
|
ROCKET_LOG = "critical";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -113,14 +113,14 @@ in
|
|||||||
systemd.packages = with pkgs; [ nssTools ];
|
systemd.packages = with pkgs; [ nssTools ];
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [
|
networking.firewall.allowedTCPPorts = [
|
||||||
service_configs.ports.https
|
service_configs.ports.public.https.port
|
||||||
|
|
||||||
# http (but really acmeCA challenges)
|
# http (but really acmeCA challenges)
|
||||||
service_configs.ports.http
|
service_configs.ports.public.http.port
|
||||||
];
|
];
|
||||||
|
|
||||||
networking.firewall.allowedUDPPorts = [
|
networking.firewall.allowedUDPPorts = [
|
||||||
service_configs.ports.https
|
service_configs.ports.public.https.port
|
||||||
];
|
];
|
||||||
|
|
||||||
# Protect Caddy basic auth endpoints from brute force attacks
|
# Protect Caddy basic auth endpoints from brute force attacks
|
||||||
|
|||||||
@@ -10,8 +10,8 @@
|
|||||||
realm = service_configs.https.domain;
|
realm = service_configs.https.domain;
|
||||||
use-auth-secret = true;
|
use-auth-secret = true;
|
||||||
static-auth-secret = lib.strings.trim (builtins.readFile ../secrets/coturn_static_auth_secret);
|
static-auth-secret = lib.strings.trim (builtins.readFile ../secrets/coturn_static_auth_secret);
|
||||||
listening-port = service_configs.ports.coturn;
|
listening-port = service_configs.ports.public.coturn.port;
|
||||||
tls-listening-port = service_configs.ports.coturn_tls;
|
tls-listening-port = service_configs.ports.public.coturn_tls.port;
|
||||||
no-cli = true;
|
no-cli = true;
|
||||||
|
|
||||||
# recommended security settings from Synapse's coturn docs
|
# recommended security settings from Synapse's coturn docs
|
||||||
@@ -41,12 +41,12 @@
|
|||||||
# coturn needs these ports open
|
# coturn needs these ports open
|
||||||
networking.firewall = {
|
networking.firewall = {
|
||||||
allowedTCPPorts = [
|
allowedTCPPorts = [
|
||||||
service_configs.ports.coturn
|
service_configs.ports.public.coturn.port
|
||||||
service_configs.ports.coturn_tls
|
service_configs.ports.public.coturn_tls.port
|
||||||
];
|
];
|
||||||
allowedUDPPorts = [
|
allowedUDPPorts = [
|
||||||
service_configs.ports.coturn
|
service_configs.ports.public.coturn.port
|
||||||
service_configs.ports.coturn_tls
|
service_configs.ports.public.coturn_tls.port
|
||||||
];
|
];
|
||||||
# relay port range
|
# relay port range
|
||||||
allowedUDPPortRanges = [
|
allowedUDPPortRanges = [
|
||||||
|
|||||||
39
services/firefox-syncserver.nix
Normal file
39
services/firefox-syncserver.nix
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
service_configs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
services.firefox-syncserver = {
|
||||||
|
enable = true;
|
||||||
|
database = {
|
||||||
|
type = "postgresql";
|
||||||
|
createLocally = false;
|
||||||
|
user = "firefox_syncserver";
|
||||||
|
};
|
||||||
|
secrets = config.age.secrets.firefox-syncserver-env.path;
|
||||||
|
settings.port = service_configs.ports.private.firefox_syncserver.port;
|
||||||
|
singleNode = {
|
||||||
|
enable = true;
|
||||||
|
hostname = service_configs.firefox_syncserver.domain;
|
||||||
|
url = "https://${service_configs.firefox_syncserver.domain}";
|
||||||
|
capacity = 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.postgresql = {
|
||||||
|
ensureDatabases = [ "firefox_syncserver" ];
|
||||||
|
ensureUsers = [
|
||||||
|
{
|
||||||
|
name = "firefox_syncserver";
|
||||||
|
ensureDBOwnership = true;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.caddy.virtualHosts."${service_configs.firefox_syncserver.domain}".extraConfig = ''
|
||||||
|
reverse_proxy :${builtins.toString service_configs.ports.private.firefox_syncserver.port}
|
||||||
|
'';
|
||||||
|
}
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
SSH_USER = "gitea";
|
SSH_USER = "gitea";
|
||||||
DOMAIN = service_configs.gitea.domain;
|
DOMAIN = service_configs.gitea.domain;
|
||||||
ROOT_URL = "https://" + config.services.gitea.settings.server.DOMAIN;
|
ROOT_URL = "https://" + config.services.gitea.settings.server.DOMAIN;
|
||||||
HTTP_PORT = service_configs.ports.gitea;
|
HTTP_PORT = service_configs.ports.private.gitea.port;
|
||||||
LANDING_PAGE = "/explore/repos";
|
LANDING_PAGE = "/explore/repos";
|
||||||
DISABLE_HTTP_GIT = true;
|
DISABLE_HTTP_GIT = true;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
services.immich = {
|
services.immich = {
|
||||||
enable = true;
|
enable = true;
|
||||||
mediaLocation = service_configs.immich.dir;
|
mediaLocation = service_configs.immich.dir;
|
||||||
port = service_configs.ports.immich;
|
port = service_configs.ports.private.immich.port;
|
||||||
# openFirewall = true;
|
# openFirewall = true;
|
||||||
host = "0.0.0.0";
|
host = "0.0.0.0";
|
||||||
database = {
|
database = {
|
||||||
|
|||||||
@@ -43,8 +43,8 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
environment = {
|
environment = {
|
||||||
JELLYFIN_URL = "http://localhost:${builtins.toString service_configs.ports.jellyfin}";
|
JELLYFIN_URL = "http://localhost:${builtins.toString service_configs.ports.private.jellyfin.port}";
|
||||||
QBITTORRENT_URL = "http://${config.vpnNamespaces.wg.namespaceAddress}:${builtins.toString service_configs.ports.torrent}";
|
QBITTORRENT_URL = "http://${config.vpnNamespaces.wg.namespaceAddress}:${builtins.toString service_configs.ports.private.torrent.port}";
|
||||||
CHECK_INTERVAL = "30";
|
CHECK_INTERVAL = "30";
|
||||||
# Bandwidth budget configuration
|
# Bandwidth budget configuration
|
||||||
TOTAL_BANDWIDTH_BUDGET = "30000000"; # 30 Mbps in bits per second
|
TOTAL_BANDWIDTH_BUDGET = "30000000"; # 30 Mbps in bits per second
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
services.caddy.virtualHosts."jellyfin.${service_configs.https.domain}".extraConfig = ''
|
services.caddy.virtualHosts."jellyfin.${service_configs.https.domain}".extraConfig = ''
|
||||||
reverse_proxy :${builtins.toString service_configs.ports.jellyfin} {
|
reverse_proxy :${builtins.toString service_configs.ports.private.jellyfin.port} {
|
||||||
header_up X-Real-IP {remote_host}
|
header_up X-Real-IP {remote_host}
|
||||||
header_up X-Forwarded-For {remote_host}
|
header_up X-Forwarded-For {remote_host}
|
||||||
header_up X-Forwarded-Proto {scheme}
|
header_up X-Forwarded-Proto {scheme}
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
keyFile = ../secrets/livekit_keys;
|
keyFile = ../secrets/livekit_keys;
|
||||||
|
|
||||||
ports = service_configs.ports;
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
services.livekit = {
|
services.livekit = {
|
||||||
@@ -14,7 +12,7 @@ in
|
|||||||
openFirewall = true;
|
openFirewall = true;
|
||||||
|
|
||||||
settings = {
|
settings = {
|
||||||
port = ports.livekit;
|
port = service_configs.ports.public.livekit.port;
|
||||||
bind_addresses = [ "127.0.0.1" ];
|
bind_addresses = [ "127.0.0.1" ];
|
||||||
|
|
||||||
rtc = {
|
rtc = {
|
||||||
@@ -38,16 +36,16 @@ in
|
|||||||
enable = true;
|
enable = true;
|
||||||
inherit keyFile;
|
inherit keyFile;
|
||||||
livekitUrl = "wss://${service_configs.livekit.domain}";
|
livekitUrl = "wss://${service_configs.livekit.domain}";
|
||||||
port = ports.lk_jwt;
|
port = service_configs.ports.private.lk_jwt.port;
|
||||||
};
|
};
|
||||||
|
|
||||||
services.caddy.virtualHosts."${service_configs.livekit.domain}".extraConfig = ''
|
services.caddy.virtualHosts."${service_configs.livekit.domain}".extraConfig = ''
|
||||||
@jwt path /sfu/get /healthz
|
@jwt path /sfu/get /healthz
|
||||||
handle @jwt {
|
handle @jwt {
|
||||||
reverse_proxy :${builtins.toString ports.lk_jwt}
|
reverse_proxy :${builtins.toString service_configs.ports.private.lk_jwt.port}
|
||||||
}
|
}
|
||||||
handle {
|
handle {
|
||||||
reverse_proxy :${builtins.toString ports.livekit}
|
reverse_proxy :${builtins.toString service_configs.ports.public.livekit.port}
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
enable = true;
|
enable = true;
|
||||||
|
|
||||||
settings.global = {
|
settings.global = {
|
||||||
port = [ service_configs.ports.matrix ];
|
port = [ service_configs.ports.private.matrix.port ];
|
||||||
server_name = service_configs.https.domain;
|
server_name = service_configs.https.domain;
|
||||||
allow_registration = true;
|
allow_registration = true;
|
||||||
registration_token = lib.strings.trim (builtins.readFile ../secrets/matrix_reg_token);
|
registration_token = lib.strings.trim (builtins.readFile ../secrets/matrix_reg_token);
|
||||||
@@ -49,25 +49,25 @@
|
|||||||
services.caddy.virtualHosts.${service_configs.https.domain}.extraConfig = lib.mkBefore ''
|
services.caddy.virtualHosts.${service_configs.https.domain}.extraConfig = lib.mkBefore ''
|
||||||
header /.well-known/matrix/* Content-Type application/json
|
header /.well-known/matrix/* Content-Type application/json
|
||||||
header /.well-known/matrix/* Access-Control-Allow-Origin *
|
header /.well-known/matrix/* Access-Control-Allow-Origin *
|
||||||
respond /.well-known/matrix/server `{"m.server": "${service_configs.matrix.domain}:${builtins.toString service_configs.ports.https}"}`
|
respond /.well-known/matrix/server `{"m.server": "${service_configs.matrix.domain}:${builtins.toString service_configs.ports.public.https.port}"}`
|
||||||
respond /.well-known/matrix/client `{"m.server":{"base_url":"https://${service_configs.matrix.domain}"},"m.homeserver":{"base_url":"https://${service_configs.matrix.domain}"},"org.matrix.msc3575.proxy":{"base_url":"https://${config.services.matrix-continuwuity.settings.global.server_name}"},"org.matrix.msc4143.rtc_foci":[{"type":"livekit","livekit_service_url":"https://${service_configs.livekit.domain}"}]}`
|
respond /.well-known/matrix/client `{"m.server":{"base_url":"https://${service_configs.matrix.domain}"},"m.homeserver":{"base_url":"https://${service_configs.matrix.domain}"},"org.matrix.msc3575.proxy":{"base_url":"https://${config.services.matrix-continuwuity.settings.global.server_name}"},"org.matrix.msc4143.rtc_foci":[{"type":"livekit","livekit_service_url":"https://${service_configs.livekit.domain}"}]}`
|
||||||
'';
|
'';
|
||||||
|
|
||||||
services.caddy.virtualHosts."${service_configs.matrix.domain}".extraConfig = ''
|
services.caddy.virtualHosts."${service_configs.matrix.domain}".extraConfig = ''
|
||||||
reverse_proxy :${builtins.toString service_configs.ports.matrix}
|
reverse_proxy :${builtins.toString service_configs.ports.private.matrix.port}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
# Exact duplicate for federation port
|
# Exact duplicate for federation port
|
||||||
services.caddy.virtualHosts."${service_configs.matrix.domain}:${builtins.toString service_configs.ports.matrix_federation}".extraConfig =
|
services.caddy.virtualHosts."${service_configs.matrix.domain}:${builtins.toString service_configs.ports.public.matrix_federation.port}".extraConfig =
|
||||||
config.services.caddy.virtualHosts."${service_configs.matrix.domain}".extraConfig;
|
config.services.caddy.virtualHosts."${service_configs.matrix.domain}".extraConfig;
|
||||||
|
|
||||||
# for federation
|
# for federation
|
||||||
networking.firewall.allowedTCPPorts = [
|
networking.firewall.allowedTCPPorts = [
|
||||||
service_configs.ports.matrix_federation
|
service_configs.ports.public.matrix_federation.port
|
||||||
];
|
];
|
||||||
|
|
||||||
# for federation
|
# for federation
|
||||||
networking.firewall.allowedUDPPorts = [
|
networking.firewall.allowedUDPPorts = [
|
||||||
service_configs.ports.matrix_federation
|
service_configs.ports.public.matrix_federation.port
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,7 +73,7 @@
|
|||||||
];
|
];
|
||||||
|
|
||||||
serverProperties = {
|
serverProperties = {
|
||||||
server-port = service_configs.ports.minecraft;
|
server-port = service_configs.ports.public.minecraft.port;
|
||||||
enforce-whitelist = true;
|
enforce-whitelist = true;
|
||||||
gamemode = "survival";
|
gamemode = "survival";
|
||||||
white-list = true;
|
white-list = true;
|
||||||
|
|||||||
@@ -18,12 +18,12 @@
|
|||||||
dataDir = service_configs.monero.dataDir;
|
dataDir = service_configs.monero.dataDir;
|
||||||
rpc = {
|
rpc = {
|
||||||
address = "0.0.0.0";
|
address = "0.0.0.0";
|
||||||
port = service_configs.ports.monero_rpc;
|
port = service_configs.ports.public.monero_rpc.port;
|
||||||
restricted = true;
|
restricted = true;
|
||||||
};
|
};
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
p2p-bind-port=${builtins.toString service_configs.ports.monero}
|
p2p-bind-port=${builtins.toString service_configs.ports.public.monero.port}
|
||||||
zmq-pub=tcp://127.0.0.1:${builtins.toString service_configs.ports.monero_zmq}
|
zmq-pub=tcp://127.0.0.1:${builtins.toString service_configs.ports.private.monero_zmq.port}
|
||||||
db-sync-mode=fast:async:1000000000bytes
|
db-sync-mode=fast:async:1000000000bytes
|
||||||
public-node=1
|
public-node=1
|
||||||
confirm-external-bind=1
|
confirm-external-bind=1
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [
|
networking.firewall.allowedTCPPorts = [
|
||||||
service_configs.ports.monero
|
service_configs.ports.public.monero.port
|
||||||
service_configs.ports.monero_rpc
|
service_configs.ports.public.monero_rpc.port
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
settings = {
|
settings = {
|
||||||
base-url = "https://${service_configs.ntfy.domain}";
|
base-url = "https://${service_configs.ntfy.domain}";
|
||||||
listen-http = "127.0.0.1:${builtins.toString service_configs.ports.ntfy}";
|
listen-http = "127.0.0.1:${builtins.toString service_configs.ports.private.ntfy.port}";
|
||||||
behind-proxy = true;
|
behind-proxy = true;
|
||||||
auth-default-access = "deny-all";
|
auth-default-access = "deny-all";
|
||||||
enable-login = true;
|
enable-login = true;
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
services.caddy.virtualHosts."${service_configs.ntfy.domain}".extraConfig = ''
|
services.caddy.virtualHosts."${service_configs.ntfy.domain}".extraConfig = ''
|
||||||
reverse_proxy :${builtins.toString service_configs.ports.ntfy}
|
reverse_proxy :${builtins.toString service_configs.ports.private.ntfy.port}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ in
|
|||||||
walletAddress = walletAddress;
|
walletAddress = walletAddress;
|
||||||
sidechain = "nano";
|
sidechain = "nano";
|
||||||
host = "127.0.0.1";
|
host = "127.0.0.1";
|
||||||
rpcPort = service_configs.ports.monero_rpc;
|
rpcPort = service_configs.ports.public.monero_rpc.port;
|
||||||
zmqPort = service_configs.ports.monero_zmq;
|
zmqPort = service_configs.ports.private.monero_zmq.port;
|
||||||
extraArgs = [
|
extraArgs = [
|
||||||
" --stratum 0.0.0.0:${builtins.toString service_configs.ports.p2pool_stratum}"
|
" --stratum 0.0.0.0:${builtins.toString service_configs.ports.private.p2pool_stratum.port}"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -43,6 +43,6 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [
|
networking.firewall.allowedTCPPorts = [
|
||||||
service_configs.ports.p2pool_p2p
|
service_configs.ports.public.p2pool_p2p.port
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,30 @@
|
|||||||
lib,
|
lib,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
|
let
|
||||||
|
pgCheckpoint = pkgs.writeShellScript "pg-checkpoint" ''
|
||||||
|
# Flush PostgreSQL dirty buffers to disk before ZFS snapshot so the
|
||||||
|
# on-disk state is consistent and the snapshot is recoverable.
|
||||||
|
# On failure: log a warning but exit 0 so sanoid still takes the
|
||||||
|
# snapshot (an inconsistent snapshot beats no snapshot).
|
||||||
|
if ! ${pkgs.systemd}/bin/systemctl is-active --quiet postgresql.service; then
|
||||||
|
echo "postgresql is not running, skipping checkpoint" >&2
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ${pkgs.coreutils}/bin/timeout 120 \
|
||||||
|
${pkgs.util-linux}/bin/runuser -u postgres -- \
|
||||||
|
${lib.getExe' config.services.postgresql.package "psql"} \
|
||||||
|
-v ON_ERROR_STOP=1 -c "CHECKPOINT" 2>&1; then
|
||||||
|
echo "postgresql checkpoint completed"
|
||||||
|
else
|
||||||
|
echo "WARNING: postgresql checkpoint failed, snapshot may be inconsistent" >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Always exit 0 — sanoid must run regardless
|
||||||
|
exit 0
|
||||||
|
'';
|
||||||
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
(lib.serviceMountWithZpool "postgresql" service_configs.zpool_ssds [
|
(lib.serviceMountWithZpool "postgresql" service_configs.zpool_ssds [
|
||||||
@@ -29,4 +53,10 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Run a PostgreSQL CHECKPOINT before sanoid snapshots so the on-disk
|
||||||
|
# state is consistent (required since full_page_writes = false).
|
||||||
|
systemd.services.sanoid.serviceConfig = {
|
||||||
|
ExecStartPre = lib.mkAfter [ "+${pgCheckpoint}" ];
|
||||||
|
TimeoutStartSec = lib.mkForce 300; # checkpoint can be slow with large txg_timeout
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
services.qbittorrent = {
|
services.qbittorrent = {
|
||||||
enable = true;
|
enable = true;
|
||||||
webuiPort = service_configs.ports.torrent;
|
webuiPort = service_configs.ports.private.torrent.port;
|
||||||
profileDir = "/var/lib/qBittorrent";
|
profileDir = "/var/lib/qBittorrent";
|
||||||
# Set the service group to 'media' so the systemd unit runs with media as
|
# Set the service group to 'media' so the systemd unit runs with media as
|
||||||
# the primary GID. Linux assigns new file ownership from the process's GID
|
# the primary GID. Linux assigns new file ownership from the process's GID
|
||||||
|
|||||||
@@ -30,11 +30,11 @@
|
|||||||
|
|
||||||
settings = {
|
settings = {
|
||||||
web = {
|
web = {
|
||||||
port = service_configs.ports.soulseek_web;
|
port = service_configs.ports.private.soulseek_web.port;
|
||||||
};
|
};
|
||||||
soulseek = {
|
soulseek = {
|
||||||
# description = "smth idk";
|
# description = "smth idk";
|
||||||
listen_port = service_configs.ports.soulseek_listen;
|
listen_port = service_configs.ports.public.soulseek_listen.port;
|
||||||
};
|
};
|
||||||
|
|
||||||
shares = {
|
shares = {
|
||||||
@@ -64,6 +64,6 @@
|
|||||||
'';
|
'';
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [
|
networking.firewall.allowedTCPPorts = [
|
||||||
service_configs.ports.soulseek_listen
|
service_configs.ports.public.soulseek_listen.port
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
dataDir = service_configs.syncthing.dataDir;
|
dataDir = service_configs.syncthing.dataDir;
|
||||||
|
|
||||||
guiAddress = "127.0.0.1:${toString service_configs.ports.syncthing_gui}";
|
guiAddress = "127.0.0.1:${toString service_configs.ports.private.syncthing_gui.port}";
|
||||||
|
|
||||||
overrideDevices = false;
|
overrideDevices = false;
|
||||||
overrideFolders = false;
|
overrideFolders = false;
|
||||||
@@ -42,16 +42,16 @@
|
|||||||
|
|
||||||
# Open firewall ports for syncthing protocol
|
# Open firewall ports for syncthing protocol
|
||||||
networking.firewall = {
|
networking.firewall = {
|
||||||
allowedTCPPorts = [ service_configs.ports.syncthing_protocol ];
|
allowedTCPPorts = [ service_configs.ports.public.syncthing_protocol.port ];
|
||||||
allowedUDPPorts = [
|
allowedUDPPorts = [
|
||||||
service_configs.ports.syncthing_discovery
|
service_configs.ports.public.syncthing_discovery.port
|
||||||
service_configs.ports.syncthing_protocol
|
service_configs.ports.public.syncthing_protocol.port
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
services.caddy.virtualHosts."syncthing.${service_configs.https.domain}".extraConfig = ''
|
services.caddy.virtualHosts."syncthing.${service_configs.https.domain}".extraConfig = ''
|
||||||
import ${config.age.secrets.caddy_auth.path}
|
import ${config.age.secrets.caddy_auth.path}
|
||||||
reverse_proxy :${toString service_configs.ports.syncthing_gui}
|
reverse_proxy :${toString service_configs.ports.private.syncthing_gui.port}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ in
|
|||||||
|
|
||||||
pools = [
|
pools = [
|
||||||
{
|
{
|
||||||
url = "127.0.0.1:${builtins.toString service_configs.ports.p2pool_stratum}";
|
url = "127.0.0.1:${builtins.toString service_configs.ports.private.p2pool_stratum.port}";
|
||||||
tls = false;
|
tls = false;
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -12,7 +12,10 @@ let
|
|||||||
dir = "/var/lib/gitea";
|
dir = "/var/lib/gitea";
|
||||||
domain = "git.test.local";
|
domain = "git.test.local";
|
||||||
};
|
};
|
||||||
ports.gitea = 3000;
|
ports.private.gitea = {
|
||||||
|
port = 3000;
|
||||||
|
proto = "tcp";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
testLib = lib.extend (
|
testLib = lib.extend (
|
||||||
|
|||||||
@@ -9,7 +9,10 @@ let
|
|||||||
testServiceConfigs = lib.recursiveUpdate baseServiceConfigs {
|
testServiceConfigs = lib.recursiveUpdate baseServiceConfigs {
|
||||||
zpool_ssds = "";
|
zpool_ssds = "";
|
||||||
https.domain = "test.local";
|
https.domain = "test.local";
|
||||||
ports.immich = 2283;
|
ports.private.immich = {
|
||||||
|
port = 2283;
|
||||||
|
proto = "tcp";
|
||||||
|
};
|
||||||
immich.dir = "/var/lib/immich";
|
immich.dir = "/var/lib/immich";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user