1 Commits

Author SHA1 Message Date
123dfd7605 all the broken 2025-10-04 20:35:06 +02:00
23 changed files with 427 additions and 332 deletions

128
flake.lock generated
View File

@@ -83,11 +83,11 @@
]
},
"locked": {
"lastModified": 1759499898,
"narHash": "sha256-UNzYHLWfkSzLHDep5Ckb5tXc0fdxwPIrT+MY4kpQttM=",
"lastModified": 1755946532,
"narHash": "sha256-POePremlUY5GyA1zfbtic6XLxDaQcqHN6l+bIxdT5gc=",
"owner": "hyprwm",
"repo": "aquamarine",
"rev": "655e067f96fd44b3f5685e17f566b0e4d535d798",
"rev": "81584dae2df6ac79f6b6dae0ecb7705e95129ada",
"type": "github"
},
"original": {
@@ -153,11 +153,11 @@
"rust-overlay": "rust-overlay"
},
"locked": {
"lastModified": 1759532138,
"narHash": "sha256-sLQIlgDwMP3mEY2PwjGW+cL56QQ2n2WXoZ3GpG5QWOY=",
"lastModified": 1759348172,
"narHash": "sha256-ZPUJX2ZA0ndcHndIA/S/nRESIJV0rifPr91SUpzJtEM=",
"owner": "chaotic-cx",
"repo": "nyx",
"rev": "bad02bbca5b5c6d45539a0d740ad0e21b1ba9afc",
"rev": "dd1af56ad79c965ee20c236ba6adbb2135ac02af",
"type": "github"
},
"original": {
@@ -212,11 +212,11 @@
"rust-analyzer-src": "rust-analyzer-src"
},
"locked": {
"lastModified": 1759646430,
"narHash": "sha256-V8mjmGzi9nS7BZfhpzYAOUg3BcCsC6MrEh9xlKq3+7s=",
"lastModified": 1759473677,
"narHash": "sha256-9AFDP5AhXe06aXXPsV7bDGH7KA9Wo4uUtK7pRrsxuFQ=",
"owner": "nix-community",
"repo": "fenix",
"rev": "b326bea4d58c9a58b346f17c710538eac00f71d1",
"rev": "8532b07ced6a95d57650124c79534a3c770431ab",
"type": "github"
},
"original": {
@@ -491,11 +491,11 @@
]
},
"locked": {
"lastModified": 1759523803,
"narHash": "sha256-PTod9NG+i3XbbnBKMl/e5uHDBYpwIWivQ3gOWSEuIEM=",
"lastModified": 1758108966,
"narHash": "sha256-ytw7ROXaWZ7OfwHrQ9xvjpUWeGVm86pwnEd1QhzawIo=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "cfc9f7bb163ad8542029d303e599c0f7eee09835",
"rev": "54df955a695a84cd47d4a43e08e1feaf90b1fd9b",
"type": "github"
},
"original": {
@@ -571,11 +571,11 @@
},
"hardware": {
"locked": {
"lastModified": 1759582739,
"narHash": "sha256-spZegilADH0q5OngM86u6NmXxduCNv5eX9vCiUPhOYc=",
"lastModified": 1759261527,
"narHash": "sha256-wPd5oGvBBpUEzMF0kWnXge0WITNsITx/aGI9qLHgJ4g=",
"owner": "nixos",
"repo": "nixos-hardware",
"rev": "3441b5242af7577230a78ffb03542add264179ab",
"rev": "e087756cf4abbe1a34f3544c480fc1034d68742f",
"type": "github"
},
"original": {
@@ -590,11 +590,11 @@
"rust-overlay": "rust-overlay_2"
},
"locked": {
"lastModified": 1759605748,
"narHash": "sha256-qALSaIE4fbTo0wbPjEp7RZKbtFk1cDhRZ0BYOHW0JwQ=",
"lastModified": 1759201995,
"narHash": "sha256-3STv6fITv8Ar/kl0H7vIA7VV0d2gyLh8UL0BOiVacXg=",
"owner": "helix-editor",
"repo": "helix",
"rev": "6fffaf6a7ded9a12fb2d5715a4eb83787a5e6402",
"rev": "bfcbef10c513108c7b43317569416c2eefc4ed44",
"type": "github"
},
"original": {
@@ -610,11 +610,11 @@
]
},
"locked": {
"lastModified": 1759573136,
"narHash": "sha256-ILSPD0Dm8p0w0fCVzOx98ZH8yFDrR75GmwmH3fS2VnE=",
"lastModified": 1759337100,
"narHash": "sha256-CcT3QvZ74NGfM+lSOILcCEeU+SnqXRvl1XCRHenZ0Us=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "5f06ceafc6c9b773a776b9195c3f47bbe1defa43",
"rev": "004753ae6b04c4b18aa07192c1106800aaacf6c3",
"type": "github"
},
"original": {
@@ -652,11 +652,11 @@
]
},
"locked": {
"lastModified": 1759337100,
"narHash": "sha256-CcT3QvZ74NGfM+lSOILcCEeU+SnqXRvl1XCRHenZ0Us=",
"lastModified": 1759261733,
"narHash": "sha256-G104PUPKBgJmcu4NWs0LUaPpSOTD4jiq4mamLWu3Oc0=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "004753ae6b04c4b18aa07192c1106800aaacf6c3",
"rev": "5a21f4819ee1be645f46d6b255d49f4271ef6723",
"type": "github"
},
"original": {
@@ -710,11 +710,11 @@
]
},
"locked": {
"lastModified": 1759490292,
"narHash": "sha256-T6iWzDOXp8Wv0KQOCTHpBcmAOdHJ6zc/l9xaztW6Ivc=",
"lastModified": 1758192433,
"narHash": "sha256-CR6RnqEJSTiFgA6KQY4TTLUWbZ8RBnb+hxQqesuQNzQ=",
"owner": "hyprwm",
"repo": "hyprgraphics",
"rev": "9431db625cd9bb66ac55525479dce694101d6d7a",
"rev": "c44e749dd611521dee940d00f7c444ee0ae4cfb7",
"type": "github"
},
"original": {
@@ -803,11 +803,11 @@
"xdph": "xdph"
},
"locked": {
"lastModified": 1759530922,
"narHash": "sha256-9NgZKpibALekGTPDc2O8lP8vFealQSZkXe+L+S7MMZU=",
"lastModified": 1759399554,
"narHash": "sha256-FsFugHj7He5siEcmoRUdMKHB8uMzyneK/fynPS57W4E=",
"owner": "hyprwm",
"repo": "hyprland",
"rev": "76d998743ac10e712238c1016db4d8e8d16f1049",
"rev": "3bcfa94ee4189faaa4daf661949e88cf28c00d94",
"type": "github"
},
"original": {
@@ -824,11 +824,11 @@
]
},
"locked": {
"lastModified": 1759613406,
"narHash": "sha256-PzgQJydp+RlKvwDi807pXPlURdIAVqLppZDga3DwPqg=",
"lastModified": 1759238633,
"narHash": "sha256-4/AtRCQKXuU49ozZZouWuC+T7vCjQh9HAz3N8Tt5OZE=",
"owner": "hyprwm",
"repo": "contrib",
"rev": "32e1a75b65553daefb419f0906ce19e04815aa3a",
"rev": "513d71d3f42c05d6a38e215382c5a6ce971bd77d",
"type": "github"
},
"original": {
@@ -942,11 +942,11 @@
]
},
"locked": {
"lastModified": 1759080228,
"narHash": "sha256-RgDoAja0T1hnF0pTc56xPfLfFOO8Utol2iITwYbUhTk=",
"lastModified": 1757694755,
"narHash": "sha256-j+w5QUUr2QT/jkxgVKecGYV8J7fpzXCMgzEEr6LG9ug=",
"owner": "hyprwm",
"repo": "hyprland-qtutils",
"rev": "629b15c19fa4082e4ce6be09fdb89e8c3312aed7",
"rev": "5ffdfc13ed03df1dae5084468d935f0a3f2c9a4c",
"type": "github"
},
"original": {
@@ -971,11 +971,11 @@
]
},
"locked": {
"lastModified": 1758927902,
"narHash": "sha256-LZgMds7M94+vuMql2bERQ6LiFFdhgsEFezE4Vn+Ys3A=",
"lastModified": 1756810301,
"narHash": "sha256-wgZ3VW4VVtjK5dr0EiK9zKdJ/SOqGIBXVG85C3LVxQA=",
"owner": "hyprwm",
"repo": "hyprlang",
"rev": "4dafa28d4f79877d67a7d1a654cddccf8ebf15da",
"rev": "3d63fb4a42c819f198deabd18c0c2c1ded1de931",
"type": "github"
},
"original": {
@@ -1006,11 +1006,11 @@
]
},
"locked": {
"lastModified": 1759572448,
"narHash": "sha256-o+r44fqPQM+/hQdjFy9qV9C51Jhty6M4icFVYocyJfA=",
"lastModified": 1759492718,
"narHash": "sha256-Mxi/LyyHE9VKUnBs4y1hXO+wRqukZJjbx/igqKQxkQk=",
"owner": "hyprwm",
"repo": "hyprlock",
"rev": "c8a6768dca626cf7d7cbc333095f048bc007b6d9",
"rev": "3cb799b1842016c85cca2db66fa502b8179cf0fe",
"type": "github"
},
"original": {
@@ -1069,11 +1069,11 @@
]
},
"locked": {
"lastModified": 1759490926,
"narHash": "sha256-7IbZGJ5qAAfZsGhBHIsP8MBsfuFYS0hsxYHVkkeDG5Q=",
"lastModified": 1756117388,
"narHash": "sha256-oRDel6pNl/T2tI+nc/USU9ZP9w08dxtl7hiZxa0C/Wc=",
"owner": "hyprwm",
"repo": "hyprutils",
"rev": "94cce794344538c4d865e38682684ec2bbdb2ef3",
"rev": "b2ae3204845f5f2f79b4703b441252d8ad2ecfd0",
"type": "github"
},
"original": {
@@ -1191,11 +1191,11 @@
]
},
"locked": {
"lastModified": 1759387127,
"narHash": "sha256-uuwJAP92SkHmnI1zo7rrK/gEuHtb97vFZcMa5w+0SZA=",
"lastModified": 1759217228,
"narHash": "sha256-P13ExJlhMVkrc5LxZLNkIJZhjNYo3LLXnxDsUNrdnMQ=",
"owner": "Jovian-Experiments",
"repo": "Jovian-NixOS",
"rev": "0cc290e05882745060fccfe6d7d073f913e0cce7",
"rev": "e52c15ab25f7dc68dde527c8df5bfa9d80d8e64f",
"type": "github"
},
"original": {
@@ -1278,11 +1278,11 @@
]
},
"locked": {
"lastModified": 1759629535,
"narHash": "sha256-VIXcJ2ahRgoqIUySwAz3r5mtITO2dp6tXGCVKVW6FmA=",
"lastModified": 1759455985,
"narHash": "sha256-8qDv7NXH3fj1CDXed7c7vJLtrRKDZSo0x6TaWSfelVg=",
"owner": "fufexan",
"repo": "nix-gaming",
"rev": "df388c42b54714bd121796a9cec9322b7fa2894e",
"rev": "eb5ab503cbd3cb386e8d85a55a9faed73ec7dc37",
"type": "github"
},
"original": {
@@ -1411,11 +1411,11 @@
},
"nixpkgs_6": {
"locked": {
"lastModified": 1759381078,
"narHash": "sha256-gTrEEp5gEspIcCOx9PD8kMaF1iEmfBcTbO0Jag2QhQs=",
"lastModified": 1758198701,
"narHash": "sha256-7To75JlpekfUmdkUZewnT6MoBANS0XVypW6kjUOXQwc=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "7df7ff7d8e00218376575f0acdcc5d66741351ee",
"rev": "0147c2f1d54b30b5dd6d4a8c8542e8d7edf93b5d",
"type": "github"
},
"original": {
@@ -1626,11 +1626,11 @@
"rust-analyzer-src": {
"flake": false,
"locked": {
"lastModified": 1759601486,
"narHash": "sha256-ZywfLIFtRr907us1tONwUJLeg3ssO4D01XBFHx7RdAo=",
"lastModified": 1759301569,
"narHash": "sha256-7StxDed3v2fAWLkl+Hse9FlpjT7Dk7Cn/4vxTFyEhIg=",
"owner": "rust-lang",
"repo": "rust-analyzer",
"rev": "4ae99f0150c94f4bdf7192b4447f512ece3546fd",
"rev": "472037b789cf593172d6adf3b8d9f7a429f6cd9b",
"type": "github"
},
"original": {
@@ -1648,11 +1648,11 @@
]
},
"locked": {
"lastModified": 1759458749,
"narHash": "sha256-WKnbJnm1B2+TO2ZUudgS39EzecQeLl4/bnRtd3y46LI=",
"lastModified": 1759286284,
"narHash": "sha256-JLdGGc4XDutzSD1L65Ni6Ye+oTm8kWfm0KTPMcyl7Y4=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "bbc3a8ae797d1700e57a4f4bcc4e79af727d4138",
"rev": "f6f2da475176bb7cff51faae8b3fe879cd393545",
"type": "github"
},
"original": {
@@ -1923,11 +1923,11 @@
]
},
"locked": {
"lastModified": 1759590499,
"narHash": "sha256-EBToRzqe5WMz4DQyxOp9/CP+rWjdaZ2EUwbItfNf3VI=",
"lastModified": 1759180079,
"narHash": "sha256-5hqTGqAKcLEumY3tqOtHK17CA6RkzS1I0EGKfuoyb58=",
"ref": "refs/heads/main",
"rev": "6e606c8bfa6a88209488790388b1005bc489fa66",
"revCount": 136,
"rev": "d4a254b38c7ac2b99931220d767610adfa3a57fe",
"revCount": 135,
"type": "git",
"url": "https://git.sr.ht/~canasta/zen-browser-flake"
},

View File

@@ -216,7 +216,7 @@
flags = "--performance";
};
tailscale = {
enable = false;
enable = true;
};
udisks = {
enable = true;

View File

@@ -1,5 +1,4 @@
{ config, ... }:
{
{config, ...}: {
server = {
enable = true;
email = "adam@cnst.dev";
@@ -9,7 +8,7 @@
uid = 994;
gid = 993;
traefik = {
nginx = {
enable = true;
};
gitea = {
@@ -43,7 +42,7 @@
enable = true;
};
jellyfin = {
enable = true;
enable = false;
cloudflared = {
tunnelId = "234811e2-bc86-44b2-9abd-493686e25704";
credentialsFile = config.age.secrets.jellyfinCloudflared.path;
@@ -61,7 +60,7 @@
};
};
www = {
enable = true;
enable = false;
url = "cnst.dev";
cloudflared = {
tunnelId = "e5076186-efb7-405a-998c-6155af7fb221";
@@ -93,14 +92,14 @@
enable = true;
gluetun.enable = true;
qbittorrent = {
enable = true;
enable = false;
port = 8387;
};
slskd = {
enable = true;
};
pihole = {
enable = true;
enable = false;
port = 8053;
};
};

View File

@@ -141,7 +141,7 @@
./server/keepalived
./server/gitea
./server/postgres
./server/traefik
./server/nginx
./server/www
./server/authentik
];

View File

@@ -3,17 +3,16 @@
config,
lib,
...
}:
let
inherit (lib)
}: let
inherit
(lib)
mkIf
mkOption
mkMerge
types
;
cfg = config.nixos.programs.pkgs;
in
{
in {
options = {
nixos.programs.pkgs = {
enable = mkOption {
@@ -51,8 +50,7 @@ in
};
config = mkIf cfg.enable {
environment.systemPackages =
with pkgs;
environment.systemPackages = with pkgs;
mkMerge [
[
pciutils
@@ -114,6 +112,8 @@ in
helix
zfs
zfstools
cron
acme-sh
])
(mkIf cfg.dev.enable [

View File

@@ -70,7 +70,7 @@ in {
secrets = {
cloudflareFirewallApiKey.file = "${self}/secrets/cloudflareFirewallApiKey.age";
cloudflareDnsApiToken.file = "${self}/secrets/cloudflareDnsApiToken.age";
cloudflareDnsCredentials.file = "${self}/secrets/cloudflareDnsCredentials.age";
# cloudflareDnsCredentials.file = "${self}/secrets/cloudflareDnsCredentials.age";
wgCredentials.file = "${self}/secrets/wgCredentials.age";
wgSobotkaPrivateKey.file = "${self}/secrets/wgSobotkaPrivateKey.age";
gluetunEnvironment.file = "${self}/secrets/gluetunEnvironment.age";

View File

@@ -4,13 +4,11 @@
pkgs,
self,
...
}:
let
}: let
unit = "authentik";
cfg = config.server.${unit};
srv = config.server;
in
{
in {
options.server.${unit} = {
enable = lib.mkEnableOption {
description = "Enable ${unit}";
@@ -106,14 +104,7 @@ in
"X-authentik-username"
"X-authentik-groups"
"X-authentik-email"
# "X-authentik-name"
# "X-authentik-uid"
"X-authentik-jwt"
# "X-authentik-meta-jwks"
# "X-authentik-meta-outpost"
# "X-authentik-meta-provider"
# "X-authentik-meta-app"
# "X-authentik-meta-version"
];
timeout = "10s";
};
@@ -130,7 +121,7 @@ in
routers = {
auth = {
entryPoints = [ "websecure" ];
entryPoints = ["websecure"];
rule = "Host(`${cfg.url}`) || HostRegexp(`{subdomain:[a-z0-9]+}.${srv.www.url}`) && PathPrefix(`/outpost.goauthentik.io/`)";
service = "auth";
tls.certResolver = "letsencrypt";

View File

@@ -17,14 +17,14 @@ in {
default = "";
type = types.str;
description = ''
Email name to be used to access the server services via Caddy reverse proxy
Email name to be used to access the server services via NGINX reverse proxy
'';
};
domain = mkOption {
default = "";
type = types.str;
description = ''
Domain name to be used to access the server services via Caddy reverse proxy
Domain name to be used to access the server services via NGINX reverse proxy
'';
};
user = lib.mkOption {
@@ -65,6 +65,11 @@ in {
};
config = lib.mkIf cfg.enable {
_module.args = {
myLib = import ./lib.nix {
inherit lib config pkgs;
};
};
users = {
groups.${cfg.group} = {
gid = cfg.gid;
@@ -93,7 +98,7 @@ in {
"render"
"input"
"authentik"
"traefik"
"nginx"
];
};
};

View File

@@ -58,14 +58,14 @@ in {
jails =
lib.attrsets.mapAttrs (name: value: {
settings = {
bantime = "24h";
findtime = "10m";
bantime = "168h";
findtime = "30m";
enabled = true;
backend = "systemd";
journalmatch = "_SYSTEMD_UNIT=${value.serviceName}.service";
port = "http,https";
filter = "${name}";
maxretry = 3;
maxretry = value.maxRetry or 5;
action = "cloudflare-token-agenix";
};
})

View File

@@ -99,23 +99,6 @@ in {
};
};
services.traefik = {
dynamicConfigOptions = {
http = {
services.gitea.loadBalancer.servers = [{url = "http://127.0.0.1:5003";}];
routers = {
gitea = {
entryPoints = ["websecure"];
rule = "Host(`${cfg.url}`)";
service = "gitea";
tls.certResolver = "letsencrypt";
# middlewares = ["authentik"];
};
};
};
};
};
server.postgresql.databases = [
{
database = "gitea";

View File

@@ -212,25 +212,6 @@ in {
}
];
};
traefik = {
dynamicConfigOptions = {
http = {
services.homepage.loadBalancer.servers = [
{url = "http://127.0.0.1:${toString config.services.${unit}.listenPort}";}
];
routers = {
homepage = {
entryPoints = ["websecure"];
rule = "Host(`cnix.dev`)";
service = "homepage";
tls.certResolver = "letsencrypt";
# middlewares = ["authentik"];
};
};
};
};
};
};
};
}

View File

@@ -2,23 +2,38 @@
config,
lib,
pkgs,
self,
...
}: let
service = "jellyfin";
cfg = config.server.${service};
unit = "jellyfin";
cfg = config.server.${unit};
srv = config.server;
in {
options.server.${service} = {
options.server.${unit} = {
enable = lib.mkEnableOption {
description = "Enable ${service}";
description = "Enable ${unit}";
};
configDir = lib.mkOption {
type = lib.types.str;
default = "/var/lib/${service}";
default = "/var/lib/${unit}";
};
url = lib.mkOption {
type = lib.types.str;
default = "jellyfin.${srv.domain}";
default = "jellyfin.${srv.www.url}";
};
cloudflared = {
credentialsFile = lib.mkOption {
type = lib.types.str;
example = lib.literalExpression ''
pkgs.writeText "cloudflare-credentials.json" '''
{"AccountTag":"secret"."TunnelSecret":"secret","TunnelID":"secret"}
'''
'';
};
tunnelId = lib.mkOption {
type = lib.types.str;
example = "00000000-0000-0000-0000-000000000000";
};
};
homepage.name = lib.mkOption {
type = lib.types.str;
@@ -38,17 +53,62 @@ in {
};
};
config = lib.mkIf cfg.enable {
services.${service} = {
enable = true;
user = srv.user;
group = srv.group;
age.secrets = {
jellyfinCloudflared = {
file = "${self}/secrets/jellyfinCloudflared.age";
owner = "${srv.user}";
group = "${srv.group}";
mode = "0400";
};
};
services = {
cloudflared = {
enable = true;
tunnels.${cfg.cloudflared.tunnelId} = {
credentialsFile = cfg.cloudflared.credentialsFile;
default = "http_status:404";
ingress."${cfg.url}".service = "http://127.0.0.1:8096";
};
};
${unit} = {
enable = true;
user = srv.user;
group = srv.group;
};
};
environment.systemPackages = with pkgs; [
jellyfin-ffmpeg
];
services.traefik = {
dynamicConfigOptions = {
http = {
middlewares = {
secureHeaders = {
headers = {
stsSeconds = 31536000;
forceSTSHeader = true;
stsIncludeSubdomains = true;
stsPreload = true;
browserXssFilter = true;
frameDeny = true;
referrerPolicy = "no-referrer";
contentTypeNosniff = true;
customResponseHeaders = {
"Content-Security-Policy" = "default-src 'self'; img-src 'self' data:; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';";
};
};
};
ratelimit = {
rateLimit = {
average = 10;
burst = 20;
};
};
};
services.jellyfin.loadBalancer.servers = [{url = "http://127.0.0.1:8096";}];
routers = {
jellyfin = {
@@ -56,7 +116,7 @@ in {
rule = "Host(`${cfg.url}`)";
service = "jellyfin";
tls.certResolver = "letsencrypt";
# middlewares = ["authentik"];
middlewares = ["authentik" "secureHeaders" "ratelimit"];
};
};
};

148
modules/server/lib.nix Normal file
View File

@@ -0,0 +1,148 @@
# from @jtojnar
{
config,
lib,
pkgs,
...
}: {
mkVirtualHost = {
path ? null,
config ? "",
acme ? null,
redirect ? null,
...
} @ args:
(
if lib.isString acme
then {
useACMEHost = acme;
forceSSL = true;
}
else {}
)
// (
if lib.isBool acme
then {
enableACME = acme;
forceSSL = true;
}
else {}
)
// (
if redirect != null
then {
globalRedirect = redirect;
}
else {}
)
// (
if path != null
then {
root = "/var/www/" + path;
}
else {}
)
// {
extraConfig = config;
}
// builtins.removeAttrs args [
"path"
"config"
"acme"
"redirect"
];
mkPhpPool = {
user,
debug ? false,
settings ? {},
...
} @ args:
{
inherit user;
settings =
{
"listen.owner" = "nginx";
"listen.group" = "root";
"pm" = "dynamic";
"pm.max_children" = 5;
"pm.start_servers" = 2;
"pm.min_spare_servers" = 1;
"pm.max_spare_servers" = 3;
}
// (
lib.optionalAttrs debug {
# log worker's stdout, but this has a performance hit
"catch_workers_output" = true;
}
// settings
);
}
// builtins.removeAttrs args [
"user"
"debug"
"settings"
];
enablePHP = sockName: ''
fastcgi_pass unix:${config.services.phpfpm.pools.${sockName}.socket};
include ${config.services.nginx.package}/conf/fastcgi.conf;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
'';
/*
Adds extra options to ssh key that will only allow it to be used for rsync.
See sshd(8) manual page for details.
*/
restrictToRsync = directory: key: ''command="${pkgs.rrsync}/bin/rrsync -wo ${directory}",restrict ${key}'';
/*
Emulate systemd credentials.
Those will only be available to the user the service is running under,
not being aware of dropped euid.
http://systemd.io/CREDENTIALS/
*/
emulateCredentials = let
parseCredential = credential: let
matches = builtins.match "(.+):(.+)" credential;
in
assert lib.assertMsg (matches != null) "A credential needs to match id:value format"; {
id = builtins.elemAt matches 0;
value = builtins.elemAt matches 1;
};
parseCredentials = credentials:
builtins.map parseCredential (
if builtins.isList credentials
then credentials
else lib.splitString "," credentials
);
in
serviceConfig:
lib.mkMerge [
(builtins.removeAttrs serviceConfig [
"SetCredential"
"LoadCredential"
])
{
Environment = [
"CREDENTIALS_DIRECTORY=${
pkgs.runCommand "credentials" {} ''
mkdir "$out"
${lib.concatMapStringsSep "\n" ({
id,
value,
}: ''ln -s "${value}" "$out/${id}"'') (
parseCredentials serviceConfig.LoadCredential or []
)}
${lib.concatMapStringsSep "\n" ({
id,
value,
}: ''echo -n "${value}" > "$out/${id}"'') (
parseCredentials serviceConfig.SetCredential or []
)}
''
}"
];
}
];
}

View File

@@ -0,0 +1,79 @@
{
lib,
config,
pkgs,
self,
myLib,
...
}: let
inherit (myLib) mkVirtualHost;
inherit (lib) mkEnableOption mkIf types;
unit = "nginx";
cfg = config.server.nginx;
srv = config.server;
in {
options.server.nginx = {
enable = mkEnableOption "Enable global NGINX reverse proxy with ACME";
};
config = mkIf cfg.enable {
age.secrets = {
nginxEnv = {
file = "${self}/secrets/nginxEnv.age";
};
};
networking.firewall.allowedTCPPorts = [80 443];
security = {
acme = {
acceptTerms = true;
defaults.email = config.server.email;
certs.${srv.domain} = {
reloadServices = ["nginx.service"];
domain = "${srv.domain}";
extraDomainNames = ["*.${srv.domain}"];
dnsProvider = "cloudflare";
dnsPropagationCheck = true;
group = config.services.nginx.group;
environmentFile = config.age.secrets.nginxEnv.path;
};
};
dhparams = {
enable = true;
params.nginx = {};
};
};
services.nginx = {
enable = true;
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
resolver.addresses = config.networking.nameservers;
sslDhparam = config.security.dhparams.params.nginx.path;
appendHttpConfig = ''
proxy_headers_hash_max_size 512;
proxy_headers_hash_bucket_size 128;
'';
virtualHosts = let
labDomain = "cnix.dev";
labCert = {
useACMEHost = "cnix.dev";
forceSSL = true;
};
in {
# proxies on domain with https, only accessible within local network
"${labDomain}" =
labCert
// {
locations."/".proxyPass = "http://127.0.0.1:${toString config.services.homepage-dashboard.listenPort}";
};
};
};
users.users.nginx.extraGroups = ["acme"];
};
}

View File

@@ -34,7 +34,7 @@ in {
};
port = lib.mkOption {
type = lib.types.int;
default = 8080;
default = 8387;
description = "The port to host qBittorrent on.";
};
homepage.name = lib.mkOption {
@@ -143,62 +143,6 @@ in {
];
};
services.traefik = lib.mkMerge [
(lib.mkIf cfg.pihole.enable {
dynamicConfigOptions = {
http = {
services = {
pihole.loadBalancer.servers = [{url = "http://localhost:${toString cfg.pihole.port}";}];
};
routers = {
pihole = {
entryPoints = ["websecure"];
rule = "Host(`${cfg.pihole.url}`)";
service = "pihole";
tls.certResolver = "letsencrypt";
};
};
};
};
})
(lib.mkIf cfg.qbittorrent.enable {
dynamicConfigOptions = {
http = {
services = {
qbittorrent.loadBalancer.servers = [{url = "http://localhost:${toString cfg.qbittorrent.port}";}];
};
routers = {
qbittorrent = {
entryPoints = ["websecure"];
rule = "Host(`${cfg.qbittorrent.url}`)";
service = "qbittorrent";
tls.certResolver = "letsencrypt";
};
};
};
};
})
(lib.mkIf cfg.slskd.enable {
dynamicConfigOptions = {
http = {
services = {
slskd.loadBalancer.servers = [{url = "http://localhost:${toString cfg.slskd.port}";}];
};
routers = {
slskd = {
entryPoints = ["websecure"];
rule = "Host(`${cfg.slskd.url}`)";
service = "slskd";
tls.certResolver = "letsencrypt";
};
};
};
};
})
];
virtualisation.oci-containers.containers = lib.mkMerge [
(lib.mkIf cfg.gluetun.enable {
gluetun = {
@@ -206,7 +150,7 @@ in {
ports = [
"8388:8388"
"58846:58846"
"8080:8080"
"8387:8387"
"5030:5030"
"5031:5031"
"50300:50300"
@@ -235,7 +179,7 @@ in {
autoStart = true;
dependsOn = ["gluetun"];
ports = [
"8080:8080"
"8387:8387"
"58846:58846"
];
extraOptions = [

View File

@@ -43,15 +43,16 @@ in {
group = srv.group;
};
services.traefik = {
# staticConfigOptions.entryPoints.${unit}.address = "127.0.0.1:8989";
dynamicConfigOptions = {
http = {
services.sonarr.loadBalancer.servers = [{url = "http://127.0.0.1:8989";}];
# services.sonarr.loadBalancer.servers = [{url = "http://127.0.0.1:8989";}];
routers = {
sonarr = {
entryPoints = ["websecure"];
rule = "Host(`${cfg.url}`)";
service = "sonarr";
tls.certResolver = "letsencrypt";
# tls.certResolver = "letsencrypt";
# middlewares = ["authentik"];
};
};

View File

@@ -1,100 +0,0 @@
{
lib,
config,
pkgs,
self,
...
}: let
inherit (lib) mkEnableOption mkIf types;
cfg = config.server.traefik;
getCloudflareCredentials = hostname:
if hostname == "ziggy"
then config.age.secrets.cloudflareDnsCredentialsZiggy.path
else if hostname == "sobotka"
then config.age.secrets.cloudflareDnsCredentials.path
else throw "Unknown hostname: ${hostname}";
in {
options.server.traefik = {
enable = mkEnableOption "Enable global Traefik reverse proxy with ACME";
};
config = mkIf cfg.enable {
age.secrets.traefikEnv = {
file = "${self}/secrets/traefikEnv.age";
mode = "640";
owner = "root";
group = "traefik";
};
systemd.services.traefik = {
serviceConfig = {
EnvironmentFile = [config.age.secrets.traefikEnv.path];
};
};
networking.firewall.allowedTCPPorts = [80 443];
services = {
tailscale.permitCertUid = "traefik";
traefik = {
enable = true;
staticConfigOptions = {
log = {
level = "DEBUG";
};
tracing = {};
api = {
dashboard = true;
};
certificatesResolvers = {
tailscale.tailscale = {};
letsencrypt = {
acme = {
email = "adam@cnst.dev";
storage = "/var/lib/traefik/cert.json";
dnsChallenge = {
provider = "cloudflare";
resolvers = [
"1.1.1.1:53"
"1.0.0.1:53"
];
};
};
};
};
entryPoints = {
redis = {
address = "0.0.0.0:6381";
};
postgres = {
address = "0.0.0.0:5433";
};
web = {
address = "0.0.0.0:80";
http.redirections.entryPoint = {
to = "websecure";
scheme = "https";
permanent = true;
};
};
websecure = {
address = "0.0.0.0:443";
http.tls = {
certResolver = "letsencrypt";
domains = [
{
main = "cnix.dev";
sans = ["*.cnix.dev"];
}
];
};
};
};
};
};
};
};
}

View File

@@ -4,18 +4,11 @@
pkgs,
self,
...
}:
let
inherit (lib)
mkOption
mkEnableOption
mkIf
types
;
}: let
inherit (lib) mkOption mkEnableOption mkIf types;
cfg = config.server.www;
srv = config.server;
in
{
in {
options.server.www = {
enable = mkEnableOption {
description = "Enable personal website";
@@ -121,18 +114,5 @@ in
Disallow: /
'';
};
services.traefik.dynamicConfigOptions.http = {
routers.webfinger = {
entryPoints = [ "websecure" ];
rule = "Host(`${cfg.url}`) && Path(`/.well-known/webfinger`)";
service = "webfinger";
tls.certResolver = "letsencrypt";
};
services.webfinger.loadBalancer.servers = [
{ url = "http://127.0.0.1:8283"; }
];
};
};
}

View File

@@ -0,0 +1,11 @@
age-encryption.org/v1
-> ssh-ed25519 t9iOEg dULaZVrpkeN1HqwM+HSU46XJjQznBOxa+wUDSSciK1w
FxqlulfViojLLoskKu56Utiq57rkDC6TocoaFQOgahc
-> ssh-ed25519 KUYMFA QYnb24Av6Vy17Lb5gC6dzQszOxa5bRP2PgFetmqhfCA
MaIes8V0NkyTAzFzbRuCMzMLwhYljYHwhXPKEZEdlC4
-> ssh-ed25519 76RhUQ NLoyNp/z5MXE3Hrmv7CCDYB1X8R1OORm2MZVMbgNDQs
6U8r3wpXNtQdkIH+lo7cDrnjPw9B6eF/jMeb+iW9T1I
-> ssh-ed25519 Jf8sqw GOWsvhSzrHJGJFOgsXr+O1jq7jnjyzKc82Mu7ntrI2Q
P3n32btGFtUxB28/a0iz6lBTM6UP3EYUrq0y8BR49IM
--- geE2uS2TMspihaNwgzH4FQKYoUFFRhjTS6V7F/cdTE0
%<25>^<5E>E3򿈾<33><F2BF88BE><EFBFBD>gg<67><67>ٸk<D9B8><6B>;<3B>lE+b<>x<EFBFBD>Ҝ-<2D>X<>Et'&^<5E>=c<><63>9<EFBFBD>v*<2A>

12
secrets/nginxEnv.age Normal file
View File

@@ -0,0 +1,12 @@
age-encryption.org/v1
-> ssh-ed25519 t9iOEg SCmn/7gQOD3fRn0PKPXxNBDKNSqUcnejG8tPwjoNT1I
vd57xXCQ16PPPMlNysw6BWSIP/EgB3HrWlesBiQUVA0
-> ssh-ed25519 KUYMFA WVn1OhFDxMMEHFa1yHpBmWskbcRgHyBiDWZjPv8NfX8
8BCp/iUFkRsAGnc+0MEfpRXo1/Xla4WO3qYZMSl7LGw
-> ssh-ed25519 76RhUQ ZfdS1EWtBOwd7+hVnJ/JqxUCDTYmfEs1OwyzXajFMmg
eE0ahMgW76RFu9y9Z+PE6IzaLX3ydhhJvjk5vu2EgXo
-> ssh-ed25519 Jf8sqw Pr/LkT5RQysShzjqEZlXFRHim3WpAav04c/GGftDTiA
TWWRURLPnkpsxxSdSQem9sAoUoLt5wQe0CYl1xl1RaA
--- cfGjcdOvwxLDlANhDe44U5JXGAyRYPZMVtC48PuhLNo
<EFBFBD>Zyr<>#*K<><4B><EFBFBD><EFBFBD> <0B><1F>
$<24><>FB<46>$<24>^<5E>BT<42><54>#D<>v<EFBFBD><76>3<EFBFBD><13><f<>dG$<24><><EFBFBD><~<7E><10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>m<EFBFBD><6D>8^<1A><><EFBFBD>\# Z<>-8<><38><EFBFBD>D<EFBFBD>dM<64><4D>

View File

@@ -58,9 +58,10 @@ in {
"sobotkaPihole.age".publicKeys = kima ++ sobotka;
"slskd.age".publicKeys = kima ++ sobotka;
"authentikEnv.age".publicKeys = kima ++ sobotka;
"traefikEnv.age".publicKeys = kima ++ sobotka;
"nginxEnv.age".publicKeys = kima ++ sobotka;
"wwwCloudflared.age".publicKeys = kima ++ sobotka;
"authentikCloudflared.age".publicKeys = kima ++ sobotka;
"jellyfinCloudflared.age".publicKeys = kima ++ sobotka;
# Ziggy-specific
"cloudflareDnsCredentialsZiggy.age".publicKeys = kima ++ ziggy;

Binary file not shown.

View File

@@ -11,7 +11,7 @@
enable = true;
};
chromium = {
enable = false;
enable = true;
};
discord = {
enable = true;