modules.system.sops: rewrite

This commit is contained in:
2025-07-12 10:18:28 +08:00
parent f9dc3d7357
commit 3e1b621434
38 changed files with 960 additions and 871 deletions

View File

@@ -40,7 +40,7 @@
dns-push = pkgs.callPackage ./dns
{
inherit localLib;
tokenPath = inputs.self.nixosConfigurations.pc.config.sops.secrets."acme/token".path;
tokenPath = inputs.self.nixosConfigurations.pc.config.nixos.system.sops.secrets."acme/token".path;
octodns = pkgs.octodns.withProviders (_: with pkgs.octodns-providers; [ cloudflare ]);
};
archive =

View File

@@ -34,21 +34,21 @@ inputs:
name = builtins.elemAt cert.value.domains 0;
value =
{
credentialsFile = inputs.config.sops.templates."acme/cloudflare.ini".path;
credentialsFile = inputs.config.nixos.system.sops.templates."acme/cloudflare.ini".path;
extraDomainNames = builtins.tail cert.value.domains;
group = inputs.lib.mkIf (cert.value.group != null) cert.value.group;
};
})
(inputs.localLib.attrsToList acme.cert));
};
sops =
nixos.system.sops =
{
templates."acme/cloudflare.ini".content =
''
CLOUDFLARE_DNS_API_TOKEN=${inputs.config.sops.placeholder."acme/token"}
CLOUDFLARE_DNS_API_TOKEN=${inputs.config.nixos.system.sops.placeholder."acme/token"}
CLOUDFLARE_PROPAGATION_TIMEOUT=300
'';
secrets."acme/token".sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/default.yaml";
secrets."acme/token" = {};
};
};
}

View File

@@ -14,14 +14,17 @@ inputs:
{
enable = true;
use-auth-secret = true;
static-auth-secret-file = inputs.config.sops.secrets."coturn/auth-secret".path;
static-auth-secret-file = inputs.config.nixos.system.sops.secrets."coturn/auth-secret".path;
realm = coturn.hostname;
cert = "${keydir}/full.pem";
pkey = "${keydir}/key.pem";
no-cli = true;
};
sops.secrets."coturn/auth-secret".owner = inputs.config.systemd.services.coturn.serviceConfig.User;
nixos.services.acme.cert.${coturn.hostname}.group = inputs.config.systemd.services.coturn.serviceConfig.Group;
nixos =
{
system.sops.secrets."coturn/auth-secret".owner = inputs.config.systemd.services.coturn.serviceConfig.User;
services.acme.cert.${coturn.hostname}.group = inputs.config.systemd.services.coturn.serviceConfig.Group;
};
networking.firewall = with inputs.config.services.coturn;
{
allowedUDPPorts = [ listening-port tls-listening-port ];

View File

@@ -15,19 +15,18 @@ inputs:
enable = true;
baseUrl = "https://${freshrss.hostname}";
defaultUser = "chn";
passwordFile = inputs.config.sops.secrets."freshrss/chn".path;
database = { type = "mysql"; passFile = inputs.config.sops.secrets."freshrss/db".path; };
};
sops.secrets =
{
"freshrss/chn".owner = inputs.config.users.users.freshrss.name;
"freshrss/db" = { owner = inputs.config.users.users.freshrss.name; key = "mariadb/freshrss"; };
passwordFile = inputs.config.nixos.system.sops.secrets."freshrss/chn".path;
database = { type = "mysql"; passFile = inputs.config.nixos.system.sops.secrets."freshrss/db".path; };
};
systemd.services.freshrss-config.after = [ "mysql.service" ];
nixos.services =
nixos =
{
mariadb = { enable = true; instances.freshrss = {}; };
nginx.https.${freshrss.hostname}.global.configName = "freshrss";
services = { mariadb.instances.freshrss = {}; nginx.https.${freshrss.hostname}.global.configName = "freshrss"; };
system.sops.secrets =
{
"freshrss/chn".owner = inputs.config.users.users.freshrss.name;
"freshrss/db" = { owner = inputs.config.users.users.freshrss.name; key = "mariadb/freshrss"; };
};
};
};
}

View File

@@ -19,9 +19,13 @@ inputs:
{
enable = true;
lfs.enable = true;
mailerPasswordFile = inputs.config.sops.secrets."gitea/mail".path;
mailerPasswordFile = inputs.config.nixos.system.sops.secrets."gitea/mail".path;
database =
{ createDatabase = false; type = "postgres"; passwordFile = inputs.config.sops.secrets."gitea/db".path; };
{
createDatabase = false;
type = "postgres";
passwordFile = inputs.config.nixos.system.sops.secrets."gitea/db".path;
};
settings =
{
session.COOKIE_SECURE = true;
@@ -48,26 +52,29 @@ inputs:
[ "DEFAULT" "MIGRATE" "MIRROR" "CLONE" "PULL" "GC" ]);
};
};
nixos.services =
nixos =
{
nginx.https.${gitea.hostname}.location =
system.sops.secrets =
{
"/".proxy.upstream = "http://127.0.0.1:3002";
"/robots.txt".static.root =
let robotsFile = inputs.pkgs.fetchurl
{
url = "https://gitea.com/robots.txt";
sha256 = "144c5s3la4a85c9lygcnxhbxs3w5y23bkhhqx69fbp9yiqyxdkk2";
};
in "${inputs.pkgs.runCommand "robots.txt" {} "mkdir -p $out; cp ${robotsFile} $out/robots.txt"}";
"gitea/mail" = { owner = "gitea"; key = "mail/bot"; };
"gitea/db" = { owner = "gitea"; key = "postgresql/gitea"; };
"mail/bot" = {};
};
services =
{
nginx.https.${gitea.hostname}.location =
{
"/".proxy.upstream = "http://127.0.0.1:3002";
"/robots.txt".static.root =
let robotsFile = inputs.pkgs.fetchurl
{
url = "https://gitea.com/robots.txt";
sha256 = "144c5s3la4a85c9lygcnxhbxs3w5y23bkhhqx69fbp9yiqyxdkk2";
};
in "${inputs.pkgs.runCommand "robots.txt" {} "mkdir -p $out; cp ${robotsFile} $out/robots.txt"}";
};
postgresql.instances.gitea = {};
};
postgresql.instances.gitea = {};
};
sops.secrets =
{
"gitea/mail" = { owner = "gitea"; key = "mail/bot"; };
"gitea/db" = { owner = "gitea"; key = "postgresql/gitea"; };
"mail/bot" = {};
};
};
}

View File

@@ -24,7 +24,7 @@ inputs:
enabled = true;
host = "mail.chn.moe";
user = "bot@chn.moe";
password = "$__file{${inputs.config.sops.secrets."grafana/mail".path}}";
password = "$__file{${inputs.config.nixos.system.sops.secrets."grafana/mail".path}}";
from_address = "bot@chn.moe";
ehlo_identity = grafana.hostname;
startTLS_policy = "MandatoryStartTLS";
@@ -32,9 +32,9 @@ inputs:
server = { root_url = "https://${grafana.hostname}"; http_port = 3001; enable_gzip = true; };
security =
{
secret_key = "$__file{${inputs.config.sops.secrets."grafana/secret".path}}";
secret_key = "$__file{${inputs.config.nixos.system.sops.secrets."grafana/secret".path}}";
admin_user = "chn";
admin_password = "$__file{${inputs.config.sops.secrets."grafana/chn".path}}";
admin_password = "$__file{${inputs.config.nixos.system.sops.secrets."grafana/chn".path}}";
admin_email = "chn@chn.moe";
};
database =
@@ -42,7 +42,7 @@ inputs:
type = "postgres";
host = "127.0.0.1:5432";
user = "grafana";
password = "$__file{${inputs.config.sops.secrets."grafana/db".path}}";
password = "$__file{${inputs.config.nixos.system.sops.secrets."grafana/db".path}}";
};
};
provision =
@@ -78,18 +78,21 @@ inputs:
extraFlags = [ "--storage.tsdb.max-block-chunk-segment-size=16MB" ];
};
};
nixos.services =
nixos =
{
nginx.https.${grafana.hostname}.location."/".proxy = { upstream = "http://127.0.0.1:3001"; websocket = true; };
postgresql.instances.grafana = {};
};
sops.secrets = let owner = inputs.config.systemd.services.grafana.serviceConfig.User; in
{
"grafana/mail" = { owner = owner; key = "mail/bot"; };
"grafana/secret".owner = owner;
"grafana/chn".owner = owner;
"grafana/db" = { owner = owner; key = "postgresql/grafana"; };
"mail/bot" = {};
services =
{
nginx.https.${grafana.hostname}.location."/".proxy = { upstream = "http://127.0.0.1:3001"; websocket = true; };
postgresql.instances.grafana = {};
};
system.sops.secrets = let owner = inputs.config.systemd.services.grafana.serviceConfig.User; in
{
"grafana/mail" = { owner = owner; key = "mail/bot"; };
"grafana/secret".owner = owner;
"grafana/chn".owner = owner;
"grafana/db" = { owner = owner; key = "postgresql/grafana"; };
"mail/bot" = {};
};
};
environment.persistence."/nix/nodatacow".directories =
[{ directory = "/var/lib/prometheus2"; user = "prometheus"; group = "prometheus"; mode = "0700"; }];

View File

@@ -15,13 +15,13 @@ inputs:
grep = "${inputs.pkgs.gnugrep}/bin/grep";
curl = "${inputs.pkgs.curl}/bin/curl";
cat = "${inputs.pkgs.coreutils}/bin/cat";
token = inputs.config.sops.secrets."telegram/token".path;
chat = inputs.config.sops.secrets."telegram/user/chn".path;
token = inputs.config.nixos.system.sops.secrets."telegram/token".path;
chat = inputs.config.nixos.system.sops.secrets."telegram/user/chn".path;
date = "${inputs.pkgs.coreutils}/bin/date";
hpcstat = "${inputs.pkgs.localPackages.hpcstat}/bin/hpcstat";
ssh = "${inputs.pkgs.openssh}/bin/ssh -i ${key} -o StrictHostKeyChecking=no"
+ " -o ForwardAgent=yes -o AddKeysToAgent=yes";
key = inputs.config.sops.secrets."hpcstat/key".path;
key = inputs.config.nixos.system.sops.secrets."hpcstat/key".path;
jykang = "${inputs.topInputs.self}/devices/jykang.xmuhpc/files";
ssh-agent = "${inputs.pkgs.openssh}/bin/ssh-agent";
in
@@ -105,10 +105,10 @@ inputs:
(inputs.localLib.attrsToList calenders));
tmpfiles.rules = [ "d /var/lib/hpcstat 0700 hpcstat hpcstat" ];
};
sops.secrets = let sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/default.yaml"; in
nixos.system.sops.secrets =
{
"telegram/token" = { group = "telegram"; mode = "0440"; inherit sopsFile; };
"telegram/user/chn" = { group = "telegram"; mode = "0440"; inherit sopsFile; };
"telegram/token" = { group = "telegram"; mode = "0440"; };
"telegram/user/chn" = { group = "telegram"; mode = "0440"; };
"hpcstat/key" = { owner = "hpcstat"; group = "hpcstat"; };
};
users =

View File

@@ -10,35 +10,37 @@ inputs:
};
config = let inherit (inputs.config.nixos.services) httpapi; in inputs.lib.mkIf (httpapi != null)
{
nixos.services =
nixos =
{
phpfpm.instances.httpapi = {};
nginx.https.${httpapi.hostname}.location =
services =
{
"/files".static.root = "/srv/api";
"/led".static = { root = "/srv/api"; detectAuth.users = [ "led" ]; };
"/notify.php".php =
phpfpm.instances.httpapi = {};
nginx.https.${httpapi.hostname}.location =
{
root = builtins.dirOf inputs.config.sops.templates."httpapi/notify.php".path;
fastcgiPass = inputs.config.nixos.services.phpfpm.instances.httpapi.fastcgi;
"/files".static.root = "/srv/api";
"/led".static = { root = "/srv/api"; detectAuth.users = [ "led" ]; };
"/notify.php".php =
{
root = builtins.dirOf inputs.config.nixos.system.sops.templates."httpapi/notify.php".path;
fastcgiPass = inputs.config.nixos.services.phpfpm.instances.httpapi.fastcgi;
};
};
};
};
sops =
{
templates."httpapi/notify.php" =
system.sops =
{
owner = inputs.config.users.users.httpapi.name;
group = inputs.config.users.users.httpapi.group;
content =
let
placeholder = inputs.config.sops.placeholder;
request = "https://api.telegram.org/bot${placeholder."telegram/token"}"
+ "/sendMessage?chat_id=${placeholder."telegram/user/chn"}&text=";
in ''<?php print file_get_contents("${request}".urlencode($_GET["message"])); ?>'';
templates."httpapi/notify.php" =
{
owner = inputs.config.users.users.httpapi.name;
group = inputs.config.users.users.httpapi.group;
content =
let
inherit (inputs.config.sops) placeholder;
request = "https://api.telegram.org/bot${placeholder."telegram/token"}"
+ "/sendMessage?chat_id=${placeholder."telegram/user/chn"}&text=";
in ''<?php print file_get_contents("${request}".urlencode($_GET["message"])); ?>'';
};
secrets = { "telegram/token" = {}; "telegram/user/chn" = {}; };
};
secrets = let sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/default.yaml"; in
{ "telegram/token" = { inherit sopsFile; }; "telegram/user/chn" = { inherit sopsFile; }; };
};
systemd.tmpfiles.rules = [ "d /srv/api 0700 nginx nginx" "Z /srv/api - nginx nginx" ];
};

View File

@@ -15,30 +15,7 @@ inputs:
image = "ghcr.io/huginn/huginn:latest";
imageFile = inputs.topInputs.self.src.huginn;
ports = [ "127.0.0.1:3000:3000/tcp" ];
environmentFiles = [ inputs.config.sops.templates."huginn/env".path ];
};
sops =
{
templates."huginn/env".content = let placeholder = inputs.config.sops.placeholder; in
''
MYSQL_PORT_3306_TCP_ADDR=host.containers.internal
HUGINN_DATABASE_NAME=huginn
HUGINN_DATABASE_USERNAME=huginn
HUGINN_DATABASE_PASSWORD=${placeholder."mariadb/huginn"}
DOMAIN=${huginn.hostname}
RAILS_ENV=production
FORCE_SSL=true
INVITATION_CODE=${placeholder."huginn/invitationCode"}
SMTP_DOMAIN=mail.chn.moe
SMTP_USER_NAME=bot@chn.moe
SMTP_PASSWORD="${placeholder."mail/bot"}"
SMTP_SERVER=mail.chn.moe
SMTP_SSL=true
EMAIL_FROM_ADDRESS=bot@chn.moe
TIMEZONE=Beijing
DO_NOT_CREATE_DATABASE=true
'';
secrets = { "huginn/invitationCode" = {}; "mail/bot" = {}; };
environmentFiles = [ inputs.config.nixos.system.sops.templates."huginn/env".path ];
};
nixos =
{
@@ -48,6 +25,29 @@ inputs:
mariadb.instances.huginn = {};
podman = {};
};
system.sops =
{
templates."huginn/env".content = let inherit (inputs.config.nixos.system.sops) placeholder; in
''
MYSQL_PORT_3306_TCP_ADDR=host.containers.internal
HUGINN_DATABASE_NAME=huginn
HUGINN_DATABASE_USERNAME=huginn
HUGINN_DATABASE_PASSWORD=${placeholder."mariadb/huginn"}
DOMAIN=${huginn.hostname}
RAILS_ENV=production
FORCE_SSL=true
INVITATION_CODE=${placeholder."huginn/invitationCode"}
SMTP_DOMAIN=mail.chn.moe
SMTP_USER_NAME=bot@chn.moe
SMTP_PASSWORD="${placeholder."mail/bot"}"
SMTP_SERVER=mail.chn.moe
SMTP_SSL=true
EMAIL_FROM_ADDRESS=bot@chn.moe
TIMEZONE=Beijing
DO_NOT_CREATE_DATABASE=true
'';
secrets = { "huginn/invitationCode" = {}; "mail/bot" = {}; };
};
};
};
}

View File

@@ -40,13 +40,13 @@ inputs:
let
passwordFile =
if db.value.passwordFile or null != null then db.value.passwordFile
else inputs.config.sops.secrets."mariadb/${db.value.user}".path;
else inputs.config.nixos.system.sops.secrets."mariadb/${db.value.user}".path;
mysql = "${inputs.config.services.mysql.package}/bin/mysql";
in
# force user use password auth
''echo "ALTER USER '${db.value.user}' IDENTIFIED BY '$(cat ${passwordFile})';" | ${mysql} -N'')
(inputs.localLib.attrsToList mariadb.instances)));
sops.secrets = builtins.listToAttrs (builtins.map
nixos.system.sops.secrets = builtins.listToAttrs (builtins.map
(db: { name = "mariadb/${db.value.user}"; value.owner = inputs.config.users.users.mysql.name; })
(builtins.filter (db: db.value.passwordFile == null) (inputs.localLib.attrsToList mariadb.instances)));
environment.persistence."/nix/nodatacow".directories =

View File

@@ -22,7 +22,8 @@ inputs:
after = [ "network.target" "redis-misskey-${instance.name}.service" "postgresql.service" ];
requires = after;
wantedBy = [ "multi-user.target" ];
environment.MISSKEY_CONFIG_YML = inputs.config.sops.templates."misskey/${instance.name}.yml".path;
environment.MISSKEY_CONFIG_YML =
inputs.config.nixos.system.sops.templates."misskey/${instance.name}.yml".path;
serviceConfig = rec
{
User = "misskey-${instance.name}";
@@ -53,50 +54,6 @@ inputs:
};
})
(inputs.localLib.attrsToList misskey.instances));
sops.templates = builtins.listToAttrs (builtins.map
(instance:
{
name = "misskey/${instance.name}.yml";
value =
{
content =
let
placeholder = inputs.config.sops.placeholder;
redis = inputs.config.nixos.services.redis.instances."misskey-${instance.name}";
in
''
url: https://${instance.value.hostname}/
port: ${toString instance.value.port}
db:
host: 127.0.0.1
port: 5432
db: misskey_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}
user: misskey_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}
pass: ${placeholder."postgresql/misskey_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}"}
extra:
statement_timeout: 600000
dbReplications: false
redis:
host: 127.0.0.1
port: ${builtins.toString redis.port}
pass: ${placeholder."redis/misskey-${instance.name}"}
id: 'aid'
proxyBypassHosts:
- api.deepl.com
- api-free.deepl.com
- www.recaptcha.net
- hcaptcha.com
- challenges.cloudflare.com
proxyRemoteFiles: true
signToActivityPubGet: true
maxFileSize: 1073741824
fulltextSearch:
provider: sqlPgroonga
'';
owner = "misskey-${instance.name}";
};
})
(inputs.localLib.attrsToList misskey.instances));
users = inputs.lib.mkMerge (builtins.map
(instance:
{
@@ -111,19 +68,66 @@ inputs:
groups."misskey-${instance.name}".gid = inputs.config.nixos.user.gid."misskey-${instance.name}";
})
(inputs.localLib.attrsToList misskey.instances));
nixos.services =
nixos =
{
redis.instances = builtins.listToAttrs (builtins.map
(instance: { name = "misskey-${instance.name}"; value.port = instance.value.redis.port; })
(inputs.localLib.attrsToList misskey.instances));
postgresql.instances = builtins.listToAttrs (builtins.map
(instance: { name = "misskey_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}"; value = {}; })
(inputs.localLib.attrsToList misskey.instances));
nginx.https = builtins.listToAttrs (builtins.map
(instance: with instance.value;
services =
{
redis.instances = builtins.listToAttrs (builtins.map
(instance: { name = "misskey-${instance.name}"; value.port = instance.value.redis.port; })
(inputs.localLib.attrsToList misskey.instances));
postgresql.instances = builtins.listToAttrs (builtins.map
(instance: { name = "misskey_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}"; value = {}; })
(inputs.localLib.attrsToList misskey.instances));
nginx.https = builtins.listToAttrs (builtins.map
(instance: with instance.value;
{
name = hostname;
value.location."/".proxy = { upstream = "http://127.0.0.1:${toString port}"; websocket = true; };
})
(inputs.localLib.attrsToList misskey.instances));
};
system.sops.templates = builtins.listToAttrs (builtins.map
(instance:
{
name = hostname;
value.location."/".proxy = { upstream = "http://127.0.0.1:${toString port}"; websocket = true; };
name = "misskey/${instance.name}.yml";
value =
{
content =
let
placeholder = inputs.config.nixos.system.sops.placeholder;
redis = inputs.config.nixos.services.redis.instances."misskey-${instance.name}";
in
''
url: https://${instance.value.hostname}/
port: ${toString instance.value.port}
db:
host: 127.0.0.1
port: 5432
db: misskey_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}
user: misskey_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}
pass: ${placeholder."postgresql/misskey_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}"}
extra:
statement_timeout: 600000
dbReplications: false
redis:
host: 127.0.0.1
port: ${builtins.toString redis.port}
pass: ${placeholder."redis/misskey-${instance.name}"}
id: 'aid'
proxyBypassHosts:
- api.deepl.com
- api-free.deepl.com
- www.recaptcha.net
- hcaptcha.com
- challenges.cloudflare.com
proxyRemoteFiles: true
signToActivityPubGet: true
maxFileSize: 1073741824
fulltextSearch:
provider: sqlPgroonga
'';
owner = "misskey-${instance.name}";
};
})
(inputs.localLib.attrsToList misskey.instances));
};

View File

@@ -21,9 +21,9 @@ inputs:
config =
{
dbtype = "pgsql";
dbpassFile = inputs.config.sops.secrets."nextcloud/postgresql".path;
dbpassFile = inputs.config.nixos.system.sops.secrets."nextcloud/postgresql".path;
adminuser = "admin";
adminpassFile = inputs.config.sops.secrets."nextcloud/admin".path;
adminpassFile = inputs.config.nixos.system.sops.secrets."nextcloud/admin".path;
};
configureRedis = true;
settings =
@@ -39,7 +39,7 @@ inputs:
overwriteprotocol = "https";
default_phone_region = "CN";
};
secretFile = inputs.config.sops.templates."nextcloud/secret".path;
secretFile = inputs.config.nixos.system.sops.templates."nextcloud/secret".path;
extraApps =
let
version = inputs.lib.versions.major inputs.config.services.nextcloud.package.version;
@@ -59,27 +59,30 @@ inputs:
(package: { name = package; value = inputs.pkgs.fetchNextcloudApp (getInfo package); })
[ "phonetrack" "twofactor_webauthn" "calendar" ]);
};
nixos.services =
nixos =
{
postgresql.instances.nextcloud = {};
redis.instances.nextcloud.port = 3499;
nginx.https.${nextcloud.hostname}.global.configName = nextcloud.hostname;
};
sops =
{
templates."nextcloud/secret" =
system.sops =
{
content = builtins.toJSON
templates."nextcloud/secret" =
{
redis.password = inputs.config.sops.placeholder."redis/nextcloud";
mail_smtppassword = inputs.config.sops.placeholder."mail/bot";
content = builtins.toJSON
{
redis.password = inputs.config.nixos.system.sops.placeholder."redis/nextcloud";
mail_smtppassword = inputs.config.nixos.system.sops.placeholder."mail/bot";
};
owner = inputs.config.users.users.nextcloud.name;
};
secrets =
{
"nextcloud/postgresql" = { key = "postgresql/nextcloud"; owner = inputs.config.users.users.nextcloud.name; };
"nextcloud/admin".owner = inputs.config.users.users.nextcloud.name;
};
owner = inputs.config.users.users.nextcloud.name;
};
secrets =
services =
{
"nextcloud/postgresql" = { key = "postgresql/nextcloud"; owner = inputs.config.users.users.nextcloud.name; };
"nextcloud/admin".owner = inputs.config.users.users.nextcloud.name;
postgresql.instances.nextcloud = {};
redis.instances.nextcloud.port = 3499;
nginx.https.${nextcloud.hostname}.global.configName = nextcloud.hostname;
};
};
systemd.services.nextcloud-setup = rec { requires = [ "postgresql.service" ]; after = requires; };

View File

@@ -95,17 +95,13 @@ inputs:
settings =
{
AccountID = 901296;
LicenseKey = inputs.config.sops.secrets."nginx/maxmind-license".path;
LicenseKey = inputs.config.nixos.system.sops.secrets."nginx/maxmind-license".path;
EditionIDs = [ "GeoLite2-ASN" "GeoLite2-City" "GeoLite2-Country" ];
};
};
};
networking.firewall.allowedTCPPorts = [ 80 443 ];
sops.secrets."nginx/maxmind-license" =
{
owner = inputs.config.users.users.nginx.name;
sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/default.yaml";
};
nixos.system.sops.secrets."nginx/maxmind-license".owner = inputs.config.users.users.nginx.name;
systemd.services.nginx.serviceConfig =
{
CapabilityBoundingSet = [ "CAP_NET_ADMIN" ];

View File

@@ -177,7 +177,7 @@ inputs:
basicAuthFile = inputs.lib.mkIf (site.value.global.detectAuth != null)
(
let secret = "nginx/templates/detectAuth/${inputs.lib.strings.escapeURL site.name}-global";
in inputs.config.sops.templates.${secret}.path
in inputs.config.nixos.system.sops.templates.${secret}.path
);
extraConfig = builtins.concatStringsSep "\n"
(
@@ -227,7 +227,7 @@ inputs:
let
inherit (inputs.lib.strings) escapeURL;
secret = "nginx/templates/detectAuth/${escapeURL site.name}/${escapeURL location.name}";
in inputs.config.sops.templates.${secret}.path
in inputs.config.nixos.system.sops.templates.${secret}.path
);
root = inputs.lib.mkIf (location.value.root or null != null) location.value.root;
}
@@ -247,7 +247,7 @@ inputs:
++ (inputs.lib.optionals (location.value.addAuth != null)
(
let authFile = "nginx/templates/addAuth/${location.value.addAuth}";
in [ "include ${inputs.config.sops.templates.${authFile}.path};" ]
in [ "include ${inputs.config.nixos.system.sops.templates.${authFile}.path};" ]
))
);
};
@@ -285,114 +285,108 @@ inputs:
};
})
sites);
nixos.services =
nixos =
{
nginx =
# { name = domain; value = listen = { http2 = xxx, proxyProtocol = xxx }; }
let listens = builtins.filter
(listen: listen.value.addToTransparentProxy)
(builtins.concatLists (builtins.map
(site: builtins.map (listen: { inherit (site) name; value = listen; }) site.value.listens)
sites));
in
{
transparentProxy.map = builtins.listToAttrs (builtins.map
(site:
{
inherit (site) name;
value = with nginx.global; httpsPort + (if site.value.http2 then httpsPortShift.http2 else 0);
})
(builtins.filter (listen: !listen.value.proxyProtocol) listens));
streamProxy.map = builtins.listToAttrs (builtins.map
(site:
{
inherit (site) name;
value =
services =
{
nginx =
# { name = domain; value = listen = { http2 = xxx, proxyProtocol = xxx }; }
let listens = builtins.filter
(listen: listen.value.addToTransparentProxy)
(builtins.concatLists (builtins.map
(site: builtins.map (listen: { inherit (site) name; value = listen; }) site.value.listens)
sites));
in
{
transparentProxy.map = builtins.listToAttrs (builtins.map
(site:
{
upstream.port = with nginx.global; httpsPort + httpsPortShift.proxyProtocol
+ (if site.value.http2 then httpsPortShift.http2 else 0);
proxyProtocol = true;
rewriteHttps = inputs.lib.mkDefault false;
};
})
(builtins.filter (listen: listen.value.proxyProtocol) listens));
http = builtins.listToAttrs (builtins.map
(site: { inherit (site) name; value.rewriteHttps = {}; })
(builtins.filter (site: site.value.global.rewriteHttps) sites));
};
acme.cert = builtins.listToAttrs (builtins.map
(site: { inherit (site) name; value.group = inputs.config.services.nginx.group; })
sites);
};
sops =
let
inherit (inputs.lib.strings) escapeURL;
detectAuthUsers = builtins.concatLists (builtins.map
(site:
(
(builtins.map
inherit (site) name;
value = with nginx.global; httpsPort + (if site.value.http2 then httpsPortShift.http2 else 0);
})
(builtins.filter (listen: !listen.value.proxyProtocol) listens));
streamProxy.map = builtins.listToAttrs (builtins.map
(site:
{
inherit (site) name;
value =
{
upstream.port = with nginx.global; httpsPort + httpsPortShift.proxyProtocol
+ (if site.value.http2 then httpsPortShift.http2 else 0);
proxyProtocol = true;
rewriteHttps = inputs.lib.mkDefault false;
};
})
(builtins.filter (listen: listen.value.proxyProtocol) listens));
http = builtins.listToAttrs (builtins.map
(site: { inherit (site) name; value.rewriteHttps = {}; })
(builtins.filter (site: site.value.global.rewriteHttps) sites));
};
acme.cert = builtins.listToAttrs (builtins.map
(site: { inherit (site) name; value.group = inputs.config.services.nginx.group; })
sites);
};
system.sops =
let
inherit (inputs.lib.strings) escapeURL;
detectAuthUsers = builtins.concatLists (builtins.map
(site:
(
(builtins.map
(location:
{
name = "${escapeURL site.name}/${escapeURL location.name}";
value = location.value.detectAuth.users;
})
(builtins.filter (location: location.value.detectAuth or null != null) site.value.locations))
++ (inputs.lib.optionals (site.value.global.detectAuth != null)
[ { name = "${escapeURL site.name}-global"; value = site.value.global.detectAuth.users; } ])
))
sites);
addAuth = builtins.concatLists (builtins.map
(site: builtins.map
(location:
{
name = "${escapeURL site.name}/${escapeURL location.name}";
value = location.value.detectAuth.users;
value = location.value.addAuth;
})
(builtins.filter (location: location.value.detectAuth or null != null) site.value.locations))
++ (inputs.lib.optionals (site.value.global.detectAuth != null)
[ { name = "${escapeURL site.name}-global"; value = site.value.global.detectAuth.users; } ])
))
sites);
addAuth = builtins.concatLists (builtins.map
(site: builtins.map
(location:
{
name = "${escapeURL site.name}/${escapeURL location.name}";
value = location.value.addAuth;
})
(builtins.filter (location: location.value.addAuth or null != null) site.value.locations)
)
sites);
in
{
templates = builtins.listToAttrs
(
(builtins.map
(detectAuth:
{
name = "nginx/templates/detectAuth/${detectAuth.name}";
value =
(builtins.filter (location: location.value.addAuth or null != null) site.value.locations)
)
sites);
in
{
templates = let inherit (inputs.config.nixos.system.sops) placeholder; in builtins.listToAttrs
(
(builtins.map
(detectAuth: inputs.lib.nameValuePair "nginx/templates/detectAuth/${detectAuth.name}"
{
owner = inputs.config.users.users.nginx.name;
content = builtins.concatStringsSep "\n" (builtins.map
(user: "${user}:{PLAIN}${inputs.config.sops.placeholder."nginx/detectAuth/${user}"}")
(user: "${user}:{PLAIN}${placeholder."nginx/detectAuth/${user}"}")
detectAuth.value);
};
})
detectAuthUsers)
++ (builtins.map
(addAuth:
{
name = "nginx/templates/addAuth/${addAuth.name}";
value =
})
detectAuthUsers)
++ (builtins.map
(addAuth: inputs.lib.nameValuePair "nginx/templates/addAuth/${addAuth.name}"
{
owner = inputs.config.users.users.nginx.name;
content =
let placeholder = inputs.config.sops.placeholder."nginx/addAuth/${addAuth.value}";
in ''proxy_set_header Authorization "Basic ${placeholder}";'';
};
})
addAuth)
);
secrets = builtins.listToAttrs
(
(builtins.map
(secret: { name = "nginx/detectAuth/${secret}"; value = {}; })
(inputs.lib.unique (builtins.concatLists (builtins.map (detectAuth: detectAuth.value)
detectAuthUsers))))
++ (builtins.map
(secret: { name = "nginx/addAuth/${secret}"; value = {}; })
(inputs.lib.unique (builtins.map (addAuth: addAuth.value) addAuth)))
);
};
''proxy_set_header Authorization "Basic ${placeholder."nginx/addAuth/${addAuth.value}"}";'';
})
addAuth)
);
secrets = builtins.listToAttrs
(
(builtins.map
(secret: { name = "nginx/detectAuth/${secret}"; value = {}; })
(inputs.lib.unique (builtins.concatLists (builtins.map (detectAuth: detectAuth.value)
detectAuthUsers))))
++ (builtins.map
(secret: { name = "nginx/addAuth/${secret}"; value = {}; })
(inputs.lib.unique (builtins.map (addAuth: addAuth.value) addAuth)))
);
};
};
}
)
]);

View File

@@ -15,12 +15,15 @@ inputs:
enable = true;
package = inputs.pkgs.nix-serve-ng;
openFirewall = true;
secretKeyFile = inputs.config.sops.secrets."store/signingKey".path;
secretKeyFile = inputs.config.nixos.system.sops.secrets."store/signingKey".path;
# curl -L cache.nixos.org/nix-cache-info
# use this cache after official one
extraParams = "--priority 50";
};
sops.secrets."store/signingKey" = {};
nixos.services.nginx.https.${nix-serve.hostname}.location."/".proxy.upstream = "http://127.0.0.1:5000";
nixos =
{
system.sops.secrets."store/signingKey" = {};
services.nginx.https.${nix-serve.hostname}.location."/".proxy.upstream = "http://127.0.0.1:5000";
};
};
}

View File

@@ -83,7 +83,7 @@ inputs:
domains = builtins.map
(vm:
{
definition = inputs.config.sops.templates."nixvirt/${vm.name}.xml".path;
definition = inputs.config.nixos.system.sops.templates."nixvirt/${vm.name}.xml".path;
active = true;
restart = false;
})
@@ -122,146 +122,142 @@ inputs:
vnc_listen = "0.0.0.0"
'';
};
nixos.services =
nixos =
{
nginx =
let hosts = builtins.concatLists (builtins.map
(vm: builtins.map
(domain:
{
inherit domain;
ip = "192.168.${builtins.toString nixvirt.subnet}.${builtins.toString vm.network.address}";
})
vm.network.portForward.web)
(builtins.attrValues nixvirt.instance));
in
{
transparentProxy.map = builtins.listToAttrs (builtins.map
(host: { name = host.domain; value = "${host.ip}" + ":443"; }) hosts);
http = builtins.listToAttrs (builtins.map
(host: { name = host.domain; value.proxy.upstream = "http://${host.ip}" + ":80"; }) hosts);
};
kvm = {};
};
sops =
{
templates = builtins.listToAttrs (builtins.map
(vm:
{
name = "nixvirt/${vm.name}.xml";
value.content = inputs.topInputs.nixvirt.lib.domain.getXML
# port from 8bcc23e27a62297254d0e9c87281e650ff777132
system.sops =
{
templates = inputs.lib.mapAttrs'
(n: v: inputs.lib.nameValuePair "nixvirt/${n}.xml"
{
inherit (vm) name;
inherit (vm.value) uuid;
type = "kvm";
vcpu = { placement = "static"; count = vm.value.cpu.count; };
cputune = inputs.lib.optionalAttrs (vm.value.cpu.set != null)
content = inputs.topInputs.nixvirt.lib.domain.getXML
# port from 8bcc23e27a62297254d0e9c87281e650ff777132
{
vcpupin = builtins.genList
(cpu: { vcpu = cpu; cpuset = builtins.elemAt vm.value.cpu.set cpu; })
vm.value.cpu.count;
};
memory =
{
count = vm.value.memory.sizeMB;
unit = "MiB";
nosharepages = vm.value.memory.dedicated;
locked = vm.value.memory.dedicated;
};
os =
{
type = "hvm";
arch = "x86_64";
machine = "q35";
bootmenu = { enable = true; timeout = 15000; };
loader = { readonly = true; type = "pflash"; path = "/run/libvirt/nix-ovmf/OVMF_CODE.fd"; };
nvram =
name = n;
inherit (v) uuid;
type = "kvm";
vcpu = { placement = "static"; count = v.cpu.count; };
cputune = inputs.lib.optionalAttrs (v.cpu.set != null)
{
template = "/run/libvirt/nix-ovmf/OVMF_VARS.fd";
path = "/var/lib/libvirt/qemu/nvram/${vm.name}_VARS.fd";
templateFormat = "raw";
format = "raw";
vcpupin = builtins.genList (cpu: { vcpu = cpu; cpuset = builtins.elemAt v.cpu.set cpu; }) v.cpu.count;
};
};
features = { acpi = {}; apic = {}; };
cpu =
{
mode = "host-passthrough";
topology =
memory =
{
sockets = 1;
dies = 1;
cores = if vm.value.cpu.hyprthread then vm.value.cpu.count / 2 else vm.value.cpu.count;
threads = if vm.value.cpu.hyprthread then 2 else 1;
count = v.memory.sizeMB;
unit = "MiB";
nosharepages = v.memory.dedicated;
locked = v.memory.dedicated;
};
};
clock =
{
offset = "utc";
timer =
[
{ name = "rtc"; tickpolicy = "catchup"; }
{ name = "pit"; tickpolicy = "delay"; }
{ name = "hpet"; present = false; }
];
};
devices =
{
emulator = "${inputs.config.virtualisation.libvirtd.qemu.package}/bin/qemu-system-x86_64";
disk =
[
os =
{
type = "hvm";
arch = "x86_64";
machine = "q35";
bootmenu = { enable = true; timeout = 15000; };
loader = { readonly = true; type = "pflash"; path = "/run/libvirt/nix-ovmf/OVMF_CODE.fd"; };
nvram =
{
type = "file";
device = "disk";
driver = { name = "qemu"; type = "raw"; cache = "writeback"; discard = "unmap"; };
source.file = "${if vm.value.storage.nodatacow then "/nix/nodatacow" else ""}/var/lib/libvirt/images/"
+ "${vm.value.storage.name}.img";
target = { dev = "vda"; bus = "virtio"; };
boot.order = 1;
}
template = "/run/libvirt/nix-ovmf/OVMF_VARS.fd";
path = "/var/lib/libvirt/qemu/nvram/${n}_VARS.fd";
templateFormat = "raw";
format = "raw";
};
};
features = { acpi = {}; apic = {}; };
cpu =
{
mode = "host-passthrough";
topology =
{
type = "file";
device = "cdrom";
driver = { name = "qemu"; type = "raw"; };
source.file = "${inputs.topInputs.self.src.iso.netboot}";
target = { dev = "sdc"; bus = "sata"; };
readonly = true;
boot.order = 10;
}
];
interface =
{
type = "bridge";
model.type = "virtio";
mac.address = vm.value.network.mac;
source.bridge = if vm.value.network.bridge then "nixvirt" else "virbr0";
sockets = 1;
dies = 1;
cores = if v.cpu.hyprthread then v.cpu.count / 2 else v.cpu.count;
threads = if v.cpu.hyprthread then 2 else 1;
};
};
input =
[
{ type = "tablet"; bus = "usb"; }
{ type = "mouse"; bus = "ps2"; }
{ type = "keyboard"; bus = "ps2"; }
];
graphics =
clock =
{
type = "vnc";
autoport = false;
port = vm.value.network.vnc.port;
listen.type = "address";
passwd = inputs.config.sops.placeholder."nixvirt/${vm.name}";
offset = "utc";
timer =
[
{ name = "rtc"; tickpolicy = "catchup"; }
{ name = "pit"; tickpolicy = "delay"; }
{ name = "hpet"; present = false; }
];
};
devices =
{
emulator = "${inputs.config.virtualisation.libvirtd.qemu.package}/bin/qemu-system-x86_64";
disk =
[
{
type = "file";
device = "disk";
driver = { name = "qemu"; type = "raw"; cache = "writeback"; discard = "unmap"; };
source.file = "${if v.storage.nodatacow then "/nix/nodatacow" else ""}/var/lib/libvirt/images/"
+ "${v.storage.name}.img";
target = { dev = "vda"; bus = "virtio"; };
boot.order = 1;
}
{
type = "file";
device = "cdrom";
driver = { name = "qemu"; type = "raw"; };
source.file = "${inputs.topInputs.self.src.iso.netboot}";
target = { dev = "sdc"; bus = "sata"; };
readonly = true;
boot.order = 10;
}
];
interface =
{
type = "bridge";
model.type = "virtio";
mac.address = v.network.mac;
source.bridge = if v.network.bridge then "nixvirt" else "virbr0";
};
input =
[
{ type = "tablet"; bus = "usb"; }
{ type = "mouse"; bus = "ps2"; }
{ type = "keyboard"; bus = "ps2"; }
];
graphics =
{
type = "vnc";
autoport = false;
port = v.network.vnc.port;
listen.type = "address";
passwd = inputs.config.sops.placeholder."nixvirt/${n}";
};
video.model = { type = "qxl"; ram = 65536; vram = 65536; vgamem = 16384; heads = 1; primary = true; };
rng = { model = "virtio"; backend = { model = "random"; source = /dev/urandom; }; };
};
video.model = { type = "qxl"; ram = 65536; vram = 65536; vgamem = 16384; heads = 1; primary = true; };
rng = { model = "virtio"; backend = { model = "random"; source = /dev/urandom; }; };
};
})
nixvirt.instance;
secrets = inputs.lib.mapAttrs' (n: _: inputs.lib.nameValuePair "nixvirt/${n}" {}) nixvirt.instance;
};
services =
{
nginx =
let hosts = builtins.concatLists (builtins.map
(vm: builtins.map
(domain:
{
inherit domain;
ip = "192.168.${builtins.toString nixvirt.subnet}.${builtins.toString vm.network.address}";
})
vm.network.portForward.web)
(builtins.attrValues nixvirt.instance));
in
{
transparentProxy.map = builtins.listToAttrs (builtins.map
(host: { name = host.domain; value = "${host.ip}" + ":443"; }) hosts);
http = builtins.listToAttrs (builtins.map
(host: { name = host.domain; value.proxy.upstream = "http://${host.ip}" + ":80"; }) hosts);
};
})
(inputs.localLib.attrsToList nixvirt.instance));
secrets = builtins.listToAttrs (builtins.map
(vm: { name = "nixvirt/${vm}"; value = {}; }) (builtins.attrNames nixvirt.instance));
placeholder = builtins.listToAttrs (builtins.map
(vm: { name = "nixvirt/${vm}"; value = builtins.hashString "sha256" "nixvirt/${vm}"; })
(builtins.attrNames nixvirt.instance));
kvm = {};
};
};
security.wrappers.vm =
{

View File

@@ -28,19 +28,22 @@ inputs:
ENABLE_IMAGE_GENERATION = "True";
IMAGES_OPENAI_API_BASE_URL = "https://oa.api2d.net/v1";
};
environmentFile = inputs.config.sops.templates."open-webui.env".path;
environmentFile = inputs.config.nixos.system.sops.templates."open-webui.env".path;
};
sops =
nixos =
{
templates."open-webui.env".content = let inherit (inputs.config.sops) placeholder; in
''
OPENAI_API_KEY=${placeholder."open-webui/openai"}
WEBUI_SECRET_KEY=${placeholder."open-webui/webui"}
IMAGES_OPENAI_API_KEY=${placeholder."open-webui/openai"}
'';
secrets = { "open-webui/openai" = {}; "open-webui/webui" = {}; };
system.sops =
{
templates."open-webui.env".content = let inherit (inputs.config.nixos.system.sops) placeholder; in
''
OPENAI_API_KEY=${placeholder."open-webui/openai"}
WEBUI_SECRET_KEY=${placeholder."open-webui/webui"}
IMAGES_OPENAI_API_KEY=${placeholder."open-webui/openai"}
'';
secrets = { "open-webui/openai" = {}; "open-webui/webui" = {}; };
};
services.nginx.https."${open-webui.hostname}".location."/".proxy =
{ upstream = "http://127.0.0.1:8080"; websocket = true; };
};
nixos.services.nginx.https."${open-webui.hostname}".location."/".proxy =
{ upstream = "http://127.0.0.1:8080"; websocket = true; };
};
}

View File

@@ -17,48 +17,46 @@ inputs:
listenHttp = 5046;
listenWeb = 443;
enableWebHttps = true;
serviceEnvironmentFile = inputs.config.sops.templates."peertube/env".path;
secrets.secretsFile = inputs.config.sops.secrets."peertube/secrets".path;
serviceEnvironmentFile = inputs.config.nixos.system.sops.templates."peertube/env".path;
secrets.secretsFile = inputs.config.nixos.system.sops.secrets."peertube/secrets".path;
configureNginx = true;
database =
{
createLocally = true;
host = "127.0.0.1";
passwordFile = inputs.config.sops.secrets."peertube/postgresql".path;
passwordFile = inputs.config.nixos.system.sops.secrets."peertube/postgresql".path;
};
redis =
{
host = "127.0.0.1";
port = 7599;
passwordFile = inputs.config.sops.secrets."redis/peertube".path;
};
smtp.passwordFile = inputs.config.sops.secrets."peertube/smtp".path;
settings.smtp =
{
host = "mail.chn.moe";
username = "bot@chn.moe";
from_address = "bot@chn.moe";
passwordFile = inputs.config.nixos.system.sops.secrets."redis/peertube".path;
};
smtp.passwordFile = inputs.config.nixos.system.sops.secrets."peertube/smtp".path;
settings.smtp = { host = "mail.chn.moe"; username = "bot@chn.moe"; from_address = "bot@chn.moe"; };
};
sops =
nixos =
{
templates."peertube/env".content =
''
PT_INITIAL_ROOT_PASSWORD=${inputs.config.sops.placeholder."peertube/password"}
'';
secrets =
system.sops =
{
"peertube/postgresql" = { owner = inputs.config.services.peertube.user; key = "postgresql/peertube"; };
"peertube/password" = {};
"peertube/secrets".owner = inputs.config.services.peertube.user;
"peertube/smtp" = { owner = inputs.config.services.peertube.user; key = "mail/bot"; };
templates."peertube/env".content =
''
PT_INITIAL_ROOT_PASSWORD=${inputs.config.nixos.system.sops.placeholder."peertube/password"}
'';
secrets =
{
"peertube/postgresql" = { owner = inputs.config.services.peertube.user; key = "postgresql/peertube"; };
"peertube/password" = {};
"peertube/secrets".owner = inputs.config.services.peertube.user;
"peertube/smtp" = { owner = inputs.config.services.peertube.user; key = "mail/bot"; };
};
};
services =
{
nginx.https.${peertube.hostname}.global.configName = peertube.hostname;
postgresql.instances.peertube = {};
redis.instances.peertube.port = 7599;
};
};
nixos.services =
{
nginx.https.${peertube.hostname}.global.configName = peertube.hostname;
postgresql.instances.peertube = {};
redis.instances.peertube.port = 7599;
};
systemd.services.peertube.after = [ "redis-peertube.service" ];
};

View File

@@ -23,21 +23,24 @@ inputs:
{
after = [ "mariadb.service" ];
requires = [ "mariadb.service" ];
serviceConfig.EnvironmentFile = inputs.config.sops.templates."photoprism/env".path;
serviceConfig.EnvironmentFile = inputs.config.nixos.system.sops.templates."photoprism/env".path;
};
sops =
nixos =
{
templates."photoprism/env".content = let placeholder = inputs.config.sops.placeholder; in
''
PHOTOPRISM_ADMIN_PASSWORD=${placeholder."photoprism/adminPassword"}
PHOTOPRISM_DATABASE_PASSWORD=${placeholder."mariadb/photoprism"}
'';
secrets."photoprism/adminPassword" = {};
};
nixos.services =
{
mariadb.instances.photoprism = {};
nginx.https."photoprism.chn.moe".location."/".proxy = { upstream = "http://127.0.0.1:2342"; websocket = true; };
system.sops =
{
templates."photoprism/env".content = let inherit (inputs.config.nixos.system.sops) placeholder; in
''
PHOTOPRISM_ADMIN_PASSWORD=${placeholder."photoprism/adminPassword"}
PHOTOPRISM_DATABASE_PASSWORD=${placeholder."mariadb/photoprism"}
'';
secrets."photoprism/adminPassword" = {};
};
services =
{
mariadb.instances.photoprism = {};
nginx.https."photoprism.chn.moe".location."/".proxy = { upstream = "http://127.0.0.1:2342"; websocket = true; };
};
};
};
}

View File

@@ -63,7 +63,7 @@ inputs:
let
passwordFile =
if db.value.passwordFile or null != null then db.value.passwordFile
else inputs.config.sops.secrets."postgresql/${db.value.user}".path;
else inputs.config.nixos.system.sops.secrets."postgresql/${db.value.user}".path;
initializeFlag =
if db.value.initializeFlags != {} then
" WITH "
@@ -85,7 +85,7 @@ inputs:
+ " | grep -E '^${db.value.user}$' -q"
+ " || $PSQL -tAc \"ALTER DATABASE ${db.value.database} OWNER TO ${db.value.user}\"")
(inputs.localLib.attrsToList postgresql.instances)));
sops.secrets = builtins.listToAttrs (builtins.map
nixos.system.sops.secrets = builtins.listToAttrs (builtins.map
(db: { name = "postgresql/${db.value.user}"; value.owner = inputs.config.users.users.postgres.name; })
(builtins.filter (db: db.value.passwordFile == null) (inputs.localLib.attrsToList postgresql.instances)));
environment.persistence."/nix/nodatacow".directories = inputs.lib.mkIf postgresql.nodatacow

View File

@@ -28,12 +28,13 @@ inputs:
# unixSocket = null; # bug
unixSocketPerm = 600;
requirePassFile =
if server.value.passwordFile == null then inputs.config.sops.secrets."redis/${server.name}".path
if server.value.passwordFile == null
then inputs.config.nixos.system.sops.secrets."redis/${server.name}".path
else server.value.passwordFile;
};
})
(inputs.localLib.attrsToList redis.instances));
sops.secrets = builtins.listToAttrs (builtins.map
nixos.system.sops.secrets = builtins.listToAttrs (builtins.map
(server: { name = "redis/${server.name}"; value.owner = inputs.config.users.users.${server.value.user}.name; })
(builtins.filter (server: server.value.passwordFile == null) (inputs.localLib.attrsToList redis.instances)));
systemd.services = builtins.listToAttrs (builtins.map

View File

@@ -15,34 +15,37 @@ inputs:
image = "rsshub:latest";
imageFile = inputs.topInputs.self.src.rsshub;
ports = [ "127.0.0.1:5221:5221/tcp" ];
environmentFiles = [ inputs.config.sops.templates."rsshub/env".path ];
environmentFiles = [ inputs.config.nixos.system.sops.templates."rsshub/env".path ];
};
sops =
nixos =
{
templates."rsshub/env".content = let placeholder = inputs.config.sops.placeholder; in
''
PORT=5221
CACHE_TYPE=memory
PIXIV_REFRESHTOKEN='${placeholder."rsshub/pixiv-refreshtoken"}'
YOUTUBE_KEY='${placeholder."rsshub/youtube-key"}'
YOUTUBE_CLIENT_ID='${placeholder."rsshub/youtube-client-id"}'
YOUTUBE_CLIENT_SECRET='${placeholder."rsshub/youtube-client-secret"}'
YOUTUBE_REFRESH_TOKEN='${placeholder."rsshub/youtube-refresh-token"}'
TWITTER_AUTH_TOKEN='${placeholder."rsshub/twitter-auth-token"}'
ZHIHU_COOKIES='${placeholder."rsshub/zhihu-cookies"}'
XDG_CONFIG_HOME='/var/cache/rsshub/chromium'
XDG_CACHE_HOME='/var/cache/rsshub/chromium'
BILIBILI_COOKIE_data0='${placeholder."rsshub/bilibili-cookie"}'
'';
secrets = (builtins.listToAttrs (builtins.map (secret: { name = "rsshub/${secret}"; value = {}; })
[
"pixiv-refreshtoken"
"youtube-key" "youtube-client-id" "youtube-client-secret" "youtube-refresh-token"
"twitter-auth-token"
"bilibili-cookie"
"zhihu-cookies"
]));
system.sops =
{
templates."rsshub/env".content = let inherit (inputs.config.nixos.system.sops) placeholder; in
''
PORT=5221
CACHE_TYPE=memory
PIXIV_REFRESHTOKEN='${placeholder."rsshub/pixiv-refreshtoken"}'
YOUTUBE_KEY='${placeholder."rsshub/youtube-key"}'
YOUTUBE_CLIENT_ID='${placeholder."rsshub/youtube-client-id"}'
YOUTUBE_CLIENT_SECRET='${placeholder."rsshub/youtube-client-secret"}'
YOUTUBE_REFRESH_TOKEN='${placeholder."rsshub/youtube-refresh-token"}'
TWITTER_AUTH_TOKEN='${placeholder."rsshub/twitter-auth-token"}'
ZHIHU_COOKIES='${placeholder."rsshub/zhihu-cookies"}'
XDG_CONFIG_HOME='/var/cache/rsshub/chromium'
XDG_CACHE_HOME='/var/cache/rsshub/chromium'
BILIBILI_COOKIE_data0='${placeholder."rsshub/bilibili-cookie"}'
'';
secrets = (builtins.listToAttrs (builtins.map (secret: inputs.lib.nameValuePair "rsshub/${secret}" {})
[
"pixiv-refreshtoken"
"youtube-key" "youtube-client-id" "youtube-client-secret" "youtube-refresh-token"
"twitter-auth-token"
"bilibili-cookie"
"zhihu-cookies"
]));
};
services.nginx.https.${rsshub.hostname}.location."/".proxy.upstream = "http://127.0.0.1:5221";
};
nixos.services.nginx.https.${rsshub.hostname}.location."/".proxy.upstream = "http://127.0.0.1:5221";
};
}

View File

@@ -14,16 +14,19 @@ inputs:
{
enable = true;
settings.server = { port = 8081; bind_address = "127.0.0.1"; secret_key = "@SEARX_SECRET_KEY@"; };
environmentFile = inputs.config.sops.templates."searx.env".path;
environmentFile = inputs.config.nixos.system.sops.templates."searx.env".path;
};
sops =
nixos =
{
templates."searx.env".content = let inherit (inputs.config.sops) placeholder; in
''
SEARX_SECRET_KEY=${placeholder."searx/secret-key"}
'';
secrets."searx/secret-key" = {};
system.sops =
{
templates."searx.env".content = let inherit (inputs.config.nixos.system.sops) placeholder; in
''
SEARX_SECRET_KEY=${placeholder."searx/secret-key"}
'';
secrets."searx/secret-key" = {};
};
services.nginx.https.${searx.hostname}.location."/".proxy.upstream = "http://127.0.0.1:8081";
};
nixos.services.nginx.https.${searx.hostname}.location."/".proxy.upstream = "http://127.0.0.1:8081";
};
}

View File

@@ -20,7 +20,7 @@ inputs:
createLocally = false;
host = "127.0.0.1";
port = 9184;
passwordFile = inputs.config.sops.secrets."redis/send".path;
passwordFile = inputs.config.nixos.system.sops.secrets."redis/send".path;
};
};
systemd.services.send.after = [ "redis-send.service" ];

View File

@@ -177,7 +177,7 @@ inputs:
# ConstrainDevices=yes
'';
};
munge = { enable = true; password = inputs.config.sops.secrets."munge.key".path; };
munge = { enable = true; password = inputs.config.nixos.system.sops.secrets."munge.key".path; };
};
systemd.services.slurmd.environment =
let gpus = slurm.node.${inputs.config.nixos.model.hostname}.gpus or null;
@@ -186,12 +186,16 @@ inputs:
CUDA_PATH = "${inputs.pkgs.cudatoolkit}";
LD_LIBRARY_PATH = "${inputs.config.hardware.nvidia.package}/lib";
};
sops.secrets."munge.key" =
nixos.system.sops.secrets."munge.key" =
{
format = "binary";
sopsFile = inputs.localLib.mkConditional (inputs.config.nixos.model.cluster == null)
"${builtins.dirOf inputs.config.sops.defaultSopsFile}/munge.key"
"${inputs.config.nixos.system.sops.clusterSopsDir}/munge.key";
sopsFile =
let
devicePath = "${inputs.topInputs.self}/devices";
inherit (inputs.config.nixos) model;
in inputs.localLib.mkConditional (model.cluster == null)
"${devicePath}/${model.hostname}/secrets/munge.key"
"${devicePath}/${model.cluster.clusterName}/secrets/munge.key";
owner = inputs.config.systemd.services.munged.serviceConfig.User;
};
environment.sessionVariables = { SLURM_UNBUFFEREDIO = "1"; SLURM_CPU_BIND = "v"; };
@@ -206,7 +210,7 @@ inputs:
{
enable = true;
dbdHost = "localhost";
storagePassFile = inputs.config.sops.secrets."slurm/db".path;
storagePassFile = inputs.config.nixos.system.sops.secrets."slurm/db".path;
extraConfig =
''
StorageHost=*
@@ -224,24 +228,20 @@ inputs:
services.slurmctld = { after = [ "suid-sgid-wrappers.service" ]; serviceConfig.MemorySwapMax = "0"; };
tmpfiles.rules = [ "d /var/log/slurmctld 700 slurm slurm" ];
};
sops =
nixos.system.sops =
{
secrets = { "slurm/db" = { owner = "slurm"; key = "mariadb/slurm"; }; }
// builtins.listToAttrs (builtins.map
(n:
{
name = "telegram/${n}";
value.sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/default.yaml";
})
(n: inputs.lib.nameValuePair "telegram/${n}" {})
[ "token" "user/chn" "user/hjp" ]);
templates."info.yaml" =
{
owner = "slurm";
content = let inherit (inputs.config.sops) placeholder; in builtins.toJSON
content = let inherit (inputs.config.nixos.system.sops) placeholder; in builtins.toJSON
{
token = placeholder."telegram/token";
user = builtins.listToAttrs (builtins.map (n: { name = n; value = placeholder."telegram/user/${n}"; })
[ "chn" "hjp" ]);
user = builtins.listToAttrs (builtins.map
(n: inputs.lib.nameValuePair n placeholder."telegram/user/${n}") [ "chn" "hjp" ]);
slurmConf = "${inputs.config.services.slurm.etcSlurm}/slurm.conf";
};
};
@@ -252,7 +252,7 @@ inputs:
let info = inputs.pkgs.localPackages.info.override
{
slurm = inputs.config.services.slurm.package;
configFile = inputs.config.sops.templates."info.yaml".path;
configFile = inputs.config.nixos.system.sops.templates."info.yaml".path;
};
in "${info}/bin/info";
program = "slurm-info";

View File

@@ -43,7 +43,7 @@ inputs:
let
package = inputs.pkgs.matrix-synapse.override
{ extras = [ "url-preview" "postgres" "redis" ]; plugins = []; };
config = inputs.config.sops.templates."synapse/${instance.name}/config.yaml".path;
config = inputs.config.nixos.system.sops.templates."synapse/${instance.name}/config.yaml".path;
homeserver = "${package}/bin/synapse_homeserver";
in
{
@@ -100,143 +100,145 @@ inputs:
];
})
(inputs.localLib.attrsToList synapse.instances));
sops = inputs.lib.mkMerge (builtins.map
(instance:
{
templates."synapse/${instance.name}/config.yaml" =
{
owner = "synapse-${instance.name}";
group = "synapse-${instance.name}";
content =
let
inherit (inputs.config.sops) placeholder;
in builtins.readFile ((inputs.pkgs.formats.yaml {}).generate "${instance.name}.yaml"
{
server_name = instance.value.matrixHostname;
public_baseurl = "https://${instance.value.hostname}/";
listeners =
[{
bind_addresses = [ "127.0.0.1" ];
inherit (instance.value) port;
resources = [{ names = [ "client" "federation" ]; compress = false; }];
tls = false;
type = "http";
x_forwarded = true;
}];
database =
{
name = "psycopg2";
args = let name = "synapse_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}"; in
{
user = name;
password = placeholder."postgresql/${name}";
database = name;
host = "127.0.0.1";
port = "5432";
};
allow_unsafe_locale = true;
};
redis =
{
enabled = true;
port = instance.value.redisPort;
password = placeholder."redis/synapse-${instance.name}";
};
turn_shared_secret = placeholder."synapse/${instance.name}/coturn";
registration_shared_secret = placeholder."synapse/${instance.name}/registration";
macaroon_secret_key = placeholder."synapse/${instance.name}/macaroon";
form_secret = placeholder."synapse/${instance.name}/form";
signing_key_path = inputs.config.sops.secrets."synapse/${instance.name}/signing-key".path;
email =
{
smtp_host = "mail.chn.moe";
smtp_port = 25;
smtp_user = "bot@chn.moe";
smtp_pass = placeholder."mail/bot";
require_transport_security = true;
notif_from = "Your Friendly %(app)s homeserver <bot@chn.moe>";
app_name = "Haonan Chen's synapse";
};
admin_contact = "mailto:chn@chn.moe";
enable_registration = true;
registrations_require_3pid = [ "email" ];
registration_requires_token = true;
turn_uris = [ "turns:coturn.chn.moe" "turn:coturn.chn.moe" ];
max_upload_size = "1024M";
web_client_location = "https://element.chn.moe/";
report_stats = true;
trusted_key_servers =
[{
server_name = "matrix.org";
verify_keys."ed25519:auto" = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw";
}];
suppress_key_server_warning = true;
log_config = (inputs.pkgs.formats.yaml {}).generate "log.yaml"
{
version = 1;
formatters.precise.format =
"%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s";
handlers.console = { class = "logging.StreamHandler"; formatter = "precise"; };
root = { level = "INFO"; handlers = [ "console" ]; };
disable_existing_loggers = true;
};
pid_file = "/run/synapse-${instance.name}.pid";
media_store_path = "/var/lib/synapse/${instance.name}/media_store";
presence.enabled = true;
url_preview_enabled = true;
url_preview_ip_range_blacklist =
[
"10.0.0.0/8" "100.64.0.0/10" "127.0.0.0/8" "169.254.0.0/16" "172.16.0.0/12" "192.0.0.0/24"
"192.0.2.0/24" "192.168.0.0/16" "192.88.99.0/24" "198.18.0.0/15" "198.51.100.0/24" "2001:db8::/32"
"203.0.113.0/24" "224.0.0.0/4" "::1/128" "fc00::/7" "fe80::/10" "fec0::/10" "ff00::/8"
];
max_image_pixels = "32M";
dynamic_thumbnails = false;
# this is required for displaying thumbnails in sticker widgets
enable_authenticated_media = false;
});
};
secrets = (builtins.listToAttrs (builtins.map
(secret: { name = "synapse/${instance.name}/${secret}"; value = {}; })
[ "coturn" "registration" "macaroon" "form" ]))
// { "synapse/${instance.name}/signing-key".owner = "synapse-${instance.name}"; }
// { "mail/bot" = {}; };
})
(inputs.localLib.attrsToList synapse.instances));
nixos.services =
nixos =
{
postgresql.instances = builtins.listToAttrs (builtins.map
system.sops = inputs.lib.mkMerge (builtins.map
(instance:
{
name = "synapse_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}";
value.initializeFlags = { TEMPLATE = "template0"; LC_CTYPE = "C"; LC_COLLATE = "C"; };
})
(inputs.localLib.attrsToList synapse.instances));
redis.instances = builtins.listToAttrs (builtins.map
(instance: { name = "synapse-${instance.name}"; value.port = instance.value.redisPort; })
(inputs.localLib.attrsToList synapse.instances));
nginx.https = builtins.listToAttrs (builtins.map
(instance: with instance.value;
{
name = hostname;
value.location =
templates."synapse/${instance.name}/config.yaml" =
{
"/".proxy = { upstream = "http://127.0.0.1:${toString port}"; websocket = true; };
"/.well-known/matrix/server".static =
{
root = builtins.toString (inputs.pkgs.writeTextFile
owner = "synapse-${instance.name}";
content =
let
inherit (inputs.config.nixos.system.sops) placeholder;
in builtins.readFile ((inputs.pkgs.formats.yaml {}).generate "${instance.name}.yaml"
{
name = "server";
text = builtins.toJSON
server_name = instance.value.matrixHostname;
public_baseurl = "https://${instance.value.hostname}/";
listeners =
[{
bind_addresses = [ "127.0.0.1" ];
inherit (instance.value) port;
resources = [{ names = [ "client" "federation" ]; compress = false; }];
tls = false;
type = "http";
x_forwarded = true;
}];
database =
{
"m.server" = "${hostname}:443";
name = "psycopg2";
args = let name = "synapse_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}"; in
{
user = name;
password = placeholder."postgresql/${name}";
database = name;
host = "127.0.0.1";
port = "5432";
};
allow_unsafe_locale = true;
};
destination = "/.well-known/matrix/server";
redis =
{
enabled = true;
port = instance.value.redisPort;
password = placeholder."redis/synapse-${instance.name}";
};
turn_shared_secret = placeholder."synapse/${instance.name}/coturn";
registration_shared_secret = placeholder."synapse/${instance.name}/registration";
macaroon_secret_key = placeholder."synapse/${instance.name}/macaroon";
form_secret = placeholder."synapse/${instance.name}/form";
signing_key_path = inputs.config.nixos.system.sops.secrets."synapse/${instance.name}/signing-key".path;
email =
{
smtp_host = "mail.chn.moe";
smtp_port = 25;
smtp_user = "bot@chn.moe";
smtp_pass = placeholder."mail/bot";
require_transport_security = true;
notif_from = "Your Friendly %(app)s homeserver <bot@chn.moe>";
app_name = "Haonan Chen's synapse";
};
admin_contact = "mailto:chn@chn.moe";
enable_registration = true;
registrations_require_3pid = [ "email" ];
registration_requires_token = true;
turn_uris = [ "turns:coturn.chn.moe" "turn:coturn.chn.moe" ];
max_upload_size = "1024M";
web_client_location = "https://element.chn.moe/";
report_stats = true;
trusted_key_servers =
[{
server_name = "matrix.org";
verify_keys."ed25519:auto" = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw";
}];
suppress_key_server_warning = true;
log_config = (inputs.pkgs.formats.yaml {}).generate "log.yaml"
{
version = 1;
formatters.precise.format =
"%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s";
handlers.console = { class = "logging.StreamHandler"; formatter = "precise"; };
root = { level = "INFO"; handlers = [ "console" ]; };
disable_existing_loggers = true;
};
pid_file = "/run/synapse-${instance.name}.pid";
media_store_path = "/var/lib/synapse/${instance.name}/media_store";
presence.enabled = true;
url_preview_enabled = true;
url_preview_ip_range_blacklist =
[
"10.0.0.0/8" "100.64.0.0/10" "127.0.0.0/8" "169.254.0.0/16" "172.16.0.0/12" "192.0.0.0/24"
"192.0.2.0/24" "192.168.0.0/16" "192.88.99.0/24" "198.18.0.0/15" "198.51.100.0/24" "2001:db8::/32"
"203.0.113.0/24" "224.0.0.0/4" "::1/128" "fc00::/7" "fe80::/10" "fec0::/10" "ff00::/8"
];
max_image_pixels = "32M";
dynamic_thumbnails = false;
# this is required for displaying thumbnails in sticker widgets
enable_authenticated_media = false;
});
};
};
secrets = (builtins.listToAttrs (builtins.map
(secret: { name = "synapse/${instance.name}/${secret}"; value = {}; })
[ "coturn" "registration" "macaroon" "form" ]))
// { "synapse/${instance.name}/signing-key".owner = "synapse-${instance.name}"; }
// { "mail/bot" = {}; };
})
(inputs.localLib.attrsToList synapse.instances));
services =
{
postgresql.instances = builtins.listToAttrs (builtins.map
(instance:
{
name = "synapse_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}";
value.initializeFlags = { TEMPLATE = "template0"; LC_CTYPE = "C"; LC_COLLATE = "C"; };
})
(inputs.localLib.attrsToList synapse.instances));
redis.instances = builtins.listToAttrs (builtins.map
(instance: { name = "synapse-${instance.name}"; value.port = instance.value.redisPort; })
(inputs.localLib.attrsToList synapse.instances));
nginx.https = builtins.listToAttrs (builtins.map
(instance: with instance.value;
{
name = hostname;
value.location =
{
"/".proxy = { upstream = "http://127.0.0.1:${toString port}"; websocket = true; };
"/.well-known/matrix/server".static =
{
root = builtins.toString (inputs.pkgs.writeTextFile
{
name = "server";
text = builtins.toJSON
{
"m.server" = "${hostname}:443";
};
destination = "/.well-known/matrix/server";
});
};
};
})
(inputs.localLib.attrsToList synapse.instances));
};
};
};
}

View File

@@ -25,29 +25,32 @@ inputs:
SMTP_SECURITY = "force_tls";
SMTP_USERNAME = "bot@chn.moe";
};
environmentFile = inputs.config.sops.templates."vaultwarden.env".path;
environmentFile = inputs.config.nixos.system.sops.templates."vaultwarden.env".path;
};
sops =
nixos =
{
templates."vaultwarden.env" = let placeholder = inputs.config.sops.placeholder; in
system.sops =
{
owner = "vaultwarden";
group = "vaultwarden";
content =
''
DATABASE_URL=postgresql://vaultwarden:${placeholder."postgresql/vaultwarden"}@localhost/vaultwarden
ADMIN_TOKEN=${placeholder."vaultwarden/admin_token"}
SMTP_PASSWORD=${placeholder."mail/bot"}
'';
templates."vaultwarden.env" = let inherit (inputs.config.nixos.system.sops) placeholder; in
{
owner = "vaultwarden";
group = "vaultwarden";
content =
''
DATABASE_URL=postgresql://vaultwarden:${placeholder."postgresql/vaultwarden"}@localhost/vaultwarden
ADMIN_TOKEN=${placeholder."vaultwarden/admin_token"}
SMTP_PASSWORD=${placeholder."mail/bot"}
'';
};
secrets = { "vaultwarden/admin_token" = {}; "mail/bot" = {}; };
};
services =
{
postgresql.instances.vaultwarden = {};
nginx.https.${vaultwarden.hostname}.location."/".proxy =
{ upstream = "http://127.0.0.1:8000"; websocket = true; };
};
secrets = { "vaultwarden/admin_token" = {}; "mail/bot" = {}; };
};
systemd.services.vaultwarden.after = [ "postgresql.service" ];
nixos.services =
{
postgresql.instances.vaultwarden = {};
nginx.https.${vaultwarden.hostname}.location."/".proxy =
{ upstream = "http://127.0.0.1:8000"; websocket = true; };
};
};
}

View File

@@ -33,7 +33,7 @@ inputs:
{
inherit (wg.value) listenPort;
ips = [ "${wg.value.ip}/${builtins.toString wg.value.netmask}" ];
privateKeyFile = inputs.config.sops.secrets.wireguard.path;
privateKeyFile = inputs.config.nixos.system.sops.secrets.wireguard.path;
peers = builtins.map
(peer:
{
@@ -45,6 +45,6 @@ inputs:
};
})
(inputs.localLib.attrsToList wireguard));
sops.secrets.wireguard = {};
nixos.system.sops.secrets.wireguard = {};
};
}

View File

@@ -43,7 +43,7 @@ inputs:
};
resolved.enable = false;
};
sops =
nixos.system.sops =
{
templates."xray-client.json" =
{
@@ -120,7 +120,7 @@ inputs:
port = 443;
users =
[{
id = inputs.config.sops.placeholder."xray-client/uuid";
id = inputs.config.nixos.system.sops.placeholder."xray-client/uuid";
encryption = "none";
flow = "xtls-rprx-vision-udp443";
}];
@@ -179,7 +179,8 @@ inputs:
{
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
script = "exec ${inputs.pkgs.xray}/bin/xray -config ${inputs.config.sops.templates."xray-client.json".path}";
script = let config = inputs.config.nixos.system.sops.templates."xray-client.json".path; in
"exec ${inputs.pkgs.xray}/bin/xray -config ${config}";
serviceConfig =
{
User = "v2ray";
@@ -191,7 +192,7 @@ inputs:
LimitNOFILE = 524288;
CPUSchedulingPolicy = "rr";
};
restartTriggers = [ inputs.config.sops.templates."xray-client.json".file ];
restartTriggers = [ inputs.config.nixos.system.sops.templates."xray-client.json".file ];
};
v2ray-forwarder =
{

View File

@@ -10,136 +10,144 @@ inputs:
};
config = let inherit (inputs.config.nixos.services.xray) server; in inputs.lib.mkIf (server != null)
(
let userList = builtins.attrNames
(inputs.pkgs.localPackages.fromYaml (builtins.readFile inputs.config.sops.defaultSopsFile)).xray-server.clients;
let userList = builtins.map (user: builtins.elemAt user 2) (builtins.filter
(user: builtins.elem user == 3 && inputs.lib.lists.hasPrefix [ "xray-server" "clients" ])
inputs.config.nixos.system.sops.availableKeys);
in
{
sops =
nixos =
{
templates."xray-server.json" =
system.sops =
{
owner = inputs.config.users.users.v2ray.name;
group = inputs.config.users.users.v2ray.group;
content = builtins.toJSON
templates."xray-server.json" =
{
log.loglevel = "warning";
inbounds =
[
(
let fallbackPort = builtins.toString
(with inputs.config.nixos.services.nginx.global; httpsPort + httpsPortShift.http2);
in
owner = inputs.config.users.users.v2ray.name;
group = inputs.config.users.users.v2ray.group;
content = builtins.toJSON
{
log.loglevel = "warning";
inbounds =
[
(
let fallbackPort = builtins.toString
(with inputs.config.nixos.services.nginx.global; httpsPort + httpsPortShift.http2);
in
{
port = 4726;
listen = "127.0.0.1";
protocol = "vless";
settings =
{
clients = builtins.map
(n:
{
id = inputs.config.nixos.system.sops.placeholder."xray-server/clients/${n}";
flow = "xtls-rprx-vision";
email = "${n}@xray.chn.moe";
})
userList;
decryption = "none";
fallbacks = [{ dest = "127.0.0.1:${fallbackPort}"; }];
};
streamSettings =
{
network = "raw";
security = "reality";
realitySettings =
{
dest = "127.0.0.1:${fallbackPort}";
serverNames = [ server.serverName ];
privateKey = inputs.config.nixos.system.sops.placeholder."xray-server/private-key";
minClientVer = "1.8.0";
shortIds = [ "" ];
};
};
sniffing = { enabled = true; destOverride = [ "http" "tls" "quic" ]; routeOnly = true; };
tag = "in-legacy";
}
)
{
port = 4726;
port = 4638;
listen = "127.0.0.1";
protocol = "vless";
settings =
{
clients = builtins.map
(n:
{
id = inputs.config.sops.placeholder."xray-server/clients/${n}";
flow = "xtls-rprx-vision";
email = "${n}@xray.chn.moe";
})
userList;
decryption = "none";
fallbacks = [{ dest = "127.0.0.1:${fallbackPort}"; }];
};
streamSettings =
{
network = "raw";
security = "reality";
realitySettings =
{
dest = "127.0.0.1:${fallbackPort}";
serverNames = [ server.serverName ];
privateKey = inputs.config.sops.placeholder."xray-server/private-key";
minClientVer = "1.8.0";
shortIds = [ "" ];
};
};
sniffing = { enabled = true; destOverride = [ "http" "tls" "quic" ]; routeOnly = true; };
tag = "in-legacy";
settings = { clients = [{ id = "be01f0a0-9976-42f5-b9ab-866eba6ed393"; }]; decryption = "none"; };
streamSettings.network = "raw";
sniffing = { enabled = true; destOverride = [ "http" "tls" "quic" ]; };
tag = "in-localdns";
}
)
{
port = 4638;
listen = "127.0.0.1";
protocol = "vless";
settings = { clients = [{ id = "be01f0a0-9976-42f5-b9ab-866eba6ed393"; }]; decryption = "none"; };
streamSettings.network = "raw";
sniffing = { enabled = true; destOverride = [ "http" "tls" "quic" ]; };
tag = "in-localdns";
}
{
listen = "127.0.0.1";
port = 6149;
protocol = "dokodemo-door";
settings.address = "127.0.0.1";
tag = "api";
}
];
outbounds =
[
{ protocol = "freedom"; tag = "freedom"; }
{
protocol = "vless";
settings.vnext =
[{
address = "127.0.0.1";
port = 4638;
users = [{ id = "be01f0a0-9976-42f5-b9ab-866eba6ed393"; encryption = "none"; }];
}];
streamSettings.network = "raw";
tag = "loopback-localdns";
}
];
routing =
{
domainStrategy = "AsIs";
rules = builtins.map (rule: rule // { type = "field"; })
[
{
inboundTag = [ "in-legacy" ];
domain = [ "domain:openai.com" ];
outboundTag = "loopback-localdns";
listen = "127.0.0.1";
port = 6149;
protocol = "dokodemo-door";
settings.address = "127.0.0.1";
tag = "api";
}
{ inboundTag = [ "in-legacy" ]; outboundTag = "freedom"; }
{ inboundTag = [ "in-localdns" ]; outboundTag = "freedom"; }
{ inboundTag = [ "api" ]; outboundTag = "api"; }
];
};
stats = {};
api = { tag = "api"; services = [ "StatsService" ]; };
policy =
{
levels."0" = { statsUserUplink = true; statsUserDownlink = true; };
system =
outbounds =
[
{ protocol = "freedom"; tag = "freedom"; }
{
protocol = "vless";
settings.vnext =
[{
address = "127.0.0.1";
port = 4638;
users = [{ id = "be01f0a0-9976-42f5-b9ab-866eba6ed393"; encryption = "none"; }];
}];
streamSettings.network = "raw";
tag = "loopback-localdns";
}
];
routing =
{
statsInboundUplink = true;
statsInboundDownlink = true;
statsOutboundUplink = true;
statsOutboundDownlink = true;
domainStrategy = "AsIs";
rules = builtins.map (rule: rule // { type = "field"; })
[
{
inboundTag = [ "in-legacy" ];
domain = [ "domain:openai.com" ];
outboundTag = "loopback-localdns";
}
{ inboundTag = [ "in-legacy" ]; outboundTag = "freedom"; }
{ inboundTag = [ "in-localdns" ]; outboundTag = "freedom"; }
{ inboundTag = [ "api" ]; outboundTag = "api"; }
];
};
stats = {};
api = { tag = "api"; services = [ "StatsService" ]; };
policy =
{
levels."0" = { statsUserUplink = true; statsUserDownlink = true; };
system =
{
statsInboundUplink = true;
statsInboundDownlink = true;
statsOutboundUplink = true;
statsOutboundDownlink = true;
};
};
};
};
secrets = builtins.listToAttrs
(builtins.map (n: inputs.lib.nameValuePair "xray-server/clients/${n}" {}) userList)
// (builtins.listToAttrs (builtins.map
(name: inputs.lib.nameValuePair "telegram/${name}" { group = "telegram"; mode = "0440"; })
[ "token" "user/chn" ]))
// { "xray-server/private-key" = {}; };
};
secrets = builtins.listToAttrs
(builtins.map (n: { name = "xray-server/clients/${n}"; value = {}; }) userList)
// (builtins.listToAttrs (builtins.map
(name:
services =
{
acme.cert.${server.serverName}.group = inputs.config.users.users.nginx.group;
nginx =
{
transparentProxy.map.${server.serverName} = 4726;
https.${server.serverName} =
{
name = "telegram/${name}";
value =
{
group = "telegram";
mode = "0440";
sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/default.yaml";
};
})
[ "token" "user/chn" ]))
// { "xray-server/private-key" = {}; };
listen.main = { proxyProtocol = false; addToTransparentProxy = false; };
location."/".return.return = "400";
};
};
};
};
systemd =
{
@@ -149,8 +157,8 @@ inputs:
{
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
script =
"exec ${inputs.pkgs.xray}/bin/xray -config ${inputs.config.sops.templates."xray-server.json".path}";
script = let config = inputs.config.nixos.system.sops.templates."xray-server.json".path; in
"exec ${inputs.pkgs.xray}/bin/xray -config ${config}";
serviceConfig =
{
User = "v2ray";
@@ -160,7 +168,7 @@ inputs:
LimitNPROC = 65536;
LimitNOFILE = 524288;
};
restartTriggers = [ inputs.config.sops.templates."xray-server.json".file ];
restartTriggers = [ inputs.config.nixos.system.sops.templates."xray-server.json".file ];
};
xray-stat =
{
@@ -172,8 +180,8 @@ inputs:
jq = "${inputs.pkgs.jq}/bin/jq";
sed = "${inputs.pkgs.gnused}/bin/sed";
cat = "${inputs.pkgs.coreutils}/bin/cat";
token = inputs.config.sops.secrets."telegram/token".path;
chat = inputs.config.sops.secrets."telegram/user/chn".path;
token = inputs.config.nixos.system.sops.secrets."telegram/token".path;
chat = inputs.config.nixos.system.sops.secrets."telegram/user/chn".path;
in
''
message='${inputs.config.nixos.model.hostname} xray:\n'
@@ -216,19 +224,6 @@ inputs:
telegram.gid = inputs.config.nixos.user.gid.telegram;
};
};
nixos.services =
{
acme.cert.${server.serverName}.group = inputs.config.users.users.nginx.group;
nginx =
{
transparentProxy.map.${server.serverName} = 4726;
https.${server.serverName} =
{
listen.main = { proxyProtocol = false; addToTransparentProxy = false; };
location."/".return.return = "400";
};
};
};
}
);
}

View File

@@ -10,7 +10,7 @@ inputs:
};
config = let inherit (inputs.config.nixos.services.xray) xmuClient; in inputs.lib.mkIf (xmuClient != null)
{
sops =
nixos.system.sops =
{
templates."xray-xmu-client.json" =
{
@@ -37,7 +37,8 @@ inputs:
[{
address = "webvpn.xmu.edu.cn";
port = 443;
users = [{ id = inputs.config.sops.placeholder."xray-xmu-client/uuid"; encryption = "none"; }];
users =
[{ id = inputs.config.nixos.system.sops.placeholder."xray-xmu-client/uuid"; encryption = "none"; }];
}];
streamSettings =
{
@@ -61,8 +62,9 @@ inputs:
in "/https/${prefix}${paddedHex}/xsession";
mode = "packet-up";
security = "tls";
extra.headers.Cookie = "show_vpn=0; heartbeat=1; show_faq=0; "
+ "wengine_vpn_ticketwebvpn_xmu_edu_cn=${inputs.config.sops.placeholder."xray-xmu-client/cookie"}";
extra.headers.Cookie =
let ticket = inputs.config.nixos.system.sops.placeholder."xray-xmu-client/cookie";
in "show_vpn=0; heartbeat=1; show_faq=0; wengine_vpn_ticketwebvpn_xmu_edu_cn=${ticket}";
};
tlsSettings.alpn = [ "http/1.1" ];
};
@@ -77,8 +79,8 @@ inputs:
{
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
script =
"exec ${inputs.pkgs.xray}/bin/xray -config ${inputs.config.sops.templates."xray-xmu-client.json".path}";
script = let config = inputs.config.nixos.system.sops.templates."xray-xmu-client.json".path; in
"exec ${inputs.pkgs.xray}/bin/xray -config ${config}";
serviceConfig =
{
User = "v2ray";
@@ -90,7 +92,7 @@ inputs:
LimitNOFILE = 524288;
CPUSchedulingPolicy = "rr";
};
restartTriggers = [ inputs.config.sops.templates."xray-xmu-client.json".file ];
restartTriggers = [ inputs.config.nixos.system.sops.templates."xray-xmu-client.json".file ];
};
};
users =

View File

@@ -10,12 +10,11 @@ inputs:
};
config = let inherit (inputs.config.nixos.services.xray) xmuServer; in inputs.lib.mkIf (xmuServer != null)
{
sops =
nixos.system.sops =
{
templates."xray-xmu-server.json" =
{
owner = inputs.config.users.users.v2ray.name;
group = inputs.config.users.users.v2ray.group;
content = builtins.toJSON
{
log.loglevel = "warning";
@@ -24,7 +23,11 @@ inputs:
port = 4727;
listen = "127.0.0.1";
protocol = "vless";
settings = { clients = [{ id = inputs.config.sops.placeholder."xray-xmu-server"; }]; decryption = "none"; };
settings =
{
clients = [{ id = inputs.config.nixos.system.sops.placeholder."xray-xmu-server"; }];
decryption = "none";
};
streamSettings = { network = "xhttp"; xhttpSettings = { mode = "stream-one"; path = "/xsession"; }; };
tag = "in";
}];
@@ -37,8 +40,8 @@ inputs:
{
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
script =
"exec ${inputs.pkgs.xray}/bin/xray -config ${inputs.config.sops.templates."xray-xmu-server.json".path}";
script = let config = inputs.config.nixos.system.sops.templates."xray-xmu-server.json".path; in
"exec ${inputs.pkgs.xray}/bin/xray -config ${config}";
serviceConfig =
{
User = "v2ray";
@@ -49,7 +52,7 @@ inputs:
LimitNPROC = 65536;
LimitNOFILE = 524288;
};
restartTriggers = [ inputs.config.sops.templates."xray-xmu-server.json".file ];
restartTriggers = [ inputs.config.nixos.system.sops.templates."xray-xmu-server.json".file ];
};
users =
{

View File

@@ -146,19 +146,19 @@ inputs:
# wpa_passphrase SSID password
networks = builtins.listToAttrs (builtins.map
(network: { name = network; value.pskRaw = "ext:${network}"; }) network.wireless);
secretsFile = inputs.config.sops.templates."wireless.env".path;
secretsFile = inputs.config.nixos.system.sops.templates."wireless.env".path;
};
firewall.trustedInterfaces = network.trust;
};
# dnsable dns fallback, use provided dns servers or no dns
services.resolved.fallbackDns = [];
sops = inputs.lib.mkIf (network.wireless != null)
nixos.system.sops = inputs.lib.mkIf (network.wireless != null)
{
templates."wireless.env".content = builtins.concatStringsSep "\n" (builtins.map
(network: "${network}=${inputs.config.sops.placeholder."wireless/${network}"}")
(network: "${network}=${inputs.config.nixos.system.sops.placeholder."wireless/${network}"}")
network.wireless);
secrets = builtins.listToAttrs (builtins.map
(network: { name = "wireless/${network}"; value = {}; })
(network: inputs.lib.nameValuePair "wireless/${network}" {})
network.wireless);
};
})

View File

@@ -105,26 +105,26 @@ inputs:
protocol = "ssh-ng";
systems = [ "x86_64-linux" ];
sshUser = "nix-ssh";
sshKey = inputs.config.sops.secrets."nix/remote".path;
sshKey = inputs.config.nixos.system.sops.secrets."nix/remote".path;
maxJobs = 1;
mandatoryFeatures = [ "big-parallel" ];
supportedFeatures = builtins.map (f: "gccarch-${f}") v;
})
nix.remote.master.host;
};
sops.secrets."nix/remote" = {};
nixos.system.sops.secrets."nix/remote" = {};
})
(inputs.lib.mkIf nix.githubToken.enable
{
nix.extraOptions = "!include ${inputs.config.sops.templates."nix-github.conf".path}";
sops =
nix.extraOptions = "!include ${inputs.config.nixos.system.sops.templates."nix-github.conf".path}";
nixos.system.sops =
{
templates."nix-github.conf" =
{
content = "access-tokens = github.com=${inputs.config.sops.placeholder."github/token"}";
content = "access-tokens = github.com=${inputs.config.nixos.system.sops.placeholder."github/token"}";
mode = "0444";
};
secrets."github/token".sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/chn.yaml";
secrets."github/token" = {};
};
})
# c++ include path

View File

@@ -2,38 +2,113 @@ inputs:
{
options.nixos.system.sops = let inherit (inputs.lib) mkOption types; in
{
crossSopsDir = mkOption
secrets = mkOption
{
type = types.nonEmptyStr;
default = "${inputs.topInputs.self}/devices/cross/secrets";
readOnly = true;
type = types.attrsOf (types.submodule (submoduleInputs: { options =
{
path = mkOption
{
type = types.path;
default = inputs.config.sops.secrets.${submoduleInputs.config.key}.path;
readOnly = true;
};
key = mkOption { type = types.str; default = submoduleInputs.config._module.args.name; };
format = mkOption { type = types.enum [ "yaml" "binary" ]; default = "yaml"; };
mode = mkOption { type = types.str; default = "0400"; };
owner = mkOption { type = types.nullOr types.str; default = null; };
group = mkOption { type = types.nullOr types.str; default = null; };
sopsFile = mkOption
{
type = types.path;
default =
let secretFileIndex =
inputs.lib.lists.findFirstIndex (x: x) null
(builtins.map
(file: inputs.lib.hasAttrByPath (inputs.lib.splitString "/" submoduleInputs.config.key)
(inputs.pkgs.localPackages.fromYaml (builtins.readFile file)))
inputs.config.nixos.system.sops.defaultSopsFile);
in
if secretFileIndex == null then builtins.abort "No sops file found for ${submoduleInputs.config.key}"
else builtins.elemAt inputs.config.nixos.system.sops.defaultSopsFile secretFileIndex;
};
neededForUsers = mkOption { type = types.bool; default = false; };
};}));
default = {};
};
clusterSopsDir = mkOption
templates = mkOption
{
type = types.nullOr types.nonEmptyStr;
default = if (inputs.config.nixos.model.cluster == null) then null
else "${inputs.topInputs.self}/devices/${inputs.config.nixos.model.cluster.clusterName}/secrets";
type = types.attrsOf (types.submodule (submoduleInputs: { options =
{
content = mkOption { type = types.str; };
path = mkOption
{
type = types.path;
default = inputs.config.sops.templates.${submoduleInputs.config._module.args.name}.path;
readOnly = true;
};
owner = mkOption { type = types.nullOr types.str; default = null; };
group = mkOption { type = types.nullOr types.str; default = null; };
mode = mkOption { type = types.str; default = "0400"; };
file = mkOption
{
type = types.path;
default = inputs.config.sops.templates.${submoduleInputs.config._module.args.name}.file;
readOnly = true;
};
};}));
default = {};
};
# define default in config
placeholder = mkOption { type = types.attrsOf types.str; };
defaultSopsFile = mkOption
{
type = types.nonEmptyListOf types.path;
readOnly = true;
default =
let
defaultSopsFile = path:
if builtins.pathExists "${path}/secrets.yaml" then [ "${path}/secrets.yaml" ]
else if builtins.pathExists "${path}/secrets/default.yaml" then [ "${path}/secrets/default.yaml" ]
else [];
devicePath = "${inputs.topInputs.self}/devices";
inherit (inputs.config.nixos) model;
in
[]
++ (inputs.lib.optionals (model.cluster == null) (defaultSopsFile "${devicePath}/${model.hostname}"))
++ (inputs.lib.optionals (model.cluster != null)
(
(defaultSopsFile "${devicePath}/${model.cluster.clusterName}/${model.cluster.nodeName}")
++ (defaultSopsFile "${devicePath}/${model.cluster.clusterName}")
))
++ (inputs.lib.optionals model.private [ "${devicePath}/cross/secrets/chn.yaml" ])
++ (defaultSopsFile "${devicePath}/cross");
};
availableKeys = mkOption
{
type = types.listOf (types.listOf types.str);
readOnly = true;
default =
let getPath = x:
if builtins.typeOf x == "string" then []
else if builtins.typeOf x == "set" then inputs.lib.mapAttrsToList (n: v: [ n ] ++ getPath v) x
else builtins.abort "Invalid type for availableKeys";
in builtins.concatLists (builtins.map getPath inputs.config.nixos.system.sops.defaultSopsFile);
};
};
config =
{
nixos.system.sops.placeholder = builtins.mapAttrs
(n: _: inputs.lib.mkOptionDefault "sops${builtins.hashString "sha256" n}sops")
inputs.config.nixos.system.sops.secrets;
sops =
{
defaultSopsFile =
let deviceDir =
if (inputs.config.nixos.model.cluster == null) then
"${inputs.topInputs.self}/devices/${inputs.config.nixos.model.hostname}"
else
"${inputs.topInputs.self}/devices/${inputs.config.nixos.model.cluster.clusterName}"
+ "/${inputs.config.nixos.model.cluster.nodeName}";
in inputs.lib.mkMerge
[
(inputs.lib.mkIf (builtins.pathExists "${deviceDir}/secrets.yaml") "${deviceDir}/secrets.yaml")
(inputs.lib.mkIf (builtins.pathExists "${deviceDir}/secrets/default.yaml")
"${deviceDir}/secrets/default.yaml")
];
# sops start before impermanence, so we need to use the absolute path
secrets = builtins.mapAttrs
(n: v: { inherit (v) key format mode owner group sopsFile neededForUsers; })
inputs.config.nixos.system.sops.secrets;
templates = builtins.mapAttrs
(n: v: { inherit (v) content owner group mode; })
inputs.config.nixos.system.sops.templates;
inherit (inputs.config.nixos.system.sops) placeholder;
age.sshKeyPaths = [ "/nix/persistent/etc/ssh/ssh_host_ed25519_key" ];
};
};

View File

@@ -5,12 +5,8 @@ inputs:
home-manager.users.chn = homeInputs:
{
config.xdg.configFile."sops/age/keys.txt".source =
homeInputs.config.lib.file.mkOutOfStoreSymlink inputs.config.sops.secrets."chn/age".path;
};
sops.secrets."chn/age" =
{
owner = "chn";
sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/chn.yaml";
homeInputs.config.lib.file.mkOutOfStoreSymlink inputs.config.nixos.system.sops.secrets."chn/age".path;
};
nixos.system.sops.secrets."chn/age".owner = "chn";
};
}

View File

@@ -40,30 +40,23 @@ inputs:
{
name = ".ssh/id_${type}";
value.source = homeInputs.config.lib.file.mkOutOfStoreSymlink
inputs.config.sops.secrets."chn/${type}".path;
inputs.config.nixos.system.sops.secrets."chn/${type}".path;
})
[ "rsa" "rsa.ppk" "ed25519" "ed25519_sk" ]
))
// {
".ssh/xmuhk_id_rsa".source =
homeInputs.config.lib.file.mkOutOfStoreSymlink inputs.config.sops.secrets."chn/xmuhk".path;
homeInputs.config.lib.file.mkOutOfStoreSymlink inputs.config.nixos.system.sops.secrets."chn/xmuhk".path;
}
);
};
};
sops.secrets = inputs.lib.mkIf inputs.config.nixos.model.private (inputs.lib.mkMerge
nixos.system.sops.secrets = inputs.lib.mkIf inputs.config.nixos.model.private (inputs.lib.mkMerge
[
(builtins.listToAttrs (builtins.map
(name:
{
name = "chn/${name}";
value = { owner = "chn"; sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/chn.yaml"; };
})
(name: inputs.lib.nameValuePair "chn/${name}" { owner = "chn"; })
[ "rsa" "rsa.ppk" "ed25519" "ed25519_sk" "xmuhk" ]))
{
"root/ed25519_sk" =
{ key = "chn/ed25519_sk"; sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/chn.yaml"; };
}
{ "root/ed25519_sk".key = "chn/ed25519_sk"; }
]);
};
}

View File

@@ -101,17 +101,15 @@ inputs:
}
# set hashedPassword if it exist in secrets
(
let
sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/default.yaml";
secrets = inputs.pkgs.localPackages.fromYaml (builtins.readFile sopsFile);
hashedPasswordExist = userName: (secrets ? users) && ((secrets.users or {}) ? ${userName});
let hashedPasswordExist = userName: inputs.lib.lists.any
(inputs.lib.lists.hasPrefix [ "users" userName ]) inputs.config.nixos.system.sops.availableKeys;
in
{
users.users = builtins.listToAttrs (builtins.map
(name: { inherit name; value.hashedPasswordFile = inputs.config.sops.secrets."users/${name}".path; })
(builtins.filter (user: hashedPasswordExist user) user.users));
sops.secrets = builtins.listToAttrs (builtins.map
(name: { name = "users/${name}"; value = { neededForUsers = true; inherit sopsFile; }; })
nixos.system.sops.secrets = builtins.listToAttrs (builtins.map
(name: inputs.lib.nameValuePair "users/${name}" { neededForUsers = true; })
(builtins.filter (user: hashedPasswordExist user) user.users));
}
)
@@ -143,7 +141,7 @@ inputs:
home.file = inputs.lib.mkIf inputs.config.nixos.model.private
{
".ssh/id_ed25519_sk".source = homeInputs.config.lib.file.mkOutOfStoreSymlink
inputs.config.sops.secrets."root/ed25519_sk".path;
inputs.config.nixos.system.sops.secrets."root/ed25519_sk".path;
};
};
};