Compare commits

..
Author SHA1 Message Date
h7x4 af69c27fe2 base/auditd: init 2026-07-25 02:00:32 +09:00
h7x4 fcc06d47c2 base/sshd: accept some useful envvars 2026-07-24 16:03:54 +09:00
h7x4andoysteikt d13df223bf bicep/mysql: add timed jobs for analyze and optimize 2026-07-22 15:09:10 +02:00
h7x4 1c4e8e7662 base/postfix: remove, base:nullmailer: init 2026-07-22 21:12:00 +09:00
h7x4 207bd1975e kommode/gitea: add robots.txt 2026-07-22 21:02:22 +09:00
h7x4andoysteikt 28794691bf bicep/{postgres,mysql}: bindmount data storage with noatime 2026-07-22 13:01:02 +02:00
h7x4 1ff34d7aab secrets: add passwords for gatus dbms checkers 2026-07-21 18:44:51 +09:00
h7x4 3d551fab52 ildkule/gatus: add healthcheck for mariadb 2026-07-21 18:44:51 +09:00
h7x4 a99a83c0d8 ildkule/gatus: add healthcheck for postgresql 2026-07-21 18:44:50 +09:00
h7x4 9a837d210d bicep/postgres: log connections/disconnections 2026-07-21 16:39:25 +09:00
h7x4 d3c9fabbc2 base/irqbalance: only start on multi-socket machines 2026-07-21 16:38:38 +09:00
h7x4 950b163869 bicep/postgresql: use scram-sha-256 as default password algorithm 2026-07-21 16:32:49 +09:00
h7x4 9bd81430a4 topology: remove (now) redundant mysql service extractor 2026-07-20 23:20:02 +09:00
h7x4 9b38b4b8d3 flake.lock: bump 2026-07-20 22:30:39 +09:00
h7x4 6abc05dc4d treewide: have rwhod ignore always logged-in users 2026-07-20 21:51:57 +09:00
h7x4 2e3ac911cb skrot: split drumknotty service details into separate file 2026-07-20 21:39:16 +09:00
h7x4 16b0d05d27 flake.lock: bump roowho2 2026-07-20 21:34:29 +09:00
h7x4 fe19bb9bdb ildkule/gatus/minecraft-checker: rewrite to use python-http-handlers module 2026-07-20 19:37:28 +09:00
h7x4 f4f9836deb modules/python-http-handlers: init 2026-07-20 19:37:26 +09:00
h7x4 fb7e350ac7 flake.lock: bump dibbler 2026-07-18 18:44:28 +09:00
h7x4 3c3bf6b10f modules/drumknotty: provide state directories for all services 2026-07-18 18:42:26 +09:00
h7x4 b0e3d90c20 ildkule/gatus/minecraft-checker: init 2026-07-07 16:26:26 +09:00
h7x4 111c3e21bd ildkule/gatus: init 2026-07-07 16:26:06 +09:00
h7x4 decd8b04c1 ildkule/uptime-kuma: remove 2026-07-06 05:31:50 +09:00
h7x4 4b8be337e0 lupine5/openvpn: additional config, open firewall 2026-07-06 02:37:17 +09:00
h7x4 fcfcb07e59 lupine5: register knutsen-vpn ip 2026-07-06 02:37:16 +09:00
h7x4 1e66049c79 lupine5/openvpn: use certs 2026-07-06 02:37:16 +09:00
h7x4 928ddde344 sops/lupine: add CA + 2 keypairs for OpenVPN 2026-07-06 02:37:16 +09:00
h7x4 3aa8d0b418 lupine5/openvpn: init 2026-07-05 01:31:15 +09:00
h7x4 293f28abb1 lupine5: set up bridge and tap netdevs 2026-07-05 01:01:35 +09:00
h7x4 f4b1f090e4 flake.lock: bump various 2026-06-30 04:15:37 +09:00
h7x4 7c684e42f0 treewide: fix rsync <-> rrsync communication 2026-06-30 02:41:40 +09:00
h7x4 90bfda9066 kommode/gitea: bump AVATAR_MAX_ORIGIN_SIZE from 2MB to 4MB 2026-06-24 14:33:20 +09:00
h7x4 522d8f18cb flake.{nix,lock}: bump roowho2 2026-06-24 13:38:03 +09:00
h7x4 5e613a03fc treewide: set relatime for most root mounts 2026-06-23 01:12:16 +09:00
h7x4 170fb2a980 bicep/synapse: fix dbname option 2026-06-22 18:55:14 +09:00
h7x4 3e627472e9 flake.{nix,lock}: bump matrix-next 2026-06-22 18:55:13 +09:00
Adrian G Landoysteikt e05c4ed8ca feat: add initialdeploy hashed password to root 2026-06-21 18:24:01 +02:00
h7x4 3fee83ec05 ildkule/loki: restrict incoming connections to pvv + ntnu 2026-06-22 01:23:16 +09:00
h7x4 a1f02fc39d {ildkule/loki,base/fluentbit}: send data over https 2026-06-22 01:23:16 +09:00
6e37635aac ildkule/loki: firewall all endpoints except push API
Co-authored-by: Øystein Kristoffer Tveit <oysteikt@pvv.ntnu.no>
2026-06-22 01:23:14 +09:00
h7x4 cdc3ad488b bicep/postgres: add script for updating all collations 2026-06-22 01:12:59 +09:00
h7x4 aa2712005a temmie/nfs-mounts: create by-uid bindmounts 2026-06-17 13:43:19 +09:00
h7x4 89921b533b temmie/userweb: further harden log-processor 2026-06-17 12:31:02 +09:00
h7x4 75f87ffab8 temmie/userweb: run passwd sync in different unit 2026-06-17 12:15:23 +09:00
h7x4 b910cf9563 temmie/userweb: suppress erroneous access log for documentRoot 2026-06-17 08:57:55 +09:00
h7x4 d23adbd4c2 temmie/userweb: deny access to documentRoot 2026-06-17 08:49:44 +09:00
h7x4 48c0a4e504 temmie/userweb: fix directory denylist enforcement 2026-06-17 08:23:08 +09:00
h7x4 374d9b1bc7 flake.nix: passthru machine config, pkgs and config.system.build
This shortens down the path needed to build both overlayed packages and
all the other machine derivations. Here are some examples:

```
nix build .#machine.etc
nix build '.#machine.units."nginx.service".unit'
nix build .#machine.pkgs.overlayed-package
nix build .#machine.config.services.nginx.package
```
2026-06-17 08:10:17 +09:00
h7x4 d84cc73819 temmie/userweb: handle more .php\d suffixes 2026-06-16 19:07:58 +09:00
h7x4 b738f08c09 temmie/userweb: render path denylist into Directory/Files directives 2026-06-16 19:07:57 +09:00
h7x4 8252bba3ad temmie/userweb: enable httpd trace on debugMode 2026-06-16 19:07:57 +09:00
h7x4 a776a5a5fe temmie/userweb: explicitly override mod_perl and mod_userdir 2026-06-16 19:07:57 +09:00
h7x4 ed57744ec3 temmie/userweb: add more patterns to denylist 2026-06-16 16:07:32 +09:00
h7x4 226db1f46e temmie/userweb: add more DirectoryIndex variants 2026-06-16 16:07:32 +09:00
h7x4 51e1656177 temmie/userweb: disable ~pvv 2026-06-16 15:53:52 +09:00
h7x4 47d2dcf9ff temmie/userweb: add bro server to userweb slice 2026-06-16 03:37:28 +09:00
h7x4 254b1d9b14 temmie/userweb: split into more modules 2026-06-16 03:33:28 +09:00
h7x4 2301672a21 temmie/userweb: run log processors as separate systemd units
This lets us divide up some of the logic making httpd itself less
brittle, and also reduces the amount of privileges for httpd.
2026-06-16 02:56:28 +09:00
felixalb 7145abadf3 flake: update input pvv-nettsiden 2026-06-13 16:59:50 +02:00
h7x4 b533b09c8f base/various: add to slice system-monitoring 2026-06-13 04:45:39 +09:00
h7x4 526b55c49a {ildkule/prometheus,base}: send stats over HTTPS through nginx 2026-06-13 02:54:28 +09:00
h7x4 e80189c6eb temmie/userweb: stop cating passwd on startup 2026-06-13 01:41:05 +09:00
h7x4 56a51e4c6f temmie/userweb: mount homedirs under /amd 2026-06-13 01:39:20 +09:00
h7x4 f54109f6f3 temmie/userweb: set handlers for php and perl scripts 2026-06-13 01:26:27 +09:00
Vegard Bieker Matthey 5763a76136 user/vegardbm: change shell to zsh and add ssh key 2026-06-08 11:35:44 +02:00
h7x4 b57a935b4c base/rsyslogd: init 2026-06-08 12:58:37 +09:00
66 changed files with 2387 additions and 971 deletions
+10 -2
View File
@@ -14,7 +14,6 @@
./mitigations.nix
./flake-input-exporter.nix
./hardening.nix
./networking.nix
./nix.nix
@@ -23,6 +22,7 @@
./vm.nix
./services/acme.nix
./services/auditd.nix
./services/auto-upgrade.nix
./services/dbus.nix
./services/fluentbit.nix
@@ -31,12 +31,14 @@
./services/journald-upload.nix
./services/logrotate.nix
./services/nginx.nix
./services/nullmailer.nix
./services/openssh.nix
./services/polkit.nix
./services/postfix.nix
./services/prometheus-flake-input-exporter.nix
./services/prometheus-node-exporter.nix
./services/prometheus-systemd-exporter.nix
./services/roowho2.nix
./services/rsyslogd.nix
./services/scrutiny-collector.nix
./services/smartd.nix
./services/thermald.nix
@@ -94,8 +96,14 @@
AllowHibernation = lib.mkDefault false;
};
systemd.slices."system-monitoring" = {
description = "Monitoring related services";
};
# users.mutableUsers = lib.mkDefault false;
users.users.root.initialHashedPassword = "$y$j9T$ahP6GAdttD17OMBo7Yqeh.$Ad7qBcFvTL7HrJ9uTtrQzksN3220Nj9t/CrP6DwgK34"; # generated using mkpasswd, see huttiheita root on vaultwarden
users.groups."drift".name = "drift";
# Trusted users on the nix builder machines
-55
View File
@@ -1,55 +0,0 @@
{
config,
inputs,
lib,
pkgs,
values,
...
}:
let
data = lib.flip lib.mapAttrs inputs (
name: input: {
inherit (input)
lastModified
;
}
);
folder = pkgs.writeTextDir "share/flake-inputs" (
lib.concatMapStringsSep "\n" (
{ name, value }: ''nixos_last_modified_input{flake="${name}"} ${toString value.lastModified}''
) (lib.attrsToList data)
);
port = 9102;
in
{
services.nginx.virtualHosts."${config.networking.fqdn}-nixos-metrics" = {
serverName = config.networking.fqdn;
serverAliases = [
"${config.networking.hostName}.pvv.org"
];
locations."/metrics" = {
root = "${folder}/share";
tryFiles = "/flake-inputs =404";
extraConfig = ''
default_type text/plain;
'';
};
listen = [
{
inherit port;
addr = "0.0.0.0";
}
];
extraConfig = ''
allow ${values.hosts.ildkule.ipv4}/32;
allow ${values.hosts.ildkule.ipv6}/128;
allow 127.0.0.1/32;
allow ::1/128;
allow ${values.ipv4-space};
allow ${values.ipv6-space};
deny all;
'';
};
networking.firewall.allowedTCPPorts = [ port ];
}
-1
View File
@@ -8,6 +8,5 @@
# Let's not spam LetsEncrypt in `nixos-rebuild build-vm` mode:
virtualisation.vmVariant = {
security.acme.defaults.server = "https://127.0.0.1";
users.users.root.initialPassword = "root";
};
}
+56
View File
@@ -0,0 +1,56 @@
{ config, lib, pkgs, ... }:
{
security.audit = {
enable = lib.mkDefault true;
# NOTE: see auditctl(8) for the meaning of the different rule flags.
rules = [
# Kernel module loading/unloading
"-a always,exit -F arch=b64 -S init_module,finit_module,delete_module -k kernel-modules"
# Mount/unmount by real (non-service) users
"-a always,exit -F arch=b64 -S mount,umount2 -F auid>=1000 -F auid!=-1 -k mounts"
# DAC permission/ownership changes by real users
"-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F auid>=1000 -F auid!=-1 -k perm-mod"
"-a always,exit -F arch=b64 -S chown,fchown,fchownat,lchown -F auid>=1000 -F auid!=-1 -k perm-mod"
"-a always,exit -F arch=b64 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>=1000 -F auid!=-1 -k perm-mod"
# Failed access attempts (permission denied) by real users
"-a always,exit -F arch=b64 -S open,openat,creat,truncate,ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=-1 -k access"
"-a always,exit -F arch=b64 -S open,openat,creat,truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=-1 -k access"
# File deletion/rename by real users
"-a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F auid>=1000 -F auid!=-1 -k delete"
# Execution of privileged commands
"-w ${config.security.wrapperDir}/sudo -p x -k privileged-sudo"
"-w ${config.security.wrapperDir}/su -p x -k privileged-su"
# Read of files containing secrets.
"-w /var/lib/sops-nix/key.txt -p r -k secrets"
"-w /run/secrets -p r -k secrets"
"-w /etc/ssh/ssh_host_ed25519_key -p r -k secrets"
"-w /etc/ssh/ssh_host_rsa_key -p r -k secrets"
# NixOS generation switching
"-w /nix/var/nix/profiles -p wa -k nixos-generation-switch"
# Switching bootloader content
"-w /boot -p wa -k boot-tampering"
# Login records
"-w /var/lib/lastlog2 -p wa -k logins"
# Write or append to the audit trail
"-w /var/log/audit -p wa -k audit-log-tampering"
"-w ${lib.getExe' pkgs.audit "auditctl"} -p x -k audit-tools"
];
};
security.auditd = {
enable = lib.mkDefault true;
plugins.syslog.active = true;
plugins.af_unix.active = true;
};
}
+5 -2
View File
@@ -62,8 +62,10 @@ in
name = "loki";
match = "*";
host = "ildkule.pvv.ntnu.no";
port = 3100;
host = "loki.pvv.ntnu.no";
port = 443;
tls = "on";
"tls.verify" = "on";
uri = "/loki/api/v1/push";
compress = "gzip";
@@ -88,6 +90,7 @@ in
systemd.services.fluent-bit = lib.mkIf cfg.enable {
serviceConfig = {
Slice = "system-monitoring.slice";
StateDirectory = "fluent-bit";
# NOTE: This hardening might be way too strong for general purpose use, don't upstream this.
+19 -1
View File
@@ -1,4 +1,22 @@
{ ... }:
{ config, pkgs, lib, ... }:
let
cfg = config.services.irqbalance;
in
{
services.irqbalance.enable = true;
# irqbalance only has meaningful work to do on multi-socket machines, so
# skip starting it pointlessly everywhere else.
systemd.services.irqbalance.serviceConfig.ExecCondition = let
isMultiSocket = pkgs.writeShellApplication {
name = "irqbalance-is-multi-socket";
runtimeInputs = [ pkgs.coreutils ];
text = ''
sockets=$(cat /sys/devices/system/cpu/cpu*/topology/physical_package_id | sort -u | wc -l)
[ "$sockets" -gt 1 ]
'';
};
in lib.mkIf cfg.enable [
(lib.getExe isMultiSocket)
];
}
+1
View File
@@ -14,6 +14,7 @@ in
};
systemd.services."systemd-journal-upload".serviceConfig = lib.mkIf cfg.enable {
Slice = "system-monitoring.slice";
IPAddressDeny = "any";
IPAddressAllow = [
values.hosts.ildkule.ipv4
+2 -24
View File
@@ -1,18 +1,5 @@
{ config, lib, ... }:
{
# nginx return 444 for all nonexistent virtualhosts
systemd.services.nginx.after = [ "generate-snakeoil-certs.service" ];
environment.snakeoil-certs = lib.mkIf config.services.nginx.enable {
"/etc/certs/nginx" = {
owner = "nginx";
group = "nginx";
};
};
networking.firewall.allowedTCPPorts = lib.mkIf config.services.nginx.enable [ 80 443 ];
services.nginx = {
recommendedTlsSettings = true;
recommendedProxySettings = true;
@@ -60,17 +47,8 @@
];
}
];
sslCertificate = "/etc/certs/nginx.crt";
sslCertificateKey = "/etc/certs/nginx.key";
addSSL = true;
extraConfig = "return 444;";
};
};
${config.networking.fqdn} = {
sslCertificate = lib.mkDefault "/etc/certs/nginx.crt";
sslCertificateKey = lib.mkDefault "/etc/certs/nginx.key";
addSSL = lib.mkDefault true;
extraConfig = lib.mkDefault "return 444;";
};
};
networking.firewall.allowedTCPPorts = lib.mkIf config.services.nginx.enable [ 80 443 ];
}
+15
View File
@@ -0,0 +1,15 @@
{ config, lib, ... }:
{
services.nullmailer = {
enable = true;
config = {
adminaddr = "root@pvv.ntnu.no";
defaultdomain = "pvv.ntnu.no";
defaulthost = "pvv.ntnu.no";
me = lib.mkDefault config.networking.fqdn;
remotes = lib.mkDefault "smtp.pvv.ntnu.no smtp port=465 tls";
};
};
}
+7 -1
View File
@@ -10,8 +10,14 @@
Match All
'';
settings.PermitRootLogin = "yes";
settings.AcceptEnv = [
"LANG"
"LC_*"
"COLORTERM"
"GIT_PROTOCOL"
];
};
users.users."root".openssh.authorizedKeys.keys = [
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCqVt4LCe0YIttr9swFxjkjn37ZDY9JxwVC+2gvfSINDJorOCtqPjDOTD2fTS1Gz08QCwpnLWq2kyvRchu6WgriAbSACpbZZBgxRaF/FVh3oiMVFGnNKGnv6/fdo/vZtu8mUVuqtmTrgLYpZdbR4oD3XiBlDKs7Cv5hPqt95lnP6MNFvE8mICCfd1PwhsABd2IQ5laz3u77/RXhNFJL0Kf2/+6gk9awcLuwHrPdvq7c3BxRHbc9UMRQENyjyQPa7aLe+uJBFLKP51I8VBuDpDacuibQx7nMt6N2UJ2KWI0JxRMHuJNq4S5jidR82aOw9gzGbTv30SKNLMqsZ0xj4LtdqCXDiZF6Lr09PsJYsvnBUFWa14HGcThKDtgwQwBryNViYmfv//0h9+RLZiU0ab+NEwSs7Zh5iAD+vhx64QqNX3tR7Le4SWXh8W0eShU9N78qYdSkiC3Ui7htxeqOocXM/P4AwbnHsLELIvkHdvgchCPvl8ygZa4WJTEWv16+ICskJcAKWGuqjvXAFuwjJJmPp9xLW9O0DFfQhMELiGamQR9wK07yYQVr34iah6qZO7cwhSKyEPFrVPIaNtfDhsjED639F7vmktf26SWNJHWfW0wOHILjI6TgqUvy0JDd8W8w0CHlAfz6Fs2l99NNgNF8dB3vBASbxS0hu/y0PVu/xQ== openstack-sleipner"
-22
View File
@@ -1,22 +0,0 @@
{ config, pkgs, lib, ... }:
let
cfg = config.services.postfix;
in
{
services.postfix = {
enable = true;
settings.main = {
myhostname = "${config.networking.hostName}.pvv.ntnu.no";
mydomain = "pvv.ntnu.no";
# Nothing should be delivered to this machine
mydestination = [ ];
relayhost = [ "smtp.pvv.ntnu.no:465" ];
smtp_tls_wrappermode = "yes";
smtp_tls_security_level = "encrypt";
};
};
}
@@ -0,0 +1,47 @@
{
config,
inputs,
lib,
pkgs,
values,
...
}:
let
data = lib.flip lib.mapAttrs inputs (
name: input: {
inherit (input)
lastModified
;
}
);
folder = pkgs.writeTextDir "share/flake-inputs" (
lib.concatMapStringsSep "\n" (
{ name, value }: ''nixos_last_modified_input{flake="${name}"} ${toString value.lastModified}''
) (lib.attrsToList data)
);
in
{
services.nginx = {
enable = lib.mkDefault true;
virtualHosts.${config.networking.fqdn} = lib.mkIf config.services.nginx.enable {
forceSSL = true;
enableACME = true;
kTLS = true;
locations."/prometheus-nixos-flake-input-exporter/metrics" = {
root = "${folder}/share";
tryFiles = "/flake-inputs =404";
extraConfig = ''
default_type text/plain;
allow 127.0.0.1;
allow ::1;
allow ${values.hosts.ildkule.ipv4};
allow ${values.hosts.ildkule.ipv6};
deny all;
'';
};
};
};
}
+24 -9
View File
@@ -5,19 +5,34 @@ in
{
services.prometheus.exporters.node = {
enable = lib.mkDefault true;
listenAddress = "127.0.0.1";
port = 9100;
enabledCollectors = [ "systemd" ];
};
systemd.services.prometheus-node-exporter.serviceConfig = lib.mkIf cfg.enable {
IPAddressDeny = "any";
IPAddressAllow = [
"127.0.0.1"
"::1"
values.hosts.ildkule.ipv4
values.hosts.ildkule.ipv6
];
services.nginx = lib.mkIf cfg.enable {
enable = lib.mkDefault true;
virtualHosts.${config.networking.fqdn} = lib.mkIf config.services.nginx.enable {
forceSSL = true;
enableACME = true;
kTLS = true;
locations."/prometheus-node-exporter/metrics" = {
proxyPass = "http://localhost:${toString cfg.port}/metrics";
extraConfig = ''
allow 127.0.0.1;
allow ::1;
allow ${values.hosts.ildkule.ipv4};
allow ${values.hosts.ildkule.ipv6};
deny all;
'';
};
};
};
networking.firewall.allowedTCPPorts = lib.mkIf cfg.enable [ cfg.port ];
systemd.services = lib.mkIf cfg.enable {
"prometheus-node-exporter".serviceConfig.Slice = "system-monitoring.slice";
};
}
+24 -9
View File
@@ -5,6 +5,7 @@ in
{
services.prometheus.exporters.systemd = {
enable = lib.mkDefault true;
listenAddress = "127.0.0.1";
port = 9101;
extraFlags = [
"--systemd.collector.enable-restart-count"
@@ -12,15 +13,29 @@ in
];
};
systemd.services.prometheus-systemd-exporter.serviceConfig = {
IPAddressDeny = "any";
IPAddressAllow = [
"127.0.0.1"
"::1"
values.hosts.ildkule.ipv4
values.hosts.ildkule.ipv6
];
services.nginx = lib.mkIf cfg.enable {
enable = lib.mkDefault true;
virtualHosts.${config.networking.fqdn} = lib.mkIf config.services.nginx.enable {
forceSSL = true;
enableACME = true;
kTLS = true;
locations."/prometheus-systemd-exporter/metrics" = {
proxyPass = "http://localhost:${toString cfg.port}/metrics";
extraConfig = ''
allow 127.0.0.1;
allow ::1;
allow ${values.hosts.ildkule.ipv4};
allow ${values.hosts.ildkule.ipv6};
deny all;
'';
};
};
};
networking.firewall.allowedTCPPorts = lib.mkIf cfg.enable [ cfg.port ];
systemd.services = lib.mkIf cfg.enable {
"prometheus-systemd-exporter".serviceConfig.Slice = "system-monitoring.slice";
};
}
+20
View File
@@ -0,0 +1,20 @@
{ config, lib, ... }:
let
cfg = config.services.rsyslogd;
in
{
services.rsyslogd = {
enable = lib.mkDefault true;
defaultConfig = ''
*.* @loghost.pvv.ntnu.no
'';
};
services.journald.extraConfig = lib.mkIf cfg.enable ''
ForwardToSyslog=yes
'';
systemd.services = lib.mkIf cfg.enable {
"syslog".serviceConfig.Slice = "system-monitoring.slice";
};
}
+3 -1
View File
@@ -23,7 +23,7 @@ in
};
};
systemd.services.uptimed = lib.mkIf (cfg.enable) {
systemd.services.uptimed = lib.mkIf cfg.enable {
serviceConfig = let
uptimed = pkgs.uptimed.overrideAttrs (prev: {
postPatch = ''
@@ -35,6 +35,8 @@ in
});
in {
Slice = "system-monitoring.slice";
Type = "notify";
ExecStart = lib.mkForce "${uptimed}/sbin/uptimed -f";
Generated
+71 -71
View File
@@ -24,11 +24,11 @@
},
"crane": {
"locked": {
"lastModified": 1776635034,
"narHash": "sha256-OEOJrT3ZfwbChzODfIH4GzlNTtOFuZFWPtW7jIeR8xU=",
"lastModified": 1784407669,
"narHash": "sha256-gcFMcRjw0ZSn380Rx2QLlU1goUQeSrKX/DF12omI6+o=",
"owner": "ipetkov",
"repo": "crane",
"rev": "dc7496d8ea6e526b1254b55d09b966e94673750f",
"rev": "1316b7d278ad77a16aec024b71d971366e123bec",
"type": "github"
},
"original": {
@@ -44,11 +44,11 @@
]
},
"locked": {
"lastModified": 1771267058,
"narHash": "sha256-EEL4SmD1b3BPJPsSJJ4wDTXWMumJqbR+BLzhJJG0skE=",
"lastModified": 1784367836,
"narHash": "sha256-yeWTb3KNvHY/InqbVmIjQRH5BI4d2HFbQqWi2eRKiv0=",
"ref": "main",
"rev": "e3962d02c78b9c7b4d18148d931a9a4bf22e7902",
"revCount": 254,
"rev": "422f383fd8736d60cd2fe818168b93d07f013865",
"revCount": 259,
"type": "git",
"url": "https://git.pvv.ntnu.no/Projects/dibbler.git"
},
@@ -104,11 +104,11 @@
]
},
"locked": {
"lastModified": 1777067150,
"narHash": "sha256-vqPz8jCS1zTQlvmgctUFpvnr6f9ISR5h7CPG/HgQvf0=",
"lastModified": 1784553797,
"narHash": "sha256-buGdmnsKNRDUNsb+aXGeUc/UjGGsMbH1KWy3xnheInA=",
"ref": "main",
"rev": "b452a854fb78d6df9fe062b45e23a968657d115d",
"revCount": 35,
"rev": "c3101eb7424d4b15665bd00624220ec411187797",
"revCount": 36,
"type": "git",
"url": "https://git.pvv.ntnu.no/Grzegorz/gergle.git"
},
@@ -126,11 +126,11 @@
"rust-overlay": "rust-overlay_2"
},
"locked": {
"lastModified": 1777019032,
"narHash": "sha256-29lw7THThWb5DW01rVRj1b816Apwz/P4m2wVWaSIadU=",
"lastModified": 1784553736,
"narHash": "sha256-W1pPlTHmp+EvONwf8Qa5NvCiuyV4LC/yNDdc27RSpuA=",
"ref": "main",
"rev": "55262afca46c96f75a834d4e00e30d5fb20affb6",
"revCount": 61,
"rev": "e06daaef1f48160254c202c59b060ac6f1da9f38",
"revCount": 62,
"type": "git",
"url": "https://git.pvv.ntnu.no/Grzegorz/greg-ng.git"
},
@@ -169,11 +169,11 @@
]
},
"locked": {
"lastModified": 1769338528,
"narHash": "sha256-t18ZoSt9kaI1yde26ok5s7aFLkap1Q9+/2icVh2zuaE=",
"lastModified": 1780178524,
"narHash": "sha256-2PcNyNqbGCWBpAMdCU1HxSQmhQiG6evdjxVnPA7w5bQ=",
"ref": "refs/heads/main",
"rev": "7218348163fd8d84df4a6f682c634793e67a3fed",
"revCount": 13,
"rev": "2406de41ce9d0a1404cbf4e55537e3f720f37f23",
"revCount": 15,
"type": "git",
"url": "https://git.pvv.ntnu.no/Projects/libdib.git"
},
@@ -189,16 +189,16 @@
]
},
"locked": {
"lastModified": 1764844095,
"narHash": "sha256-Drf1orxsmFDzO+UbPo85gHjXW7QzAM+6oTPvI7vOSik=",
"lastModified": 1782122067,
"narHash": "sha256-95q3DiYOTHjQGbqR0I1w4ETrH+smtddqW0bBxaB/Egg=",
"owner": "dali99",
"repo": "nixos-matrix-modules",
"rev": "25b9f31ef1dbc3987b4c716de716239f2b283701",
"rev": "0e0fd9f6a407b08dd5e180a2ff6c3808461e2c47",
"type": "github"
},
"original": {
"owner": "dali99",
"ref": "v0.8.0",
"ref": "master",
"repo": "nixos-matrix-modules",
"type": "github"
}
@@ -211,11 +211,11 @@
"rust-overlay": "rust-overlay_3"
},
"locked": {
"lastModified": 1767906976,
"narHash": "sha256-igCg8I83eO+noF00raXVJqDxzLS2SrZN8fK5bnvO+xI=",
"lastModified": 1784554105,
"narHash": "sha256-lgtCXgYCf0ljf14H7K7ngxnUc30FwcHMJlDZx+7Nt8s=",
"ref": "main",
"rev": "626bc9b6bae6a997b347cdbe84080240884f2955",
"revCount": 17,
"rev": "cbd5b7318239303e19e8a7a407699ed85cc25d94",
"revCount": 18,
"type": "git",
"url": "https://git.pvv.ntnu.no/Projects/minecraft-heatmap.git"
},
@@ -232,11 +232,11 @@
]
},
"locked": {
"lastModified": 1769500363,
"narHash": "sha256-vFxmdsLBPdTy5j2bf54gbTQi1XnWbZDmeR/BBh8MFrw=",
"lastModified": 1784554069,
"narHash": "sha256-5UNUBVAAMEvLanAyOgm6yGZgKJoTAZ2gXavKbMH+6OA=",
"ref": "main",
"rev": "2618e434e40e109eaab6a0693313c7e0de7324a3",
"revCount": 47,
"rev": "62ffa4f7de826ced2c2a8ad787695118589450bb",
"revCount": 48,
"type": "git",
"url": "https://git.pvv.ntnu.no/Projects/minecraft-kartverket.git"
},
@@ -275,11 +275,11 @@
]
},
"locked": {
"lastModified": 1778407980,
"narHash": "sha256-r980BhsReZQe6FkmyNZkwCZpvzARo5jZgTl8HxjAssY=",
"lastModified": 1782153600,
"narHash": "sha256-Vbkgl7/x8+Gg0gMe94EStfIfNC4bHQIbaZrIAxpuQ/w=",
"owner": "oddlama",
"repo": "nix-topology",
"rev": "ca0a602f650306d00d6f3e3c76d0f4c48a5c5adc",
"rev": "e61876f548e4f301d63640d30ecc1305c05c3986",
"type": "github"
},
"original": {
@@ -291,11 +291,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1779622335,
"narHash": "sha256-06G98ieM6l+OI7EMhlvchgDBDn+DvIWCNj40LDhKpmc=",
"rev": "705e9929918b43bd7b715dc0a878ac870449bb03",
"lastModified": 1784526640,
"narHash": "sha256-UDnuu3uM64qjfVvsGSislJgP1j15FiFiDiKOjbGTv9Q=",
"rev": "036c2421db75172aeef4bb83921988891d4773c9",
"type": "tarball",
"url": "https://releases.nixos.org/nixos/26.05-small/nixos-26.05beta1.705e9929918b/nixexprs.tar.xz"
"url": "https://releases.nixos.org/nixos/26.05-small/nixos-26.05.5692.036c2421db75/nixexprs.tar.xz"
},
"original": {
"type": "tarball",
@@ -319,11 +319,11 @@
},
"nixpkgs-unstable": {
"locked": {
"lastModified": 1778586796,
"narHash": "sha256-XmDljcG4x8slQDlsWOc77pCA1YVuYn8JGumkYlhfTxI=",
"rev": "b25e938b89759b5f9466fc53c4a970244f84dc39",
"lastModified": 1784536202,
"narHash": "sha256-7CmHmK10lEXBgymS0DeYj4/4STLpzRWCc/5BfoIxHQo=",
"rev": "94f12be79cb7f961726a0157b4168bc722befeac",
"type": "tarball",
"url": "https://releases.nixos.org/nixos/unstable-small/nixos-26.05pre996582.b25e938b8975/nixexprs.tar.xz"
"url": "https://releases.nixos.org/nixos/unstable-small/nixos-26.11pre1037880.94f12be79cb7/nixexprs.tar.xz"
},
"original": {
"type": "tarball",
@@ -358,11 +358,11 @@
]
},
"locked": {
"lastModified": 1779774845,
"narHash": "sha256-QJU1J4eupwjRrtvWGzRut0GY3woql92RS9O/acWkJkk=",
"lastModified": 1784554034,
"narHash": "sha256-NbL+1ju1j53MqsjUCAFWgpVp3IXo2lLET1OoDdxc18Q=",
"ref": "main",
"rev": "13667cd216db260ab549e6f1b6281aa230d2f9e0",
"revCount": 29,
"rev": "a7cbd30941ee0430f6a626e7dc38b5358dcc8a2a",
"revCount": 30,
"type": "git",
"url": "https://git.pvv.ntnu.no/Projects/calendar-bot.git"
},
@@ -379,11 +379,11 @@
]
},
"locked": {
"lastModified": 1779903528,
"narHash": "sha256-4rajaHeBeQ4PjbNSpslE9G3A5mZM1J/64ls+VoufWZo=",
"lastModified": 1782759909,
"narHash": "sha256-gktjBeZyoRvVBkm2cO1tD99fdQ34iUDyB6iecRdorm4=",
"ref": "main",
"rev": "bba7413a1c611d4918fbef4d3aa55e465ca3f3fb",
"revCount": 585,
"rev": "ad6c79fb713884a4a2df8aab30914cd0c1c2e6cb",
"revCount": 587,
"type": "git",
"url": "https://git.pvv.ntnu.no/Projects/nettsiden.git"
},
@@ -447,17 +447,17 @@
"rust-overlay": "rust-overlay_4"
},
"locked": {
"lastModified": 1778600367,
"narHash": "sha256-YB0b2xUf4D8792D5Ay//7C3AjHyv+9yoy8K1mTe+wvE=",
"lastModified": 1784550731,
"narHash": "sha256-KDrBGT98fQWlnEBmTvIijPq4n4sVLcETBu8EuL486SM=",
"ref": "main",
"rev": "8e5f2849ff7c9616100fe928261512a7ad647939",
"revCount": 91,
"rev": "c0c0e47c8a45673c62462cadf38a489b72fd39ec",
"revCount": 112,
"type": "git",
"url": "https://git.pvv.ntnu.no/Projects/roowho2.git"
},
"original": {
"ref": "main",
"rev": "8e5f2849ff7c9616100fe928261512a7ad647939",
"rev": "c0c0e47c8a45673c62462cadf38a489b72fd39ec",
"type": "git",
"url": "https://git.pvv.ntnu.no/Projects/roowho2.git"
}
@@ -491,11 +491,11 @@
]
},
"locked": {
"lastModified": 1777000482,
"narHash": "sha256-CZ5FKUSA8FCJf0h9GWdPJXoVVDL9H5yC74GkVc5ubIM=",
"lastModified": 1784526465,
"narHash": "sha256-L37teKC6oINWG4PGZLIqbphMWvSQ0PEz+aWxAk+rIDw=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "403c09094a877e6c4816462d00b1a56ff8198e06",
"rev": "58c6334db52d51fc5dd8877c90b01f00cf8a696b",
"type": "github"
},
"original": {
@@ -512,11 +512,11 @@
]
},
"locked": {
"lastModified": 1766371695,
"narHash": "sha256-W7CX9vy7H2Jj3E8NI4djHyF8iHSxKpb2c/7uNQ/vGFU=",
"lastModified": 1784526465,
"narHash": "sha256-L37teKC6oINWG4PGZLIqbphMWvSQ0PEz+aWxAk+rIDw=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "d81285ba8199b00dc31847258cae3c655b605e8c",
"rev": "58c6334db52d51fc5dd8877c90b01f00cf8a696b",
"type": "github"
},
"original": {
@@ -533,11 +533,11 @@
]
},
"locked": {
"lastModified": 1776914043,
"narHash": "sha256-qug5r56yW1qOsjSI99l3Jm15JNT9CvS2otkXNRNtrPI=",
"lastModified": 1784438913,
"narHash": "sha256-NYF7ZM5ip0u+w1pBFDpIGEbrbgN/wpnLFAmBkWkYMXw=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "2d35c4358d7de3a0e606a6e8b27925d981c01cc3",
"rev": "afacd6819d3765a05814ee8e3de74c77d42ac799",
"type": "github"
},
"original": {
@@ -553,11 +553,11 @@
]
},
"locked": {
"lastModified": 1777944972,
"narHash": "sha256-VfGRo1qTBKOe3s2gOv8LSoA6Fk19PvBlwQ1ECN0Evn8=",
"lastModified": 1783174389,
"narHash": "sha256-aCWC8ngycU7OdJrU2+Je3qf+1a2ykuBvpPhZT/9tXMc=",
"owner": "Mic92",
"repo": "sops-nix",
"rev": "c591bf665727040c6cc5cb409079acb22dcce33c",
"rev": "f1406619a3884cd5c47992a70b8b35c9c0fcb4c9",
"type": "github"
},
"original": {
@@ -575,11 +575,11 @@
]
},
"locked": {
"lastModified": 1773932847,
"narHash": "sha256-IklIAdlonrmO8/lkDxNIVz9+ORL4pcVotMTxeyvxzoc=",
"lastModified": 1780762731,
"narHash": "sha256-EuDaLnasWN0mpi995n+fAQQfPGBhqNW4fNjlQRpHt58=",
"ref": "main",
"rev": "0871a319f51d3cb0d1abb5b11edb768b39906d3f",
"revCount": 104,
"rev": "931bd2d63e285e767c8c81c103dda3c0a63f2965",
"revCount": 108,
"type": "git",
"url": "https://git.pvv.ntnu.no/Projects/worblehat.git"
},
+12 -5
View File
@@ -26,7 +26,7 @@
worblehat.url = "git+https://git.pvv.ntnu.no/Projects/worblehat.git?ref=main";
worblehat.inputs.nixpkgs.follows = "nixpkgs";
matrix-next.url = "github:dali99/nixos-matrix-modules/v0.8.0";
matrix-next.url = "github:dali99/nixos-matrix-modules/master";
matrix-next.inputs.nixpkgs.follows = "nixpkgs";
nix-gitea-themes.url = "git+https://git.pvv.ntnu.no/Drift/nix-gitea-themes.git?ref=main";
@@ -35,7 +35,7 @@
minecraft-heatmap.url = "git+https://git.pvv.ntnu.no/Projects/minecraft-heatmap.git?ref=main";
minecraft-heatmap.inputs.nixpkgs.follows = "nixpkgs";
roowho2.url = "git+https://git.pvv.ntnu.no/Projects/roowho2.git?ref=main&rev=8e5f2849ff7c9616100fe928261512a7ad647939";
roowho2.url = "git+https://git.pvv.ntnu.no/Projects/roowho2.git?ref=main&rev=c0c0e47c8a45673c62462cadf38a489b72fd39ec";
roowho2.inputs.nixpkgs.follows = "nixpkgs";
greg-ng.url = "git+https://git.pvv.ntnu.no/Grzegorz/greg-ng.git?ref=main";
@@ -173,6 +173,7 @@
sops-nix.nixosModules.sops
inputs.roowho2.nixosModules.default
self.nixosModules.rsync-pull-targets
self.nixosModules.python-http-handlers
])
++ modules;
}
@@ -267,6 +268,7 @@
modules = [
inputs.nix-gitea-themes.nixosModules.default
inputs.disko.nixosModules.disko
self.nixosModules.robots-txt
];
};
@@ -306,13 +308,14 @@
nixosModules = {
bluemap = ./modules/bluemap.nix;
drumknotty = ./modules/drumknotty;
gickup = ./modules/gickup;
matrix-ooye = ./modules/matrix-ooye.nix;
python-http-handlers = ./modules/python-http-handlers.nix;
robots-txt = ./modules/robots-txt.nix;
rsync-pull-targets = ./modules/rsync-pull-targets.nix;
snakeoil-certs = ./modules/snakeoil-certs.nix;
snappymail = ./modules/snappymail.nix;
drumknotty = ./modules/drumknotty;
};
devShells = forAllSystems (system: {
@@ -369,7 +372,12 @@
//
# Machines
lib.genAttrs allMachines
(machine: self.nixosConfigurations.${machine}.config.system.build.toplevel)
(machine: self.nixosConfigurations.${machine}.config.system.build.toplevel.overrideAttrs (prev: {
passthru =
(prev.passthru or { })
// self.nixosConfigurations.${machine}.config.system.build
// { inherit (self.nixosConfigurations.${machine}) pkgs config; };
}))
//
# Nix-topology
(let
@@ -397,7 +405,6 @@
inputs.nix-topology.nixosModules.default
./topology/service-extractors/greg-ng.nix
./topology/service-extractors/postgresql.nix
./topology/service-extractors/mysql.nix
./topology/service-extractors/gitea-runners.nix
];
})
@@ -16,6 +16,7 @@
fileSystems."/" =
{ device = "/dev/sda1";
fsType = "btrfs";
options = [ "relatime" ];
};
fileSystems."/boot" =
+1 -1
View File
@@ -74,7 +74,7 @@ in {
name = "psycopg2";
args = {
host = "/var/run/postgresql";
dbname = "synapse";
database = "synapse";
user = "matrix-synapse";
cp_min = 1;
cp_max = 5;
+1 -1
View File
@@ -43,7 +43,7 @@ in
sshCommand = ''${pkgs.openssh}/bin/ssh -o UserKnownHostsFile='${knownHostsFile}' -i \"$CREDENTIALS_DIRECTORY\"/sshkey'';
in [
"${lib.getExe' pkgs.coreutils "mkdir"} -p '${cfg.minecraftLogsDir}'"
"${lib.getExe pkgs.rsync} ${rsyncArgs} --rsh=\"${sshCommand}\" root@innovation.pvv.ntnu.no:/ '${cfg.minecraftLogsDir}'/"
"${lib.getExe pkgs.rsync} ${rsyncArgs} --rsh=\"${sshCommand}\" root@innovation.pvv.ntnu.no:. '${cfg.minecraftLogsDir}'/"
];
};
};
+17 -1
View File
@@ -4,7 +4,10 @@ let
dataDir = "/data/mysql";
in
{
imports = [ ./backup.nix ];
imports = [
./backup.nix
./timed-jobs.nix
];
sops.secrets."mysql/password" = {
owner = "mysql";
@@ -54,6 +57,18 @@ in
mode = "0700";
};
fileSystems.${dataDir} = lib.mkIf cfg.enable {
device = dataDir;
fsType = "none";
options = [
"bind"
"noatime"
"noauto"
"x-systemd.requires=systemd-tmpfiles-setup.service"
"x-systemd.requires=systemd-tmpfiles-resetup.service"
];
};
systemd.services.mysql = lib.mkIf cfg.enable {
after = [
"systemd-tmpfiles-setup.service"
@@ -61,6 +76,7 @@ in
];
serviceConfig = {
RequiresMountsFor = [ dataDir ];
BindPaths = [ "${dataDir}:${cfg.dataDir}" ];
LogsDirectory = "mysql";
+48
View File
@@ -0,0 +1,48 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.mysql;
in
{
config = lib.mkIf cfg.enable {
systemd.services = {
mysql-analyze = {
requires = [ "mysql.service" ];
after = [ "mysql.service" ];
description = "Refresh MariaDB optimizer statistics for all databases";
startAt = "Mon 05:00:00";
serviceConfig = {
Type = "oneshot";
User = cfg.user;
Group = cfg.group;
Nice = 19;
IOSchedulingClass = "best-effort";
IOSchedulingPriority = 7;
ExecStart = "${lib.getExe' cfg.package "mariadb-check"} --all-databases --analyze";
};
};
mysql-optimize = {
requires = [ "mysql.service" ];
after = [ "mysql.service" ];
description = "Check, repair and optimize all MariaDB databases";
startAt = "*-*-01 04:00:00";
serviceConfig = {
Type = "oneshot";
User = cfg.user;
Group = cfg.group;
Nice = 19;
IOSchedulingClass = "best-effort";
IOSchedulingPriority = 7;
ExecStart = [
"${lib.getExe' cfg.package "mariadb-check"} --all-databases --auto-repair"
"${lib.getExe' cfg.package "mariadb-check"} --all-databases --optimize"
];
};
};
};
};
}
@@ -14,6 +14,7 @@ in
extensions = ps: with ps; [ pg_repack ];
enableTCPIP = true;
# NOTE: md5 accepts both md5 and scram-sha-256
authentication = ''
host all all ${values.ipv4-space} md5
host all all ${values.ipv6-space} md5
@@ -76,6 +77,15 @@ in
maintenance_io_concurrency = 100;
wal_recycle = true;
# -------------------------------- #
# Authentication
password_encryption = "scram-sha-256";
# Logging
log_connections = "authorization";
log_disconnections = true;
# SSL
ssl = true;
ssl_cert_file = "/run/credentials/postgresql.service/cert";
@@ -89,6 +99,18 @@ in
mode = "0700";
};
fileSystems."/data/postgresql" = lib.mkIf cfg.enable {
device = "/data/postgresql";
fsType = "none";
options = [
"bind"
"noatime"
"noauto"
"x-systemd.requires=systemd-tmpfiles-setup.service"
"x-systemd.requires=systemd-tmpfiles-resetup.service"
];
};
systemd.services.postgresql-setup = lib.mkIf cfg.enable {
after = [
"systemd-tmpfiles-setup.service"
@@ -100,6 +122,7 @@ in
"key:/etc/certs/postgres.key"
];
RequiresMountsFor = [ "/data/postgresql" ];
BindPaths = [ "/data/postgresql:/var/lib/postgresql" ];
};
};
@@ -115,6 +138,7 @@ in
"key:/etc/certs/postgres.key"
];
RequiresMountsFor = [ "/data/postgresql" ];
BindPaths = [ "/data/postgresql:/var/lib/postgresql" ];
};
};
@@ -127,4 +151,27 @@ in
networking.firewall.allowedTCPPorts = lib.mkIf cfg.enable [ 5432 ];
networking.firewall.allowedUDPPorts = lib.mkIf cfg.enable [ 5432 ];
environment.systemPackages = [
(pkgs.writeShellApplication {
name = "postgres-update-collations.sh";
runtimeInputs = [
config.systemd.package
cfg.package
];
text = ''
run0 --user=postgres psql <${pkgs.writeText "postgres-update-collations.sql" ''
CREATE FUNCTION exec(text) returns text language plpgsql volatile
AS $f$
BEGIN
EXECUTE $1;
RETURN $1;
END;
$f$;
SELECT exec('ALTER DATABASE "' || datname || '" REFRESH COLLATION VERSION') FROM pg_database WHERE datistemplate = false;
''}
'';
})
];
}
@@ -16,6 +16,7 @@
fileSystems."/" =
{ device = "/dev/disk/by-uuid/4e8667f8-55de-4103-8369-b94665f42204";
fsType = "ext4";
options = [ "relatime" ];
};
fileSystems."/boot" =
+1
View File
@@ -16,6 +16,7 @@
fileSystems."/" =
{ device = "/dev/disk/by-uuid/33825f0d-5a63-40fc-83db-bfa1ebb72ba0";
fsType = "ext4";
options = [ "relatime" ];
};
fileSystems."/boot" =
@@ -28,6 +28,7 @@
fileSystems."/" = {
device = "/dev/mapper/pool-root";
fsType = "ext4";
options = [ "relatime" ];
};
fileSystems."/boot" = {
+2 -2
View File
@@ -93,7 +93,7 @@ in {
no-group = true;
rsh = "${pkgs.openssh}/bin/ssh -o UserKnownHostsFile=%d/ssh-known-hosts -i %d/sshkey";
};
in "${lib.getExe pkgs.rsync} ${rsyncArgs} root@innovation.pvv.ntnu.no:/ ${vanillaSurvival}";
in "${lib.getExe pkgs.rsync} ${rsyncArgs} root@innovation.pvv.ntnu.no:. ${vanillaSurvival}";
ExecStartPost = let
rsyncArgs = lib.cli.toCommandLineShellGNU { } {
archive = true;
@@ -103,7 +103,7 @@ in {
no-group = true;
rsh = "${pkgs.openssh}/bin/ssh -o UserKnownHostsFile=%d/ssh-known-hosts -i %d/sshkey";
};
in "${lib.getExe pkgs.rsync} ${rsyncArgs} --groupmap=root:nginx ${config.services.bluemap.webRoot}/ root@bekkalokk.pvv.ntnu.no:/";
in "${lib.getExe pkgs.rsync} ${rsyncArgs} --groupmap=root:nginx ${config.services.bluemap.webRoot}/ root@bekkalokk.pvv.ntnu.no:.";
LoadCredential = [
"sshkey:${config.sops.secrets."bluemap/ssh-key".path}"
"ssh-known-hosts:${config.sops.secrets."bluemap/ssh-known-hosts".path}"
@@ -2,10 +2,10 @@
{
imports = [
./gatus
./grafana.nix
./loki.nix
./prometheus
./scrutiny.nix
./uptime-kuma.nix
];
}
@@ -0,0 +1,169 @@
{ config, lib, ... }:
let
cfg = config.services.gatus;
in
{
imports = [
./minecraft-checker.nix
./postgres-checker.nix
./mariadb-checker.nix
];
services.gatus = {
enable = true;
settings = {
web = {
address = "127.0.0.1";
port = 19283;
};
storage = {
type = "sqlite";
path = "/var/lib/gatus/data.db";
};
ui = {
title = "PVV Nede!?";
header = "😭😭😭";
dashboard-heading = "PVV Nede!?";
dashboard-subheading = "Kan noen ringe drift?";
};
endpoints = let
mkMachine = name: {
inherit name;
group = "Machines";
url = "icmp://${name}.pvv.ntnu.no";
conditions = [
"[CONNECTED] == true"
];
};
mkWebsite = name: url: {
inherit name url;
group = "Websites";
method = "GET";
conditions = [
"[STATUS] == 200"
];
};
mkService = name: url: {
inherit name url;
group = "Services";
conditions = [
"[CONNECTED] == true"
];
};
in (lib.sortOn (m: m.name) [
(mkMachine "ambidextrous")
(mkMachine "bekkalokk")
(mkMachine "bicep")
(mkMachine "bikkje")
(mkMachine "brzeczyszczykiewicz")
(mkMachine "georg")
(mkMachine "gluttony")
(mkMachine "ildkule")
(mkMachine "kana")
(mkMachine "kommode")
(mkMachine "lupine-1")
(mkMachine "lupine-2")
(mkMachine "lupine-3")
(mkMachine "lupine-4")
(mkMachine "lupine-5")
(mkMachine "skrot")
(mkMachine "temmie")
(mkMachine "wenche")
(mkMachine "balduzius")
(mkMachine "blossom")
(mkMachine "bubbles")
(mkMachine "buskerud")
(mkMachine "buttercup")
(mkMachine "demiurgen")
(mkMachine "drolsum")
(mkMachine "hildring")
(mkMachine "innovation")
(mkMachine "isvegg")
(mkMachine "knutsen")
(mkMachine "ludvigsen" // {
url = "icmp://ludvigsen-tap.pvv.ntnu.no";
})
(mkMachine "microbel")
(mkMachine "mirage")
(mkMachine "orchid")
(mkMachine "principal")
(mkMachine "sleipner")
(mkMachine "smask")
(mkMachine "tom")
(mkMachine "wegonke")
]) ++ [
(mkWebsite "Bluemap" "https://minecraft.pvv.ntnu.no")
(mkWebsite "Element Web" "https://chat.pvv.ntnu.no")
(mkWebsite "Gitea" "https://git.pvv.ntnu.no/api/healthz" // {
conditions = [
"[STATUS] == 200"
"[BODY].status == pass"
];
})
(mkWebsite "Grafana" "https://grafana.pvv.ntnu.no/api/health" // {
conditions = [
"[STATUS] == 200"
"[BODY].database == ok"
];
})
(mkWebsite "Grzegorz - Brzeczyszczykiewicz" "https://brzeczyszczykiewicz.pvv.ntnu.no")
(mkWebsite "Grzegorz - Georg" "https://georg.pvv.ntnu.no")
(mkWebsite "IDP" "https://idp.pvv.ntnu.no")
(mkWebsite "Mailing Lists" "http://list.pvv.ntnu.no")
(mkWebsite "Mapcrafter" "http://isvegg.pvv.ntnu.no/kart")
(mkWebsite "PVV-Nettsiden" "https://www.pvv.ntnu.no")
(mkWebsite "Roundcube" "https://webmail.pvv.ntnu.no/roundcube")
(mkWebsite "Scrutiny" "https://scrutiny.pvv.ntnu.no")
(mkWebsite "Snappymail" "http://snappymail.pvv.ntnu.no")
(mkWebsite "Userweb - Temmie" "https://temmie.pvv.ntnu.no/~oysteikt")
(mkWebsite "Userweb - Tom" "https://www.pvv.ntnu.no/~oysteikt")
(mkWebsite "Vaultwarden" "https://pw.pvv.ntnu.no/alive")
(mkWebsite "Wiki" "https://wiki.pvv.ntnu.no/w/api.php?action=query&format=json")
(mkService "Gitea SSH" "ssh://git.pvv.ntnu.no:2222")
(mkService "QoTD" "tcp://bekkalokk.pvv.ntnu.no:17")
(mkService "Minecraft" "http://localhost:1337" // {
conditions = [
"[STATUS] == 200"
"[BODY].ok == true"
];
})
(mkService "PostgreSQL" "http://localhost:1338" // {
conditions = [
"[STATUS] == 200"
"[BODY].ok == true"
];
})
(mkService "MariaDB" "http://localhost:1339" // {
conditions = [
"[STATUS] == 200"
"[BODY].ok == true"
];
})
(mkService "Email (SMTP)" "starttls://mail.pvv.ntnu.no:587")
(mkService "Email (POP3)" "tls://mail.pvv.ntnu.no:995")
(mkService "Email (IMAP)" "tls://mail.pvv.ntnu.no:993")
(mkService "Matrix Synapse" "https://matrix.pvv.ntnu.no/_matrix/client/versions" // {
method = "GET";
conditions = [
"[STATUS] == 200"
];
})
];
};
};
services.nginx.virtualHosts."status.pvv.ntnu.no" = lib.mkIf cfg.enable {
enableACME = true;
forceSSL = true;
kTLS = true;
locations."/".proxyPass = "http://localhost:${toString cfg.settings.web.port}";
};
}
@@ -0,0 +1,79 @@
{ config, pkgs, ... }:
{
sops.secrets."keys/gatus/mariadb" = {
restartUnits = [ "phh-gatus-mariadb-checker.service" ];
};
sops.templates."gatus-mariadb-checker.env" = {
restartUnits = [ "phh-gatus-mariadb-checker.service" ];
content = ''
MYSQL_HOST=mysql.pvv.ntnu.no
MYSQL_PORT=3306
MYSQL_DATABASE=mysql
MYSQL_USER=gatus_healthcheck
MYSQL_PASSWORD=${config.sops.placeholder."keys/gatus/mariadb"}
'';
};
services.python-http-handlers."gatus-mariadb-checker" = {
listenStreams = [ "127.0.0.1:1339" ];
libraries = with pkgs.python3Packages; [
pymysql
];
serviceConfig = {
EnvironmentFile = config.sops.templates."gatus-mariadb-checker.env".path;
};
handler = ''
import os
import json
import pymysql
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
try:
conn = pymysql.connect(
host=os.environ["MYSQL_HOST"],
port=int(os.environ.get("MYSQL_PORT", "3306")),
user=os.environ["MYSQL_USER"],
password=os.environ["MYSQL_PASSWORD"],
database=os.environ.get("MYSQL_DATABASE", "mysql"),
connect_timeout=5,
)
try:
with conn.cursor() as cur:
cur.execute("SELECT VERSION();")
(version,) = cur.fetchone()
cur.execute("SHOW STATUS LIKE 'Threads_connected';")
(_, connections) = cur.fetchone()
cur.execute("SHOW DATABASES;")
databases = cur.fetchall()
finally:
conn.close()
body = {
"ok": True,
"version": version,
"connections": int(connections),
"databases": len(databases),
}
data = json.dumps(body).encode()
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
except Exception as e:
data = json.dumps({"ok": False, "error": str(e)}).encode()
self.send_response(500)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
'';
};
}
@@ -0,0 +1,40 @@
{ lib, pkgs, ... }:
{
services.python-http-handlers."gatus-minecraft-checker" = {
listenStreams = [ "127.0.0.1:1337" ];
libraries = with pkgs.python3Packages; [
mcstatus
];
handler = ''
import json
from mcstatus import JavaServer
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
try:
mcserver = JavaServer.lookup("minecraft.pvv.ntnu.no")
status = mcserver.status()
body = {
"ok": True,
"players": status.players.online,
"version": status.version.name,
"latency": status.latency,
}
data = json.dumps(body).encode()
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
except Exception as e:
data = json.dumps({"ok": False, "error": str(e)}).encode()
self.send_response(500)
self.end_headers()
self.wfile.write(data)
'';
};
}
@@ -0,0 +1,79 @@
{ config, pkgs, ... }:
{
sops.secrets."keys/gatus/postgres" = {
restartUnits = [ "phh-gatus-postgres-checker.service" ];
};
sops.templates."gatus-postgres-checker.env" = {
restartUnits = [ "phh-gatus-postgres-checker.service" ];
content = ''
PGHOST=postgres.pvv.ntnu.no
PGPORT=5432
PGDATABASE=postgres
PGUSER=gatus_healthcheck
PGPASSWORD=${config.sops.placeholder."keys/gatus/postgres"}
'';
};
services.python-http-handlers."gatus-postgres-checker" = {
listenStreams = [ "127.0.0.1:1338" ];
libraries = with pkgs.python3Packages; [
psycopg2
];
serviceConfig = {
EnvironmentFile = config.sops.templates."gatus-postgres-checker.env".path;
};
handler = ''
import os
import json
import psycopg2
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
try:
conn = psycopg2.connect(
host=os.environ["PGHOST"],
port=os.environ.get("PGPORT", "5432"),
dbname=os.environ.get("PGDATABASE", "postgres"),
user=os.environ["PGUSER"],
password=os.environ["PGPASSWORD"],
connect_timeout=5,
)
try:
with conn.cursor() as cur:
cur.execute("SELECT version();")
(version,) = cur.fetchone()
cur.execute("SELECT count(*) FROM pg_stat_activity;")
(connections,) = cur.fetchone()
cur.execute("SELECT count(*) FROM pg_database WHERE NOT datistemplate;")
(databases,) = cur.fetchone()
finally:
conn.close()
body = {
"ok": True,
"version": version,
"connections": connections,
"databases": databases,
}
data = json.dumps(body).encode()
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
except Exception as e:
data = json.dumps({"ok": False, "error": str(e)}).encode()
self.send_response(500)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
'';
};
}
+24 -4
View File
@@ -1,4 +1,4 @@
{ config, pkgs, ... }:
{ config, pkgs, values, ... }:
let
cfg = config.services.loki;
@@ -9,8 +9,8 @@ in {
configuration = {
auth_enabled = false;
server = {
http_listen_port = 3100;
http_listen_address = "0.0.0.0";
http_listen_port = 31832;
http_listen_address = "127.0.0.1";
grpc_listen_port = 9096;
};
@@ -81,5 +81,25 @@ in {
};
};
networking.firewall.allowedTCPPorts = [ cfg.configuration.server.http_listen_port ];
services.nginx.virtualHosts."loki.pvv.ntnu.no" = {
forceSSL = true;
enableACME = true;
kTLS = true;
locations = {
"/".return = "403";
"/loki/api/v1/push" = {
proxyPass = "http://${cfg.configuration.server.http_listen_address}:${toString cfg.configuration.server.http_listen_port}/loki/api/v1/push";
extraConfig = ''
allow 127.0.0.1;
allow ::1;
allow ${values.ipv4-space};
allow ${values.ipv6-space};
allow ${values.ntnu.ipv4-space};
allow ${values.ntnu.ipv6-space};
deny all;
'';
};
};
};
}
@@ -8,7 +8,6 @@ in {
./matrix-synapse.nix
./mysqld.nix
./postgres.nix
./dibbler.nix
];
services.prometheus = {
@@ -1,96 +0,0 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.prometheus.exporters.sql;
configFile =
if cfg.configFile != null then
cfg.configFile
else
let
nameInline = lib.mapAttrsToList (k: v: v // { name = k; });
renameStartupSql = j: removeAttrs (j // { startup_sql = j.startupSql; }) [ "startupSql" ];
configuration = {
jobs = map renameStartupSql (
nameInline (lib.mapAttrs (k: v: (v // { queries = nameInline v.queries; })) cfg.configuration.jobs)
);
};
in
builtins.toFile "config.yaml" (builtins.toJSON configuration);
in
{
sops.secrets."config/postgresql_dibbler_password" = { };
services.prometheus.scrapeConfigs = [
{
job_name = "sql_exporter";
scrape_interval = "1m";
scheme = "http";
static_configs = [
{
targets = [ "localhost:9237" ];
}
];
}
];
services.prometheus.exporters.sql = {
enable = true;
configuration = {
jobs.dibbler = {
interval = "1m";
queries."daily_purchase_sum" = {
help = "Sum of purchases for the current day.";
labels = [ "thing" ];
values = [ "sum" ];
query = "SELECT SUM(price) FROM purchases GROUP BY DATE(time) ORDER BY DATE(time) DESC LIMIT 1";
};
queries."total_purchase_sum" = {
help = "Sum of all purchases.";
labels = [ "thing" ];
values = [ "sum" ];
query = "SELECT SUM(price) FROM purchases";
};
queries."total_stock_value" = {
help = "The value of all stock in dibbler.";
labels = [ "thing" ];
values = [ "sum" ];
query = "SELECT SUM(price * stock) FROM products";
};
queries."user_credit_sum" = {
help = "The sum of all user credit.";
labels = [ "thing" ];
values = [ "sum" ];
query = "SELECT SUM(credit) FROM users";
};
};
};
};
systemd.services."prometheus-sql-exporter".serviceConfig = {
RuntimeDirectory = "prometheus-sql-exporter";
LoadCredential = "postgresql_dibbler_password:${
config.sops.secrets."config/postgresql_dibbler_password".path
}";
ExecStartPre = ''
|${lib.getExe pkgs.jq} \
--null-input \
--compact-output \
--slurpfile config '${configFile}' \
--rawfile pw '%d/postgresql_dibbler_password' \
--from-file '${pkgs.writeText "prometheus-sql-exec-start-jq-filter" ''
("postgres://pvv_vv:\($pw | gsub("\n"; ""))@postgres.pvv.ntnu.no") as $pg_uri
| $config[0]
| .jobs[0].connections[0] = $pg_uri
''}' > /run/prometheus-sql-exporter/config.yaml
'';
};
}
@@ -6,32 +6,63 @@
targets = map (port: "${name}.pvv.ntnu.no:${toString port}") ports;
};
nixosMachines = [
"ildkule"
"bekkalokk"
"bicep"
"brzeczyszczykiewicz"
"georg"
"gluttony"
"kommode"
"lupine-1"
"lupine-2"
"lupine-3"
"lupine-4"
"lupine-5"
# TODO: export prometheus stats via apache on temmie
# "temmie"
"wenche"
];
defaultNodeExporterPort = 9100;
defaultSystemdExporterPort = 9101;
defaultNixosExporterPort = 9102;
in {
services.prometheus.scrapeConfigs = [{
job_name = "base_info";
services.prometheus.scrapeConfigs = [
{
job_name = "nixos-node";
scheme = "https";
metrics_path = "/prometheus-node-exporter/metrics";
static_configs = map (name: {
labels.hostname = name;
targets = [ "${name}.pvv.ntnu.no:443" ];
}) nixosMachines;
}
{
job_name = "nixos-systemd";
scheme = "https";
metrics_path = "/prometheus-systemd-exporter/metrics";
static_configs = map (name: {
labels.hostname = name;
targets = [ "${name}.pvv.ntnu.no:443" ];
}) nixosMachines;
}
{
job_name = "nixos-flake-input";
scheme = "https";
metrics_path = "/prometheus-nixos-flake-input-exporter/metrics";
static_configs = map (name: {
labels.hostname = name;
targets = [ "${name}.pvv.ntnu.no:443" ];
}) nixosMachines;
}
{
job_name = "non-nixos-node";
scheme = "http";
metrics_path = "/metrics";
static_configs = [
(mkHostScrapeConfig "ildkule" [ cfg.exporters.node.port cfg.exporters.systemd.port defaultNixosExporterPort ])
(mkHostScrapeConfig "bekkalokk" [ defaultNodeExporterPort defaultSystemdExporterPort defaultNixosExporterPort ])
(mkHostScrapeConfig "bicep" [ defaultNodeExporterPort defaultSystemdExporterPort defaultNixosExporterPort ])
(mkHostScrapeConfig "brzeczyszczykiewicz" [ defaultNodeExporterPort defaultSystemdExporterPort defaultNixosExporterPort ])
(mkHostScrapeConfig "georg" [ defaultNodeExporterPort defaultSystemdExporterPort defaultNixosExporterPort ])
(mkHostScrapeConfig "gluttony" [ defaultNodeExporterPort defaultSystemdExporterPort defaultNixosExporterPort ])
(mkHostScrapeConfig "kommode" [ defaultNodeExporterPort defaultSystemdExporterPort defaultNixosExporterPort ])
(mkHostScrapeConfig "lupine-1" [ defaultNodeExporterPort defaultSystemdExporterPort defaultNixosExporterPort ])
(mkHostScrapeConfig "lupine-2" [ defaultNodeExporterPort defaultSystemdExporterPort defaultNixosExporterPort ])
(mkHostScrapeConfig "lupine-3" [ defaultNodeExporterPort defaultSystemdExporterPort defaultNixosExporterPort ])
(mkHostScrapeConfig "lupine-4" [ defaultNodeExporterPort defaultSystemdExporterPort defaultNixosExporterPort ])
(mkHostScrapeConfig "lupine-5" [ defaultNodeExporterPort defaultSystemdExporterPort defaultNixosExporterPort ])
(mkHostScrapeConfig "temmie" [ defaultNodeExporterPort defaultSystemdExporterPort defaultNixosExporterPort ])
(mkHostScrapeConfig "wenche" [ defaultNodeExporterPort defaultSystemdExporterPort defaultNixosExporterPort ])
(mkHostScrapeConfig "hildring" [ defaultNodeExporterPort ])
(mkHostScrapeConfig "isvegg" [ defaultNodeExporterPort ])
(mkHostScrapeConfig "microbel" [ defaultNodeExporterPort ])
];
}];
}
];
}
@@ -1,44 +0,0 @@
{ config, pkgs, lib, values, ... }:
let
cfg = config.services.uptime-kuma;
domain = "status.pvv.ntnu.no";
stateDir = "/data/monitoring/uptime-kuma";
in {
services.uptime-kuma = {
enable = true;
settings = {
PORT = "5059";
HOST = "127.0.1.2";
};
};
services.nginx.virtualHosts.${domain} = {
enableACME = true;
forceSSL = true;
kTLS = true;
locations."/".proxyPass = "http://${cfg.settings.HOST}:${cfg.settings.PORT}";
};
fileSystems."/var/lib/private/uptime-kuma" = {
device = stateDir;
fsType = "bind";
options = [ "bind" ];
};
services.rsync-pull-targets = {
enable = true;
locations.${stateDir} = {
user = "root";
rrsyncArgs.ro = true;
authorizedKeysAttrs = [
"restrict"
"from=\"principal.pvv.ntnu.no,${values.hosts.principal.ipv6},${values.hosts.principal.ipv4}\""
"no-agent-forwarding"
"no-port-forwarding"
"no-pty"
"no-X11-forwarding"
];
publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJXzcDm6cVr4NmWzUSroy33FlielKqaG83wY0RCMC0p/ uptime_kuma rsync backup";
};
};
}
+1
View File
@@ -48,6 +48,7 @@
# swap.swapfile.size = "4G";
mountpoint = "/";
mountOptions = [ "relatime" ];
};
};
+103 -1
View File
@@ -136,7 +136,7 @@ in {
picture = {
AVATAR_MAX_FILE_SIZE = 1024 * 1024 * 5;
# NOTE: go any bigger than this, and gitea will freeze your gif >:(
AVATAR_MAX_ORIGIN_SIZE = 1024 * 1024 * 2;
AVATAR_MAX_ORIGIN_SIZE = 1024 * 1024 * 4;
};
actions.ENABLED = true;
webhook.ALLOWED_HOST_LIST = lib.concatStringsSep "," [
@@ -196,6 +196,108 @@ in {
};
};
environment.robots-txt."gitea" = {
virtualHost = domain;
rules = [
{
pre_comment = ''
Gitea internals
See these for more information:
- https://gitea.com/robots.txt
- https://codeberg.org/robots.txt
'';
User-agent = "*";
Disallow = [
"/api/*"
"/avatars"
"/*/*/src/commit/*"
"/*/*/commit/*"
"/*/*/*/refs/*"
"/*/*/*/star"
"/*/*/*/watch"
"/*/*/labels"
"/*/*/activity/*"
"/vendor/*"
"/swagger.*.json"
"/repo/create"
"/repo/migrate"
"/org/create"
"/*/*/fork"
"/*/*/watchers"
"/*/*/stargazers"
"/*/*/forks"
"*/.git/"
"/*.git"
"/*.atom"
"/*.rss"
];
Crawl-delay = "2";
}
{
pre_comment = "Language Spam";
Disallow = "/*?lang=";
}
{
pre_comment = ''
AI bots
Sourced from:
- https://www.vg.no/robots.txt
- https://codeberg.org/robots.txt
'';
User-agent = [
"AI2Bot"
"Ai2Bot-Dolma"
"Amazonbot"
"Applebot-Extended"
"Bytespider"
"CCBot"
"ChatGPT-User"
"Claude-Web"
"ClaudeBot"
"Crawlspace"
"Diffbot"
"FacebookBot"
"FriendlyCrawler"
"GPTBot"
"Google-Extended"
"ICC-Crawler"
"ImagesiftBot"
"Kangaroo Bot"
"Meta-ExternalAgent"
"OAI-SearchBot"
"Omgili"
"Omgilibot"
"PanguBot"
"PerplexityBot"
"PetalBot"
"Scrapy"
"SemrushBot-OCOB"
"Sidetrade indexer bot"
"Timpibot"
"VelenPublicWebCrawler"
"Webzio-Extended"
"YouBot"
"anthropic-ai"
"cohere-ai"
"cohere-training-data-crawler"
"facebookexternalhit"
"iaskspider/2.0"
"img2dataset"
"meta-externalagent"
"omgili"
"omgilibot"
];
Disallow = "/";
Crawl-delay = "2";
}
{
Sitemap = "https://${domain}/sitemap.xml";
}
];
};
networking.firewall.allowedTCPPorts = [ sshPort ];
services.rsync-pull-targets = {
+52 -3
View File
@@ -5,6 +5,8 @@
(fp /base)
./services/gitea-runner.nix
] ++ lib.optionals (lupineName == "lupine-5") [
./services/openvpn.nix
];
sops.defaultSopsFile = fp /secrets/lupine/lupine.yaml;
@@ -15,14 +17,61 @@
"i686-linux"
];
systemd.network.networks."30-enp0s31f6" = values.defaultNetworkConfig // {
systemd.network = if (lupineName != "lupine-5")
then {
networks."30-enp0s31f6" = (values.defaultNetworkConfig // {
matchConfig.Name = "enp0s31f6";
address = with values.hosts.${lupineName}; [ (ipv4 + "/25") (ipv6 + "/64") ];
networkConfig.LLDP = false;
};
systemd.network.wait-online = {
});
wait-online = {
anyInterface = true;
};
}
else {
netdevs."10-br0".netdevConfig = {
Name = "br0";
Kind = "bridge";
};
netdevs."20-tap0".netdevConfig = {
Name = "tap0";
Kind = "tap";
};
networks."10-enp0s31f6" = {
matchConfig.Name = "enp0s31f6";
bridge = [ "br0" ];
};
networks."20-br0" = {
matchConfig.Name = "br0";
address = with values.hosts.${lupineName}; [
(ipv4 + "/25")
(ipv6 + "/64")
values.services.knutsen-vpn
];
networkConfig.LLDP = false;
dns = ["129.241.0.200" "129.241.0.201" "2001:700:300:1900::200" "2001:700:300:1900::201"];
domains = ["pvv.ntnu.no" "pvv.org"];
gateway = [values.hosts.gateway values.hosts.gateway6];
networkConfig.IPv6AcceptRA = "no";
DHCP = "no";
};
networks."30-tap0" = {
matchConfig.Name = "tap0";
bridge = [ "br0" ];
};
wait-online = {
anyInterface = true;
};
};
# Don't change (even during upgrades) unless you know what you are doing.
# See https://search.nixos.org/options?show=system.stateVersion
+101
View File
@@ -0,0 +1,101 @@
{ config, pkgs, lib, values, ... }:
let
renderConfig = attrs: lib.pipe attrs [
(lib.filterAttrs (_: value: !(builtins.isNull value || value == false)))
(builtins.mapAttrs (_: value:
if builtins.isList value then builtins.concatStringsSep " " (map toString value)
else if value == true then value
else if builtins.any (f: f value) [
builtins.isString
builtins.isInt
builtins.isFloat
lib.isPath
lib.isDerivation
] then toString value
else throw "Unknown value in lupine openvpn config:\n${value}"
))
(lib.mapAttrsToList (name: value: if value == true then name else "${name} ${value}"))
(builtins.concatStringsSep "\n")
(x: x + "\n\n")
];
in
{
sops.secrets = {
"openvpn/ca/crt" = { };
"openvpn/server/crt" = { };
"openvpn/server/key" = { };
};
services.openvpn.servers."ov-tunnel" = {
config = renderConfig {
mode = "server";
# TODO: use aliases
local = "0.0.0.0";
port = 1194;
proto = "udp";
dev = "tap0";
dev-type = "tap";
script-security = 0;
ca = config.sops.secrets."openvpn/ca/crt".path;
cert = config.sops.secrets."openvpn/server/crt".path;
key = config.sops.secrets."openvpn/server/key".path;
dh = "none";
# Maintain a record of client <-> virtual IP address
# associations in this file. If OpenVPN goes down or
# is restarted, reconnecting clients can be assigned
# the same virtual IP address from the pool that was
# previously assigned.
# ifconfig-pool-persist = ./ipp.txt;
server-bridge = builtins.concatStringsSep " " [
# Gateway
"129.241.210.129"
# Netmask
"255.255.255.128"
# Pool start
values.services.knutsen-tap
# Pool end
values.services.ludvigsen-tap
];
keepalive = "10 120";
user = "nobody";
group = "nobody";
status = "/var/log/openvpn-status.log";
client-config-dir = pkgs.writeTextDir "ludvigsen" ''
# Sett IP-adr. for tap0 til ludvigsens PVV-addresse.
ifconfig-push ${values.services.ludvigsen-tap} 255.255.255.128
# Hvordan skal man faa dette til aa funke, tro?
# ifconfig-ipv6-push 2001:700:300:1900::xxx/64
# La ludvigsen bruke std. PVV-gateway til all trafikk (unntatt VPN-tunnellen).
push "redirect-gateway"
'';
persist-key = true;
persist-tun = true;
tls-version-min = "1.2";
tls-version-max = "1.2";
verb = 5;
explicit-exit-notify = 1;
};
};
networking.firewall = {
allowedTCPPorts = [ 1194 ];
allowedUDPPorts = [ 1194 ];
};
}
+1
View File
@@ -16,6 +16,7 @@
fileSystems."/" =
{ device = "/dev/disk/by-uuid/224c45db-9fdc-45d4-b3ad-aaf20b3efa8a";
fsType = "ext4";
options = [ "relatime" ];
};
fileSystems."/boot" =
+2 -53
View File
@@ -12,6 +12,8 @@
./hardware-configuration.nix
./disk-config.nix
(fp /base)
./services/drumknotty.nix
];
boot.consoleLogLevel = 0;
@@ -26,59 +28,6 @@
];
};
sops.secrets = {
"dibbler/postgresql/password" = {
owner = "drumknotty";
group = "drumknotty";
};
"worblehat/postgresql/password" = {
owner = "drumknotty";
group = "drumknotty";
};
};
services.drumknotty = {
enable = true;
kioskMode = true;
screen = {
limitWidth = 80;
limitHeight = 42;
};
dibbler = {
enable = true;
settings = {
general.quit_allowed = false;
database = {
type = "postgresql";
postgresql = {
username = "pvv_vv";
dbname = "pvv_vv";
host = "postgres.pvv.ntnu.no";
password_file = config.sops.secrets."dibbler/postgresql/password".path;
};
};
};
};
worblehat = {
enable = true;
settings = {
general.quit_allowed = false;
database = {
type = "postgresql";
postgresql = {
username = "worblehat";
dbname = "worblehat";
host = "postgres.pvv.ntnu.no";
password = config.sops.secrets."worblehat/postgresql/password".path;
};
};
};
};
};
systemd.services."serial-getty@ttyUSB0" = lib.mkIf (!config.virtualisation.isVmVariant) {
enable = true;
wantedBy = [ "getty.target" ]; # to start at boot
+1
View File
@@ -31,6 +31,7 @@
type = "filesystem";
format = "ext4";
mountpoint = "/";
mountOptions = [ "relatime" ];
};
};
};
+57
View File
@@ -0,0 +1,57 @@
{ config, ... }:
{
sops.secrets = {
"dibbler/postgresql/password" = {
owner = "drumknotty";
group = "drumknotty";
};
"worblehat/postgresql/password" = {
owner = "drumknotty";
group = "drumknotty";
};
};
services.drumknotty = {
enable = true;
kioskMode = true;
screen = {
limitWidth = 80;
limitHeight = 42;
};
dibbler = {
enable = true;
settings = {
general.quit_allowed = false;
database = {
type = "postgresql";
postgresql = {
username = "pvv_vv";
dbname = "pvv_vv";
host = "postgres.pvv.ntnu.no";
password_file = config.sops.secrets."dibbler/postgresql/password".path;
};
};
};
};
worblehat = {
enable = true;
settings = {
general.quit_allowed = false;
database = {
type = "postgresql";
postgresql = {
username = "worblehat";
dbname = "worblehat";
host = "postgres.pvv.ntnu.no";
password = config.sops.secrets."worblehat/postgresql/password".path;
};
};
};
};
};
services.roowho2.settings.rwhod.ignoreUsers = [ "drumknotty" ];
}
+1
View File
@@ -16,6 +16,7 @@
fileSystems."/" =
{ device = "/dev/disk/by-uuid/c3aed415-0054-4ac5-8d29-75a99cc26451";
fsType = "btrfs";
options = [ "relatime" ];
};
fileSystems."/boot" =
+61 -2
View File
@@ -1,4 +1,4 @@
{ lib, values, ... }:
{ lib, pkgs, values, ... }:
let
# See microbel:/etc/exports
letters = [ "a" "b" "c" "d" "h" "i" "j" "k" "l" "m" "z" ];
@@ -6,6 +6,20 @@ in
{
systemd.targets."pvv-homedirs" = {
description = "PVV Homedir Partitions";
requires = map (l: "pvv-homedir-create-uidmapped-bindmounts@${l}.service") letters;
};
systemd.tmpfiles.settings."10-pvv-homedirs" = {
"/run/pvvhome".d = {
user = "root";
group = "root";
mode = "0755";
};
"/run/pvvhome/by-uid".d = {
user = "root";
group = "root";
mode = "0755";
};
};
systemd.mounts = map (l: {
@@ -17,7 +31,7 @@ in
type = "nfs";
what = "homepvv${l}.pvv.ntnu.no:/export/home/pvv/${l}";
where = "/run/pvv-home-mounts/${l}";
where = "/run/pvvhome/${l}";
options = lib.concatStringsSep "," [
"nfsvers=3"
@@ -54,4 +68,49 @@ in
"rw"
];
}) letters;
systemd.services."pvv-homedir-create-uidmapped-bindmounts@" = {
bindsTo = [ "run-pvvhome-%i.mount" ];
after = [ "run-pvvhome-%i.mount" ];
serviceConfig = {
Type = "oneshot";
};
path = with pkgs; [
coreutils
systemdMinimal
];
scriptArgs = "%i";
script = ''
for dir in "/run/pvvhome/$1"/*/; do
[[ -d "$dir" ]] || continue
uid="$(stat -c '%u' "$dir")"
mountpoint="/run/pvvhome/by-uid/$uid"
mkdir -p "$mountpoint"
unit_name=$(systemd-escape --path --suffix=mount "$mountpoint")
if systemctl --quiet is-active "$unit_name" ||
systemctl --quiet is-failed "$unit_name"; then
echo "Skipping existing mount unit: $unit_name"
continue
fi
systemd-mount \
--collect \
--fsck=no \
--type=none \
--options=bind \
--property=BindsTo=$(systemd-escape --path --suffix=mount "/run/pvvhome/$1") \
--property=After=$(systemd-escape --path --suffix=mount "/run/pvvhome/$1") \
"$dir" \
"$mountpoint" \
|| echo "Failed mounting for uid $uid"
done
'';
};
}
+5 -450
View File
@@ -1,455 +1,10 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.httpd;
# NOTE Enable this if you want to strace stuff in the sandbox...
debug = false;
homeLetters = [ "a" "b" "c" "d" "h" "i" "j" "k" "l" "m" "z" ];
phpOptions = lib.concatStringsSep "\n" (lib.mapAttrsToList (k: v: "${k} = ${v}"){
display_errors = "Off";
display_startup_errors = "Off";
post_max_size = "40M";
upload_max_filesize = "40M";
});
apache-log-processor = pkgs.callPackage ./apache-log-processor { };
# https://nixos.org/manual/nixpkgs/stable/#ssec-php-user-guide-installing-with-extensions
phpEnv = pkgs.php.buildEnv {
extensions = { all, ... }: with all; [
bz2
curl
decimal
gd
imagick
mysqli
mysqlnd
pgsql
posix
protobuf sqlite3
uuid
xml
xsl
zlib
zstd
pdo
pdo_mysql
pdo_pgsql
pdo_sqlite
];
extraConfig = phpOptions;
};
perlEnv = (pkgs.perl.withPackages (ps: with ps; [
pkgs.exiftool
pkgs.ikiwiki
pkgs.irssi
pkgs.nix.libs.nix-perl-bindings
CGI
DBDPg
DBDSQLite
DBDmysql
DBI
Git
ImageMagick
JSON
TemplateToolkit
])).overrideAttrs (prev: {
# NOTE: `pkgs.perl.propagatedBuildInputs` don't actually propagate through the
# wrapper derivation created by `withPackages`. This should compensate
# for that.
postBuild = prev.postBuild + ''
cp -r '${pkgs.perl}/nix-support' "$out"/nix-support
'';
});
# https://nixos.org/manual/nixpkgs/stable/#python.buildenv-function
pythonEnv = pkgs.python3.buildEnv.override {
extraLibs = with pkgs.python3Packages; [
legacy-cgi
matplotlib
requests
];
ignoreCollisions = true;
};
# https://nixos.org/manual/nixpkgs/stable/#sec-building-environment
fhsEnv = pkgs.buildEnv {
name = "userweb-env";
ignoreCollisions = true;
paths = with pkgs; [
bash
config.services.bro.instances.userweb-sendmail.client.package
perlEnv
pythonEnv
phpEnv
]
++ (with phpEnv.packages; [
# composer
])
++ [
# Useful packages for homepages
exiftool
gnuplot
ikiwiki-full
imagemagick
jhead
ruby
sbcl
sourceHighlight
# Missing packages from tom
# blosxom
# pyblosxom
# mediawiki (TODO: do people host their own mediawikis in userweb?)
# nanoblogger
# Version control
cvs
rcs
git
# Compression/Archival
bzip2
gnutar
gzip
lz4
unzip
xz
zip
zstd
# Other tools you might expect to find on a normal system
acl
coreutils-full
curl
diffutils
file
findutils
gawk
gnugrep
gnumake
gnupg
gnused
less
man
util-linux
vim
wget
which
xdg-utils
] ++ lib.optionals debug [
glibc.getent
strace
systemd
];
extraOutputsToInstall = [
"man"
"doc"
];
};
in
{
imports = [
./httpd.nix
./log-processor.nix
./mail.nix
./module.nix
./packages.nix
./passwd-sync.nix
];
sops.secrets = {
"httpd/passwd-ssh-key" = { };
"httpd/ssh-known-hosts" = { };
};
services.httpd = {
enable = true;
adminAddr = "drift@pvv.ntnu.no";
# TODO: consider upstreaming systemd support
# TODO: mod_log_journald in v2.5
package = pkgs.apacheHttpd.overrideAttrs (prev: {
nativeBuildInputs = prev.nativeBuildInputs ++ [ pkgs.pkg-config ];
buildInputs = prev.buildInputs ++ [ pkgs.systemdLibs ];
configureFlags = prev.configureFlags ++ [ "--enable-systemd" ];
});
enablePHP = true;
phpPackage = phpEnv;
inherit phpOptions;
enablePerl = true;
# TODO: mod_log_journald in v2.5
extraModules = [
"systemd"
"userdir"
{
name = "perl";
path = let
mod_perl = pkgs.symlinkJoin {
name = "userweb_modperl_with_custom_perl_env";
ignoreCollisions = true;
paths = [
(pkgs.apacheHttpdPackages.mod_perl.override {
apacheHttpd = cfg.package.out;
})
perlEnv
];
};
in "${mod_perl}/modules/mod_perl.so";
}
];
logPerVirtualHost = false;
extraConfig = ''
TraceEnable on
LogLevel warn rewrite:trace3
'';
virtualHosts."temmie.pvv.ntnu.no" = {
forceSSL = true;
enableACME = true;
serverAliases = [
"www2.pvv.ntnu.no"
];
extraConfig = ''
CustomLog "${cfg.logDir}/access.log" combined
CustomLog "|${lib.getExe apache-log-processor} access" combined
ErrorLog "|${lib.getExe apache-log-processor} error"
ScriptLog "${cfg.logDir}/cgi.log"
UserDir ${lib.concatMapStringsSep " " (l: "/home/pvv/${l}/*/web-docs") homeLetters}
UserDir disabled root
AddHandler cgi-script .cgi
DirectoryIndex index.html index.html.var index.php index.php3 index.cgi index.phtml index.shtml meg.html
SetEnvIf Request_URI "^/~([^/]+)" USERDIR_USER=$1
<Directory "/home/pvv/?/*/web-docs">
Options MultiViews Indexes SymLinksIfOwnerMatch ExecCGI IncludesNoExec
AllowOverride All
Require all granted
</Directory>
<DirectoryMatch "^/home/pvv/.*/web-docs/(${lib.concatStringsSep "|" [
"\\.git"
"\\.hg"
"\\.svn"
"\\.ssh"
"\\.env"
"\\.envrc"
"\\.bzr"
"\\.venv"
"CVS"
"RCS"
".*\\.swp"
".*\\.bak"
".*~"
]})(/|$)">
AllowOverride All
Require all denied
</DirectoryMatch>
'';
};
};
networking.firewall.allowedTCPPorts = [
80
443
];
# socket activation comes in v2.5
# systemd.sockets.httpd = {
# wantedBy = [ "sockets.target" ];
# description = "HTTPD socket";
# listenStreams = [
# "0.0.0.0:80"
# "0.0.0.0:443"
# ];
# };
# NOTE: 54 -> 33, this is the UID/GID we used for www-data on tom in the past.
# Any files accessed by or created by httpd will do so over NFS with this
# UID/GID pair as its credentials.
# This overlaps with the hardcoded `disnix` uid in nixpkgs, but we *probably*
# won't be using that for the foreseeable future.
users.users."wwwrun".uid = lib.mkForce 33;
users.groups."wwwrun".gid = lib.mkForce 33;
systemd.services.httpd = {
after = [ "pvv-homedirs.target" ];
requires = [ "pvv-homedirs.target" ];
environment = {
PATH = lib.mkForce "/usr/bin";
};
serviceConfig = {
Type = lib.mkForce "notify";
ExecStartPre = let
rsyncCommand = ''${lib.getExe pkgs.rsync} -e "${pkgs.openssh}/bin/ssh -o UserKnownHostsFile=%d/ssh-known-hosts -i %d/sshkey" -avz'';
in lib.mkForce [
"${lib.getExe (pkgs.writeShellApplication {
name = "http-exec-start-pre-remove-old-semaphores";
text = ''
# Get rid of old semaphores. These tend to accumulate across
# server restarts, eventually preventing it from restarting
# successfully.
for i in $(${pkgs.util-linux}/bin/ipcs -s | grep ' ${cfg.user} ' | cut -f2 -d ' '); do
${pkgs.util-linux}/bin/ipcrm -s "$i"
done
'';
})}"
"${rsyncCommand} pvv@smtp.pvv.ntnu.no:/etc/passwd /run/httpd/pamunix-in/"
"${rsyncCommand} pvv@smtp.pvv.ntnu.no:/etc/group /run/httpd/pamunix-in/"
(let
args = lib.cli.toCommandLineShellGNU { } {
passwd-file = "/run/httpd/pamunix-in/passwd";
group-file = "/run/httpd/pamunix-in/group";
output-dir = "/run/httpd/pamunix-out";
shadow-file = pkgs.emptyFile;
output-passwd = true;
ignore-user-file = toString ./ignore_user_file.txt;
ignore-group-file = toString ./ignore_group_file.txt;
};
in ''${lib.getExe pkgs.passwd2systemd-users} ${args}'')
"${lib.getExe' pkgs.coreutils "shred"} -u /run/httpd/pamunix-in/passwd /run/httpd/pamunix-in/group"
":${lib.getExe pkgs.gnused} -i '$ a\\\\root:x:0:0:System administrator:/root:/run/current-system/sw/bin/bash' /run/httpd/pamunix-out/passwd"
":${lib.getExe pkgs.gnused} -i '$ a\\\\wwwrun:x:54:54:Apache httpd user:/var/empty:/run/current-system/sw/bin/bash' /run/httpd/pamunix-out/passwd"
":${lib.getExe pkgs.gnused} -i '$ a\\\\root:x:0:' /run/httpd/pamunix-out/group"
":${lib.getExe pkgs.gnused} -i '$ a\\\\wwwrun:x:54:' /run/httpd/pamunix-out/group"
"${lib.getExe' pkgs.coreutils "cat"} /run/httpd/pamunix-out/passwd"
"+${lib.getExe' pkgs.coreutils "chown"} root:root /run/httpd/pamunix-out/passwd /run/httpd/pamunix-out/group"
"+${lib.getExe' pkgs.coreutils "chmod"} 0644 /run/httpd/pamunix-out/passwd /run/httpd/pamunix-out/group"
"+${lib.getExe pkgs.mount} --bind /run/httpd/pamunix-out/passwd /etc/passwd"
"+${lib.getExe pkgs.mount} --bind /run/httpd/pamunix-out/group /etc/group"
];
ExecStart = lib.mkForce "${cfg.package}/bin/httpd -D FOREGROUND -f /etc/httpd/httpd.conf -k start";
ExecReload = lib.mkForce "${cfg.package}/bin/httpd -f /etc/httpd/httpd.conf -k graceful";
ExecStop = lib.mkForce "";
KillMode = "mixed";
LoadCredential=[
"sshkey:${config.sops.secrets."httpd/passwd-ssh-key".path}"
"ssh-known-hosts:${config.sops.secrets."httpd/ssh-known-hosts".path}"
];
ConfigurationDirectory = [ "httpd" ];
LogsDirectory = [ "httpd" ];
LogsDirectoryMode = "0700";
AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" "CAP_SETUID" "CAP_SETGID" ] ++ lib.optionals debug [ "CAP_SYS_PTRACE" ];
CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" "CAP_SETUID" "CAP_SETGID" ] ++ lib.optionals debug [ "CAP_SYS_PTRACE" ];
LockPersonality = !debug;
PrivateDevices = true;
PrivateTmp = true;
# NOTE: this removes CAP_NET_BIND_SERVICE...
# PrivateUsers = true;
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = "tmpfs";
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectSystem = true;
RemoveIPC = true;
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_UNIX"
"AF_NETLINK"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SocketBindDeny = "any";
SocketBindAllow = [
"tcp:80"
"tcp:443"
];
SystemCallArchitectures = "native";
SystemCallFilter = lib.mkIf (!debug) [
"@system-service"
"@setuid"
];
UMask = "0077";
RuntimeDirectoryMode = "0750";
RuntimeDirectory = [
"httpd/root-mnt"
"httpd/pamunix-in"
"httpd/pamunix-out"
];
RootDirectory = "/run/httpd/root-mnt";
MountAPIVFS = true;
BindReadOnlyPaths = [
builtins.storeDir
"/etc"
"/dev/null"
"/etc/resolv.conf"
"/var/lib/acme"
"-/run/httpd/pamunix-out/passwd:/etc/passwd"
"-/run/httpd/pamunix-out/group:/etc/group"
"${pkgs.writeText "userweb-fake-nsswitch.conf" ''
passwd: files
group: files
shadow: files
sudoers: files
hosts: mymachines resolve [!UNAVAIL=return] files myhostname dns
networks: files
ethers: files
services: files
protocols: files
rpc: files
subuid: files
subgid: files
''}:/etc/nsswitch.conf"
"${fhsEnv}/bin:/bin"
"${fhsEnv}/sbin:/sbin"
"${fhsEnv}/lib:/lib"
"${fhsEnv}/share:/share"
] ++ (lib.mapCartesianProduct ({ parent, child }: "${fhsEnv}${child}:${parent}${child}") {
parent = [
"/local"
"/opt"
"/opt/local"
"/store"
"/store/gnu"
"/usr"
"/usr/local"
"/run/current-system/sw"
];
child = [
"/bin"
"/sbin"
"/lib"
"/libexec"
"/include"
"/share"
];
});
BindPaths = map (l: "/run/pvv-home-mounts/${l}:/home/pvv/${l}") homeLetters;
};
};
# TODO: create phpfpm pools with php environments that contain packages similar to those present on tom
}
+318
View File
@@ -0,0 +1,318 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.httpd;
mcfg = config.services.pvv-userweb;
in
{
services.httpd = {
enable = true;
adminAddr = "drift@pvv.ntnu.no";
# TODO: consider upstreaming systemd support
# TODO: mod_log_journald in v2.5
package = pkgs.apacheHttpd.overrideAttrs (prev: {
nativeBuildInputs = prev.nativeBuildInputs ++ [ pkgs.pkg-config ];
buildInputs = prev.buildInputs ++ [ pkgs.systemdLibs ];
configureFlags = prev.configureFlags ++ [ "--enable-systemd" ];
});
enablePHP = true;
phpPackage = mcfg.php.env;
phpOptions = mcfg.php.options;
# NOTE: we include our own `mod_perl` in `extraModules` instead.
enablePerl = false;
# NOTE: we include `mod_userdir` in `extraModules` and configure this in `extraConfig` ourselves.
# enableUserDir = false;
# TODO: mod_log_journald in v2.5
extraModules = [
"systemd"
"userdir"
{
name = "perl";
path = let
mod_perl = pkgs.symlinkJoin {
name = "userweb_modperl_with_custom_perl_env";
ignoreCollisions = true;
paths = [
(pkgs.apacheHttpdPackages.mod_perl.override {
apacheHttpd = cfg.package.out;
})
mcfg.perl.env
];
};
in "${mod_perl}/modules/mod_perl.so";
}
];
logPerVirtualHost = false;
extraConfig = lib.mkIf mcfg.debugMode ''
TraceEnable on
LogLevel warn rewrite:trace3
'';
virtualHosts."temmie.pvv.ntnu.no" = {
forceSSL = true;
enableACME = true;
serverAliases = [
"www2.pvv.ntnu.no"
];
extraConfig = ''
<Directory "${pkgs.emptyDirectory}">
Require all denied
LogLevel authz_core:crit
</Directory>
CustomLog "${cfg.logDir}/access.log" combined
CustomLog "/run/httpd-log-processor-access.fifo" combined
ErrorLog "/run/httpd-log-processor-error.fifo"
ScriptLog "${cfg.logDir}/cgi.log"
UserDir ${lib.concatMapStringsSep " " (l: "/home/pvv/${l}/*/web-docs") mcfg.homeLetters}
UserDir disabled root
UserDir disabled pvv
AddHandler cgi-script .cgi
DirectoryIndex ${lib.concatStringsSep " " [
"index.htm"
"index.html"
"index.html.var"
"index.shtml"
"index.xhtml"
"index.php"
"index.php3"
"index.php4"
"index.php5"
"index.php7"
"index.php8"
"index.pht"
"index.phtml"
"index.cgi"
"index.txt"
"meg.html"
]}
SetEnvIf Request_URI "^/~([^/]+)" USERDIR_USER=$1
<Directory "/home/pvv/?/*/web-docs">
Options MultiViews Indexes SymLinksIfOwnerMatch ExecCGI IncludesNoExec
AllowOverride All
Require all granted
</Directory>
${lib.concatMapStringsSep "\n" (d: ''
<DirectoryMatch "/${d}(/|$)">
Require all denied
</DirectoryMatch>
'') [
"\\.git"
"\\.hg"
"\\.svn"
"\\.ssh"
"\\.bzr"
"\\.venv"
"CVS"
"RCS"
".*\\.bak"
".*\\.bak.*"
".*\\.bkp"
".*\\.bkp.*"
".*\\.backup"
".*\\.backup.*"
]}
${lib.concatMapStringsSep "\n" (d: ''
<Files "${d}">
Require all denied
</Files>
'') [
".env"
".env.*"
".envs"
".envs.*"
".envrc"
"*.swp"
"*~"
"*.bak"
"*.bak*"
"*.bkp"
"*.bkp*"
"*.backup"
"*.backup*"
"*.lck"
"*.lock"
"LCK..*"
]}
<FilesMatch ".+\.ph(p[34578]?|t|tml)$">
SetHandler application/x-httpd-php
</FilesMatch>
<FilesMatch ".+\.phps$">
SetHandler application/x-httpd-php-source
Require all denied
</FilesMatch>
<FilesMatch "\.pl$">
SetHandler modperl
PerlResponseHandler ModPerl::Registry
Options +ExecCGI
</FilesMatch>
'';
};
};
networking.firewall.allowedTCPPorts = [
80
443
];
# socket activation comes in v2.5
# systemd.sockets.httpd = {
# wantedBy = [ "sockets.target" ];
# description = "HTTPD socket";
# listenStreams = [
# "0.0.0.0:80"
# "0.0.0.0:443"
# ];
# };
# NOTE: 54 -> 33, this is the UID/GID we used for www-data on tom in the past.
# Any files accessed by or created by httpd will do so over NFS with this
# UID/GID pair as its credentials.
# This overlaps with the hardcoded `disnix` uid in nixpkgs, but we *probably*
# won't be using that for the foreseeable future.
users.users."wwwrun".uid = lib.mkForce 33;
users.groups."wwwrun".gid = lib.mkForce 33;
systemd.targets.userweb = {
description = "PVV HTTPD UserWeb";
};
systemd.slices.system-userweb = {
description = "PVV HTTPD UserWeb";
};
systemd.services.httpd = {
after = [
"pvv-homedirs.target"
"httpd-log-processor@access.socket"
"httpd-log-processor@error.socket"
];
requires = [
"pvv-homedirs.target"
"httpd-log-processor@access.socket"
"httpd-log-processor@error.socket"
];
requiredBy = [ "userweb.target" ];
environment = {
PATH = lib.mkForce "/usr/bin";
};
serviceConfig = {
Type = lib.mkForce "notify";
ExecStart = lib.mkForce "${cfg.package}/bin/httpd -D FOREGROUND -f /etc/httpd/httpd.conf -k start";
ExecReload = lib.mkForce "${cfg.package}/bin/httpd -f /etc/httpd/httpd.conf -k graceful";
ExecStop = lib.mkForce "";
KillMode = "mixed";
Slice = "system-userweb.slice";
ConfigurationDirectory = [ "httpd" ];
LogsDirectory = [ "httpd" ];
LogsDirectoryMode = "0700";
AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ] ++ lib.optionals mcfg.debugMode [ "CAP_SYS_PTRACE" ];
CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ] ++ lib.optionals mcfg.debugMode [ "CAP_SYS_PTRACE" ];
LockPersonality = !mcfg.debugMode;
PrivateDevices = true;
PrivateTmp = true;
# NOTE: this removes CAP_NET_BIND_SERVICE...
# PrivateUsers = true;
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = "tmpfs";
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectSystem = true;
RemoveIPC = true;
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_UNIX"
"AF_NETLINK"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SocketBindDeny = "any";
SocketBindAllow = [
"tcp:80"
"tcp:443"
];
SystemCallArchitectures = "native";
SystemCallFilter = lib.mkIf (!mcfg.debugMode) [ "@system-service" ];
UMask = "0077";
RuntimeDirectoryMode = "0750";
RuntimeDirectory = [ "httpd/root-mnt" ];
RootDirectory = "/run/httpd/root-mnt";
MountAPIVFS = true;
BindReadOnlyPaths = [
builtins.storeDir
"/etc"
"/dev/null"
"/var/lib/acme"
"/var/run/nscd"
"${mcfg.fhsEnv}/bin:/bin"
"${mcfg.fhsEnv}/sbin:/sbin"
"${mcfg.fhsEnv}/lib:/lib"
"${mcfg.fhsEnv}/share:/share"
] ++ (lib.mapCartesianProduct ({ parent, child }: "${mcfg.fhsEnv}${child}:${parent}${child}") {
parent = [
"/local"
"/opt"
"/opt/local"
"/store"
"/store/gnu"
"/usr"
"/usr/local"
"/run/current-system/sw"
];
child = [
"/bin"
"/sbin"
"/lib"
"/libexec"
"/include"
"/share"
];
});
BindPaths = (lib.mapCartesianProduct ({ directoryFn, letter }: "/run/pvvhome/${letter}:${directoryFn letter}${letter}") {
directoryFn = [
(_: "/home/pvv/")
(l: "/amd/homepvv${l}/")
];
letter = mcfg.homeLetters;
}) ++ [
"/run/httpd-log-processor-access.fifo"
"/run/httpd-log-processor-error.fifo"
];
};
};
# TODO: create phpfpm pools with php environments that contain packages similar to those present on tom
}
@@ -0,0 +1,113 @@
{ config, lib, pkgs, values, ... }:
let
mcfg = config.services.pvv-userweb;
in
{
systemd.targets.sockets.wants = [
"httpd-log-processor@access.socket"
"httpd-log-processor@error.socket"
];
systemd.sockets."httpd-log-processor@" = lib.mkIf config.services.httpd.enable {
requiredBy = [ "userweb.target" ];
socketConfig = {
ListenFIFO = "/run/httpd-log-processor-%i.fifo";
RemoveOnStop = true;
SocketUser = "wwwrun";
SocketGroup = "wwwrun";
SocketMode = "0600";
};
};
systemd.services."httpd-log-processor@" = lib.mkIf config.services.httpd.enable {
requiredBy = [ "userweb.target" ];
after = [ "httpd-passwd-sync.service" ];
requires = [ "httpd-passwd-sync.service" ];
serviceConfig = {
User = "wwwrun";
Group = "wwwrun";
Slice = "system-userweb.slice";
Restart = "on-failure";
StandardInput = "socket";
StandardOutput = "journal";
StandardError = "journal";
ExecStart = "${lib.getExe mcfg.apacheLogProcessorPackage} %i";
AmbientCapabilities = [ "CAP_SETUID" "CAP_SETGID" ];
CapabilityBoundingSet = [ "CAP_SETUID" "CAP_SETGID" ];
DeviceAllow = [ "" ];
IPAddressDeny = "any";
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateDevices = true;
PrivateIPC = true;
PrivateNetwork = true;
PrivateTmp = true;
PrivateUsers = false;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = "tmpfs";
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
RemoveIPC = true;
RestrictAddressFamilies = [ "none" ];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SocketBindDeny = "any";
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"@setuid"
"~@resources"
];
UMask = "0077";
RootDirectory = "/run/httpd-log-processor-%i/root-mnt";
MountAPIVFS = true;
RuntimeDirectoryMode = "0750";
RuntimeDirectory = [ "httpd-log-processor-%i/root-mnt" ];
BindReadOnlyPaths = [
builtins.storeDir
"/etc"
"/var/lib/httpd-passwd-sync/passwd:/etc/passwd"
"/var/lib/httpd-passwd-sync/group:/etc/group"
"${pkgs.writeText "userweb-fake-nsswitch.conf" ''
passwd: files
group: files
shadow: files
sudoers: files
hosts: mymachines resolve [!UNAVAIL=return] files myhostname dns
networks: files
ethers: files
services: files
protocols: files
rpc: files
subuid: files
subgid: files
''}:/etc/nsswitch.conf"
] ++ lib.optionals mcfg.debugMode [
"/bin"
];
BindPaths = map (l: "/run/pvvhome/${l}:/home/pvv/${l}") mcfg.homeLetters ++ [
"/var/log/httpd"
];
};
};
}
+8 -8
View File
@@ -1,14 +1,13 @@
{ config, lib, pkgs, ... }:
{
services.postfix.enable = lib.mkForce false;
assertions = [{
assertion = config.services.nullmailer.enable;
message = ''
Expected nullmailer to be enabled for temmie userweb.
services.nullmailer = {
enable = true;
config = {
me = config.networking.fqdn;
remotes = "mail.pvv.ntnu.no smtp --port=25";
};
};
If you change the default sendmail implementation, please make sure that temmie userweb works correctly!
'';
}];
services.bro = {
enable = true;
@@ -70,6 +69,7 @@
serviceConfig = {
User = "nullmailer-user";
Group = "nullmailer-user";
Slice = "system-userweb.slice";
ReadWritePaths = [
"/var/spool/nullmailer"
+118
View File
@@ -0,0 +1,118 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.pvv-userweb;
in
{
options.services.pvv-userweb = {
enable = lib.mkEnableOption "" // {
default = true;
};
debugMode = lib.mkEnableOption "";
apacheLogProcessorPackage = lib.mkOption {
type = lib.types.package;
default = pkgs.callPackage ./apache-log-processor { };
};
homeLetters = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ "a" "b" "c" "d" "h" "i" "j" "k" "l" "m" "z" ];
readOnly = true;
};
packages = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = _: [ ];
};
php.extensions = lib.mkOption {
type = lib.types.functionTo (lib.types.listOf lib.types.package);
default = _: [ ];
};
php.options = lib.mkOption {
type = lib.types.attrsOf lib.types.str;
default = {
display_errors = "Off";
display_startup_errors = "Off";
post_max_size = "40M";
upload_max_filesize = "40M";
};
apply = attrs: lib.concatStringsSep "\n" (lib.mapAttrsToList (k: v: "${k} = ${v}") attrs);
};
# https://nixos.org/manual/nixpkgs/stable/#ssec-php-user-guide-installing-with-extensions
php.env = lib.mkOption {
type = lib.types.package;
readOnly = true;
default = pkgs.php.buildEnv {
extensions = cfg.php.extensions;
extraConfig = cfg.php.options;
};
};
perl.packages = lib.mkOption {
type = lib.types.functionTo (lib.types.listOf lib.types.package);
default = _: [ ];
};
perl.env = lib.mkOption {
type = lib.types.package;
readOnly = true;
default = (pkgs.perl.withPackages cfg.perl.packages).overrideAttrs (prev: {
# NOTE: `pkgs.perl.propagatedBuildInputs` don't actually propagate through the
# wrapper derivation created by `withPackages`. This should compensate
# for that.
postBuild = prev.postBuild + ''
cp -r '${pkgs.perl}/nix-support' "$out"/nix-support
'';
});
};
python3.packages = lib.mkOption {
type = lib.types.functionTo (lib.types.listOf lib.types.package);
default = _: [ ];
};
python3.env = lib.mkOption {
type = lib.types.package;
readOnly = true;
default = pkgs.python3.buildEnv.override {
extraLibs = cfg.python3.packages pkgs.python3Packages;
ignoreCollisions = true;
};
};
fhsEnv = lib.mkOption {
type = lib.types.package;
readOnly = true;
default = let
in pkgs.buildEnv {
name = "userweb-env";
ignoreCollisions = true;
paths = with pkgs; [
bash
config.services.bro.instances.userweb-sendmail.client.package
cfg.perl.env
cfg.python3.env
cfg.php.env
] ++ cfg.packages;
extraOutputsToInstall = [
"man"
"doc"
];
};
};
};
config = lib.mkIf cfg.enable {
services.pvv-userweb.packages = lib.mkIf cfg.debugMode (with pkgs; [
glibc.getent
strace
systemd
]);
};
}
+104
View File
@@ -0,0 +1,104 @@
{ pkgs, ... }:
{
services.pvv-userweb = {
packages = with pkgs; [
# Useful packages for homepages
exiftool
gnuplot
ikiwiki-full
imagemagick
jhead
ruby
sbcl
sourceHighlight
# Missing packages from tom
# blosxom
# pyblosxom
# mediawiki (TODO: do people host their own mediawikis in userweb?)
# nanoblogger
# Version control
cvs
rcs
git
# Compression/Archival
bzip2
gnutar
gzip
lz4
unzip
xz
zip
zstd
# Other tools you might expect to find on a normal system
acl
coreutils-full
curl
diffutils
file
findutils
gawk
gnugrep
gnumake
gnupg
gnused
less
man
util-linux
vim
wget
which
xdg-utils
];
php.extensions = { all, ... }: with all; [
bz2
curl
decimal
gd
imagick
mysqli
mysqlnd
pgsql
posix
protobuf sqlite3
uuid
xml
xsl
zlib
zstd
pdo
pdo_mysql
pdo_pgsql
pdo_sqlite
];
perl.packages = perlPkgs: with perlPkgs; [
pkgs.exiftool
pkgs.ikiwiki
pkgs.irssi
pkgs.nix.libs.nix-perl-bindings
CGI
DBDPg
DBDSQLite
DBDmysql
DBI
Git
ImageMagick
JSON
TemplateToolkit
];
python3.packages = pythonPkgs: with pythonPkgs; [
legacy-cgi
matplotlib
requests
];
};
}
@@ -0,0 +1,147 @@
{ config, lib, pkgs, values, ... }:
let
mcfg = config.services.pvv-userweb;
in
{
config = lib.mkIf mcfg.enable {
sops.secrets = {
"httpd/passwd-ssh-key" = { };
"httpd/ssh-known-hosts" = { };
};
# NOTE: because we are running as `DynamicUser` and we want the result files to be available to
# other services, this directory needs to be created via systemd-tmpfiles
systemd.tmpfiles.settings."10-httpd-passwd-sync"."/var/lib/httpd-passwd-sync".d = {
user = "root";
group = "root";
mode = "0700";
};
systemd.timers.httpd-passwd-sync = {
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = "daily";
Persistent = true;
Unit = "httpd-passwd-sync.service";
};
};
systemd.services."httpd-passwd-sync" = {
requiredBy = [ "userweb.target" ];
after = [
"systemd-tmpfiles-setup.service"
"systemd-tmpfiles-resetup.service"
];
serviceConfig = {
Type = "oneshot";
Slice = "system-userweb.slice";
Restart = "on-failure";
RestartSec = "3s";
DynamicUser = true;
LoadCredential = [
"sshkey:${config.sops.secrets."httpd/passwd-ssh-key".path}"
"ssh-known-hosts:${config.sops.secrets."httpd/ssh-known-hosts".path}"
];
ExecStart = let
rsyncArgs = lib.cli.toCommandLineShellGNU { } {
verbose = true;
compress = true;
rsh = "${lib.getExe' pkgs.openssh "ssh"} -o BatchMode=yes -o UserKnownHostsFile=%d/ssh-known-hosts -i %d/sshkey";
};
inputDir = "/run/httpd-passwd-sync/in";
wipDir = "/run/httpd-passwd-sync/wip";
outputDir = "/var/lib/httpd-passwd-sync";
in [
"${lib.getExe pkgs.rsync} ${rsyncArgs} pvv@smtp.pvv.ntnu.no:/etc/passwd ${inputDir}/"
"${lib.getExe pkgs.rsync} ${rsyncArgs} pvv@smtp.pvv.ntnu.no:/etc/group ${inputDir}/"
(let
args = lib.cli.toCommandLineShellGNU { } {
passwd-file = "${inputDir}/passwd";
group-file = "${inputDir}/group";
output-dir = wipDir;
shadow-file = pkgs.emptyFile;
output-passwd = true;
ignore-user-file = toString ./ignore_user_file.txt;
ignore-group-file = toString ./ignore_group_file.txt;
};
in ''${lib.getExe pkgs.passwd2systemd-users} ${args}'')
"${lib.getExe' pkgs.coreutils "shred"} -u ${inputDir}/passwd ${inputDir}/group"
":${lib.getExe pkgs.gnused} -i '$ a\\\\root:x:0:0:System administrator:/root:/run/current-system/sw/bin/bash' ${wipDir}/passwd"
":${lib.getExe pkgs.gnused} -i '$ a\\\\wwwrun:x:54:54:Apache httpd user:/var/empty:/run/current-system/sw/bin/bash' ${wipDir}/passwd"
":${lib.getExe pkgs.gnused} -i '$ a\\\\root:x:0:' ${wipDir}/group"
":${lib.getExe pkgs.gnused} -i '$ a\\\\wwwrun:x:54:' ${wipDir}/group"
"+${lib.getExe' pkgs.coreutils "install"} -m644 -o root -g root -t '${outputDir}' ${wipDir}/passwd ${wipDir}/group"
"${lib.getExe' pkgs.coreutils "shred"} -u ${wipDir}/passwd ${wipDir}/group"
];
AmbientCapabilities = [ "" ];
CapabilityBoundingSet = [ "" ];
DeviceAllow = [ "" ];
LockPersonality = true;
MemoryDenyWriteExecute = true;
PrivateDevices = true;
PrivateTmp = true;
PrivateUsers = true;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = "tmpfs";
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
ProtectKernelTunables = true;
RemoveIPC = true;
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_UNIX"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SocketBindDeny = "any";
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~@resources"
];
UMask = "0077";
IPAddressAllow = [
values.hosts.microbel.ipv4
values.hosts.microbel.ipv6
];
IPAddressDeny = "any";
RootDirectory = "/run/httpd-passwd-sync/root-mnt";
MountAPIVFS = true;
RuntimeDirectoryMode = "0750";
RuntimeDirectory = [
"httpd-passwd-sync/root-mnt"
"httpd-passwd-sync/in"
"httpd-passwd-sync/wip"
];
BindPaths = [
"/var/lib/httpd-passwd-sync"
];
BindReadOnlyPaths = [
builtins.storeDir
"/etc"
"/var/run/nscd"
];
};
};
};
}
+1
View File
@@ -13,6 +13,7 @@
fileSystems."/" =
{ device = "/dev/disk/by-uuid/4e8ecdd2-d453-4fff-b952-f06da00f3b85";
fsType = "ext4";
options = [ "relatime" ];
};
swapDevices = [ {
View File
+5
View File
@@ -109,5 +109,10 @@ in
Group = "drumknotty";
};
};
systemd.services."drumknotty-screen-session".serviceConfig.StateDirectory = [
"dibbler"
"dibbler/crashdumps"
];
};
}
+4
View File
@@ -117,6 +117,10 @@ in
];
};
};
systemd.services."drumknotty-screen-session".serviceConfig.StateDirectory = [
"worblehat"
];
}
(lib.mkIf ((mainCfg.enable && cfg.enable) || cfg.deadline-daemon.enable) {
+2
View File
@@ -123,5 +123,7 @@ in {
};
};
};
services.roowho2.settings.rwhod.ignoreUsers = [ "greg" ];
}
+224
View File
@@ -0,0 +1,224 @@
{ config, options, lib, pkgs, utils, ... }:
let
cfg = config.services.python-http-handlers;
in
{
options.services.python-http-handlers = lib.mkOption {
default = { };
type = lib.types.attrsOf (lib.types.submodule ({ name, ... }: {
options = {
enable = lib.mkEnableOption "" // {
default = true;
description = "Whether to enable this python HTTP handler.";
};
name = lib.mkOption {
type = lib.types.str;
default = "phh-${name}";
defaultText = "phh-<name>";
description = ''
The name of this HTTP handler.
This will be used for the systemd service among other things.
'';
};
listenStreams = lib.mkOption {
type = with lib.types; listOf str;
default = [
"/run/phh-${name}.socket"
];
defaultText = lib.literalExpression ''
[
"/run/phh-<name>.socket"
]
'';
description = ''
For each item in this list, a `ListenStream`
option in the `[Socket]` section will be created.
'';
};
socketConfig = lib.mkOption {
type = utils.systemdUtils.unitOptions.unitOption;
default = { };
description = ''
Config for the systemd socket's `[Socket]` section.
See {manpage}`systemd.socket(5)` for details.
'';
};
serviceConfig = lib.mkOption {
type = utils.systemdUtils.unitOptions.unitOption;
default = { };
description = ''
Config for the systemd service's `[Service]` section.
See {manpage}`systemd.exec(5)` and {manpage}`systemd.service(5)` for details.
'';
};
enableDefaultHardening = lib.mkEnableOption "" // {
default = true;
description = ''
Whether to enable a set of recommended systemd hardening directives.
If this breaks the service, you can either override the offending directives
through {option}`serviceConfig`, or disable this option altogether.
'';
};
libraries = lib.mkOption {
type = with lib.types; listOf package;
default = [ ];
example = lib.literalExpression ''
with pkgs.python3Packages; [
matplotlib
numpy
pillow
]
'';
description = ''
Extra python libraries to make available to the service.
'';
};
flakeIgnore = lib.mkOption {
type = with lib.types; listOf str;
default = [
"E111" # indentation is not a multiple of four
"E201" # whitespace after (
"E202" # whitespace after )
"E203" # whitespace before :
"E211" # whitespace before (
"E251" # unexpected spaces around keyword / parameter equals
"E301" # expected 1 blank line, found 0
"E302" # expected 2 blank lines, found 0
"E303" # too many blank lines
"E305" # expected 2 blank lines after end of function or class
"E306" # expected 1 blank line before a nested definition
"E501" # max line length
"E704" # multiple statements on one line (def)
];
description = ''
A list of flake8 rules to ignore while linting the python code.
An opinionated list of bogus rules (according to module author) is provided as default.
'';
};
handler = lib.mkOption {
type = lib.types.lines;
default = ''
import json
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
body = {"ok": True}
data = json.dumps(body).encode()
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
'';
description = ''
Python code including the HTTP handler for the server.
You can include as many imports and functions as you'd like here, but you will need
to at least provide a `class Handler(BaseHTTPRequestHandler)` to handle incoming HTTP requests.
'';
};
};
}));
};
config = {
systemd.sockets = lib.pipe cfg [
lib.attrValues
(lib.filter (v: v.enable))
(vs: lib.genAttrs' vs (v: {
inherit (v) name;
value = {
wantedBy = [ "sockets.target" ];
inherit (v) listenStreams;
socketConfig = {
Accept = false;
} // v.socketConfig;
};
}))
];
systemd.services = lib.pipe cfg [
lib.attrValues
(lib.filter (v: v.enable))
(vs: lib.genAttrs' vs (v: {
inherit (v) name;
value = {
serviceConfig = {
Type = "simple";
DynamicUser = true;
ExecStart = let
package = pkgs.writers.writePython3Bin "${v.name}-bin" {
inherit (v) libraries flakeIgnore;
} ''
import socket
from http.server import HTTPServer, BaseHTTPRequestHandler
${v.handler}
class NoBindHTTPServer(HTTPServer):
def server_bind(): pass
def server_activate(): pass
def main():
httpd = NoBindHTTPServer(
("", 0),
Handler,
bind_and_activate=False,
)
httpd.socket = socket.fromfd(3, socket.AF_INET, socket.SOCK_STREAM)
httpd.serve_forever()
if __name__ == '__main__':
main()
'';
in lib.getExe package;
} // (lib.optionalAttrs v.enableDefaultHardening {
AmbientCapabilities = [ "" ];
CapabilityBoundingSet = [ "" ];
DeviceAllow = [ "" ];
LockPersonality = true;
NoNewPrivileges = true;
PrivateDevices = true;
PrivateTmp = true;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
RemoveIPC = true;
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SocketBindDeny = "any";
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~@privileged"
"~@resources"
];
UMask = "0077";
}) // v.serviceConfig;
};
}))
];
};
}
+20 -18
View File
@@ -1,7 +1,9 @@
config:
mysqld_exporter_password: ENC[AES256_GCM,data:I9K+QMqaN3FOOVKzeOR9Q6UERStXX0P8WEHyN1jzzbM=,iv:UxvIdlfAyJvNuxPkU4+guKPa0fiD0vVLzHOTYktcmso=,tag:ltnIqEwESYx9HBu8UN0ZLw==,type:str]
postgresql_dibbler_password: ENC[AES256_GCM,data:wP4CVz9qRE3CJrblWWYqOIkcH3LM5H81,iv:j8zr1TRNlPPqIppYlWhDoKlL7m2Ph2wQlU6bvFj8R9A=,tag:Cfp8zbYkoLqI7DTDpOBlJw==,type:str]
keys:
gatus:
mariadb: ENC[AES256_GCM,data:U7CGtjHacJlKcReEw3JO86okCVgLAkP92iX1bHGNw8qeImpvk5mNw77Ox7tbsChvozrJWa/Npu2pTBsNnVYYYA==,iv:hWa+KPiBc3AnH1tHCGJa8LhPXZ1o8sxufpGe7nUjV0E=,tag:mso5HEfmWAOGw350408X7g==,type:str]
postgres: ENC[AES256_GCM,data:7fI0JeZDK1MX5poXWaMo67PXbjdjvM+xPKioHSHmGdS8iNDGe5Ym6LlS/hOnPvvDuNFyHjKKizqDst0227U2gg==,iv:D3bz/xyFrnQsUCiMEFq8JOjSudyiw+idEMWQ1e6Uk3k=,tag:8XqadKVHK9NMWehK7V5J0Q==,type:str]
grafana:
secret_key: ENC[AES256_GCM,data:+WoAJbDBEgKs0RoHT+7oEELAVQ+/2Xt+5RTMSXg23moCqVRx+Gzll9P5Drw=,iv:AkRn/Y20iEe5i1T+84wAgLCTFtAox2G3giyawAkltAw=,tag:BZbt5Wb5lYLIJBm/pfP4GQ==,type:str]
admin_password: ENC[AES256_GCM,data:ttKwfC4WuXeL/6x4,iv:x1X+e3z08CR992GzC62YnFIN7SGrE81/nDNrgcgVzx0=,tag:YajUoy61kYbpeGeC7yNrXQ==,type:str]
@@ -10,8 +12,7 @@ keys:
postgres_exporter_knakelibrak_env: ENC[AES256_GCM,data:xjC7DGXrW2GIJq8XioIZb+jSe/Hzcz0tv9cUHmX/n1nhI+D64lYt+EKnq1+RX/vJzU4sTaKjveKBh88Qqnv6RQm+MZC//dIxcvnnAdl50qnHZyBCaFFEzSNI8I8vGyArMk8Ja72clBq3kMpUz/pLBP0qDrjblKDoWkU=,iv:ZW98hJy8A5t4Oxtu17R3tM7gou183VLbgBsHA8LFuJY=,tag:VMOvQz3X/XDylV1YFg2Jsg==,type:str]
sops:
age:
- recipient: age102e6y8gah0ntr6fxqnkpepc8ar29p6ls7ks9ka7v8w87q8scm9yqmc2u8d
enc: |
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyTWRSM3IwMmxtTmZVcCsw
OUhlakxHZzgrSEhEdUZFTXE1anNjQ2wvdkZFCnB6S1l3TXQ3ZGFYWmtYM1cwMFZT
@@ -19,8 +20,8 @@ sops:
YlltQ3FBU3RBYUx4TnNPRk1SUWNqZG8KAJjc09x553ncaWduGLsnIHdroaOmMasP
/fq0GzW6UNfmE2rQ6qrQti21B37/sN0WMLCSPLUPG45kBgx20GG4hQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age1ug30gg4y7ftuya0wdv7q0vh4egn00wlv2th7mt7cgc2ze46wmvyq9lq6ge
enc: |
recipient: age102e6y8gah0ntr6fxqnkpepc8ar29p6ls7ks9ka7v8w87q8scm9yqmc2u8d
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBTOWFvcFFzc1lmNVdmV3lX
cVVLNHowcGdENzI5UUJLZTNSMHhjNlI2c0FnCmdwOS9oL1kwTnhwbXRodWxxWVE3
@@ -28,8 +29,8 @@ sops:
eDVwd2dKMG9FRW1OY1pyUkhLeWw3b0EKtJpsQ/Ss39ZLiRNqUhn8sdB3hpQy7Syv
ererqhMkqmDugGEHPk6KpZuj7DVSK1di7JgA2qZOUPzI7UpxjaC0Kg==
-----END AGE ENCRYPTED FILE-----
- recipient: age1mrnldl334l2nszuta6ywvewng0fswv2dz9l5g4qcwe3nj4yxf92qjskdx6
enc: |
recipient: age1ug30gg4y7ftuya0wdv7q0vh4egn00wlv2th7mt7cgc2ze46wmvyq9lq6ge
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBOQU1iVXRkQmo4b3F1Vngz
S0pkNkVFR1FUb1djdmI0eHh3V3BBTDJTSTJZClA0S0Z0cTdFRmRaOEZQdHQzdGZ3
@@ -37,8 +38,8 @@ sops:
REdjRFZyY2pNdEd6cmgvQisyVDhLUEkKRItJ0CGbzlEB5RNAyem4feMVhTfcLef3
QIqltZ2l4LLexnkECi3FCJZHxrbUa+/RF6p1DsueUw7LLUnOcphB9A==
-----END AGE ENCRYPTED FILE-----
- recipient: age1hmpdk4h69wxpwqk9tkud39f66hprhehxtzhgw97r6dvr7v0mx5jscsuhkn
enc: |
recipient: age1mrnldl334l2nszuta6ywvewng0fswv2dz9l5g4qcwe3nj4yxf92qjskdx6
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAvZTBpaWM0c1hmODBaK0Iw
bmp1NzRacklXMHU0K2J2d0g5ajBiNlRNWGhRCm1DOWI0cm5BdTdlNmFzM2JVekNk
@@ -46,8 +47,8 @@ sops:
U0ZCT2toZ1ZMZ3E0bXRhSTQvNGFWNVkKhxfQDIDe2LQW7OMBJv0J267AW1wI32df
ZQxd657TEqzm7i19azrCS0jyRbfj2MYzEJAtTGiGZaNC9uKDFzBhKw==
-----END AGE ENCRYPTED FILE-----
- recipient: age1wrssr4z4g6vl3fd3qme5cewchmmhm0j2xe6wf2meu4r6ycn37anse98mfs
enc: |
recipient: age1hmpdk4h69wxpwqk9tkud39f66hprhehxtzhgw97r6dvr7v0mx5jscsuhkn
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBmRlJROHRKb21YUnlicmc1
MlptQllEcXFhajNKS1krMDdUMWk5QWo4eVJBCndGSlhXS1Vaa2RSTllIcmF1ZVpl
@@ -55,8 +56,8 @@ sops:
TE41aFdjU0h0ekQ2Zjg4Z3VQVjFWcnMK6zjSalqeYjyc4NH6nOeghlhYJydrz4pM
N5ZcXjRbrIVFdhbYnvQGKvGKZm0kK6vjzBjdT7BM6ctr8cq/qrz1xQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age1zhxul786an743u0fascv4wtc5xduu7qfy803lfs539yzhgmlq5ds2lznt5
enc: |
recipient: age1wrssr4z4g6vl3fd3qme5cewchmmhm0j2xe6wf2meu4r6ycn37anse98mfs
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBIRXpBa2tYc2xEeldub0VK
bkFwOFdlUGRZM0FVT0tyUW1RWnl0TjRUTUh3CnZlMC92MU1hRW1yZU1NSUdoUEZh
@@ -64,8 +65,8 @@ sops:
aXFQWlNVQ2laVm1ETStRemNZRXc3TUEKlPYSU3gp67dsPfbEJkru4ieMvspC7+pu
rfp315HLyj1FGhrA8f2qOxE/PYI2rn0yKm80KffWBV7ylX/uonm4Fg==
-----END AGE ENCRYPTED FILE-----
- recipient: age1sqs7urnzsdy64efmd0zukzv3gs5pnjksuxd7nqmdwdy5l0nqnunq6hyune
enc: |
recipient: age1zhxul786an743u0fascv4wtc5xduu7qfy803lfs539yzhgmlq5ds2lznt5
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBsaTEzOFBEeG9LVThSVmQ5
VXBoaFpueFRCbFJ1akE4RWc1aE1HUmVGcXdZCjFnbU0wd2drazNsTmNBMHNuOFhO
@@ -73,8 +74,9 @@ sops:
dC9meDZlc3d3aUJEVjc4REF0Y1BLcGcK79LbJzc5KVgEgyJR11crGuX8YcVoJBbT
Fin7Zoon06L7qx0Zw5u27wV7RKMnYT7hOMiWs6660ZTLcYJ5M1aEZQ==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2026-06-07T12:51:04Z"
mac: ENC[AES256_GCM,data:otGwzc3Bme1PGRU4zWRRf3kmAf5EDjT8sPkDK/zDrO0ve+d3x99Qls4DBZV8G6FsFtUXbeKVo70I5VpqUgaIef+nyMl6zzWkW1wpbKIBYjh5fkaP0xxhLnw+shrB088PAXT0wkP7hJBLO0ZJgTrpprJKhmeqVj2HEXBSJ1wSjk8=,iv:cjqtdbWBVLUfpQdykb3vKDKa/VC/kGBybwYtG/eStqc=,tag:remOj4bX/H/LlAPgcXHAdA==,type:str]
recipient: age1sqs7urnzsdy64efmd0zukzv3gs5pnjksuxd7nqmdwdy5l0nqnunq6hyune
lastmodified: "2026-07-21T09:40:54Z"
mac: ENC[AES256_GCM,data:FLpmsW9I21qNMFs6Tn/1AzFo+RcmCwtVdAaaGIrGlUi2l3gzb//ZK6ruI/VYx1R5DoX1OhD3EIg6aLMSOT6jiHf+8GwfhdijpayG1nrgeZW3SuFbjVlCYNMPH3DOJJB82U3T+ozSbpnZEtdUwmNWcZJt5F2hOEnoaNa+jLEKDao=,iv:qyQuyWuu+w2ynRvhIx0QVtw+tieO3dbQsUxEB5Brzp0=,tag:qYAj4h6foWm16YqIdZ6xbQ==,type:str]
pgp:
- created_at: "2026-05-20T17:35:58Z"
enc: |-
@@ -97,4 +99,4 @@ sops:
-----END PGP MESSAGE-----
fp: F7D37890228A907440E1FD4846B9228E814A2AAC
unencrypted_suffix: _unencrypted
version: 3.12.2
version: 3.13.2
File diff suppressed because one or more lines are too long
-19
View File
@@ -1,19 +0,0 @@
{ config, unstablePkgs, lib, ... }:
let
cfg = config.services.mysql;
cfgBak = config.services.mysqlBackup;
in
{
config.topology.self.services.mysql = lib.mkIf cfg.enable {
name = "MySQL";
icon = "${unstablePkgs.super-tiny-icons}/share/icons/SuperTinyIcons/svg/mysql.svg";
details.listen.text = "${cfg.settings.mysqld.bind-address or "127.0.0.1"}:${toString (cfg.settings.mysqld.port or 3306)}";
details.socket.text = cfg.settings.mysqld.socket or "/run/mysqld/mysqld.sock";
details.type.text = cfg.package.pname;
details.dataDir.text = cfg.dataDir;
# details.backup-time = lib.mkIf cfgBak.enable cfgBak.calendar;
# details.backup-location = lib.mkIf cfgBak.enable cfgBak.location;
};
}
+3 -1
View File
@@ -1,4 +1,4 @@
{ pkgs, ... }:
{ pkgs, config, ... }:
{
users.users.vegardbm = {
isNormalUser = true;
@@ -8,12 +8,14 @@
"drift"
"nix-builder-users"
];
shell = if config.programs.zsh.enable then pkgs.zsh else pkgs.bash;
packages = with pkgs; [
btop
eza
];
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDVA3HqEx3je6L1AC+bP8sTxu3ZTKvTCR0npCyOVAYK5 vbm@arch-xeon"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICrYATHNvBNAHr9G+VwZIaAQPe02iRgAjqtZkW4x/dje vbm@talos"
];
};
}
+4
View File
@@ -26,6 +26,10 @@ in rec {
ipv4 = pvv-ipv4 213;
ipv6 = pvv-ipv6 213;
};
knutsen-vpn = pvv-ipv4 191;
knutsen-tap = pvv-ipv4 253;
ludvigsen-tap = pvv-ipv4 254;
};
hosts = {