Compare commits

...

40 commits

Author SHA1 Message Date
goeranh
03795a46a7
allow all local connections 2026-05-03 14:19:43 +02:00
goeranh
66d6857710
use nftables on all haproxy host for better blacklisting 2026-05-02 00:29:06 +02:00
goeranh
d0a8fb0c09
enable nginx access logs for now 2026-05-01 23:54:32 +02:00
goeranh
855cd7bd9b
fix build failure because of new upstream release 2026-05-01 23:16:24 +02:00
goeranh
1e5cd75652
set http mode for port 80 2026-04-30 17:59:32 +02:00
goeranh
b2ac4a6ac1
haproxy acme rule ordering 2026-04-30 17:50:22 +02:00
goeranh
590f42d5d9
enable proxy protocol for plone backends 2026-04-29 18:42:20 +02:00
goeranh
ed10898adb
flake.lock: Update
Flake lock file updates:

• Updated input 'authentik':
    'github:nix-community/authentik-nix/7e4730351fb6df479c46a1bf7e23d46a0b0c5d46?narHash=sha256-hcstQ1Z9aQSJM3AVCLb0/OPTicbME9nhP01GiPrOjZM%3D' (2026-03-07)
  → 'github:nix-community/authentik-nix/4370b561c8bafb59773ce3a518506bcf1161dbdb?narHash=sha256-JvvWVbXJYSY8qOReMbAOD4lxcN2cjKV6lg/jLz8CEuY%3D' (2026-04-13)
• Updated input 'authentik/authentik-src':
    'github:goauthentik/authentik/0dccbd4193c45c581e9fb7cd89df0c1487510f1f?narHash=sha256-0Vpf1hj9C8r%2BrhrCgwoNazpQ%2BmwgjdjDhuoKCxYQFWw%3D' (2026-03-03)
  → 'github:goauthentik/authentik/5249546862986202b901c2afd860992ec48c6ef6?narHash=sha256-Xq7JGI/8ppIydIuWd9KRJKUrh7UpeniwvZ4NAtXbYJ4%3D' (2026-04-07)
• Updated input 'disko':
    'github:nix-community/disko/7b9f7f88ab3b339f8142dc246445abb3c370d3d3?narHash=sha256-khlHllTsovXgT2GZ0WxT4%2BRvuMjNeR5OW0UYeEHPYQo%3D' (2026-03-09)
  → 'github:nix-community/disko/32f4236bfc141ae930b5ba2fb604f561fed5219d?narHash=sha256-gC9Cp5ibBmGD5awCA9z7xy6MW6iJufhazTYJOiGlCUI%3D' (2026-04-19)
• Updated input 'mailserver':
    'git+https://gitlab.com/simple-nixos-mailserver/nixos-mailserver?ref=nixos-25.11&rev=9cdd6869e513df8153db4b920c8f15d394e150f7' (2026-03-12)
  → 'git+https://gitlab.com/simple-nixos-mailserver/nixos-mailserver?ref=nixos-25.11&rev=25e6dbb8fca3b6e779c5a46fd03bd760b2165bb5' (2026-03-19)
• Updated input 'mailserver/flake-compat':
    'github:edolstra/flake-compat/f387cd2afec9419c8ee37694406ca490c3f34ee5?narHash=sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4%3D' (2025-10-27)
  → 'github:edolstra/flake-compat/5edf11c44bc78a0d334f6334cdaf7d60d732daab?narHash=sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns%3D' (2025-12-29)
• Updated input 'mailserver/git-hooks':
    'github:cachix/git-hooks.nix/7275fa67fbbb75891c16d9dee7d88e58aea2d761?narHash=sha256-YG19IyrTdnVn0l3DvcUYm85u3PaqBt6tI6VvolcuHnA%3D' (2025-11-16)
  → 'github:cachix/git-hooks.nix/8baab586afc9c9b57645a734c820e4ac0a604af9?narHash=sha256-JDqZMgxUTCq85ObSaFw0HhE%2BlvdOre1lx9iI6vYyOEs%3D' (2026-03-07)
• Updated input 'mailserver/nixpkgs':
    'github:NixOS/nixpkgs/a320ce8e6e2cc6b4397eef214d202a50a4583829?narHash=sha256-6zddwDs2n%2Bn01l%2B1TG6PlyokDdXzu/oBmEejcH5L5%2BA%3D' (2025-11-24)
  → 'github:NixOS/nixpkgs/826430a188181a750ffa5948daff334039c5d741?narHash=sha256-JW2/QPyCVzmouqEp1H9kNa8JXd7xEhlam9sy3TYfhDY%3D' (2026-03-18)
• Updated input 'nixpkgs':
    'github:nixos/nixpkgs/0590cd39f728e129122770c029970378a79d076a?narHash=sha256-BHoB/XpbqoZkVYZCfXJXfkR%2BGXFqwb/4zbWnOr2cRcU%3D' (2026-03-11)
  → 'github:nixos/nixpkgs/10e7ad5bbcb421fe07e3a4ad53a634b0cd57ffac?narHash=sha256-vl3dkhlE5gzsItuHoEMVe%2BDlonsK%2B0836LIRDnm6MXQ%3D' (2026-04-21)
• Updated input 'sops':
    'github:Mic92/sops-nix/d1ff3b1034d5bab5d7d8086a7803c5a5968cd784?narHash=sha256-M3zEnq9OElB7zqc%2BmjgPlByPm1O5t2fbUrH3t/Hm5Ag%3D' (2026-03-09)
  → 'github:Mic92/sops-nix/bef289e2248991f7afeb95965c82fbcd8ff72598?narHash=sha256-DRFGPfFV6hbrfO9a1PH1FkCi7qR5FgjSqsQGGvk1rdI%3D' (2026-04-21)
2026-04-24 14:42:39 +02:00
goeranh
c0c528ae29
geoip haproxy 2026-04-21 11:35:06 +02:00
goeranh
c89b6e7ee9
accept accept v6proxy proxy protocol 2026-04-21 11:34:31 +02:00
goeranh
1ba340e2a4
process metrics 2026-04-21 11:34:10 +02:00
goeranh
6ea0361692
send proxy protocol from hetzner 2026-04-21 09:06:13 +02:00
goeranh
3c186a9e56 Merge pull request 'monitoring' (#8) from monitoring into master
Reviewed-on: https://codeberg.org/stura-htw-dresden/stura-infra/pulls/8
2026-04-20 14:29:19 +02:00
goeranh
c31063ca56
purge logs and metrics after 4 weeks 2026-04-20 14:28:13 +02:00
goeranh
9a5716f2df
increase max series for queries 2026-04-20 14:10:33 +02:00
goeranh
e1530c606f
use extra input sink options 2026-04-20 13:53:12 +02:00
goeranh
53c592abd9
add extra inputs option for the loki and mimir sinks 2026-04-20 13:52:57 +02:00
goeranh
93e27dd3e5
receive proxmox logs 2026-04-20 13:07:21 +02:00
goeranh
dd2aa96e25
fix mimir 2026-04-20 13:07:13 +02:00
goeranh
fd02a136ef
scrape haproxy metrics 2026-04-20 13:06:04 +02:00
goeranh
e7cba90a45
fix vector settings 2026-04-20 12:10:18 +02:00
goeranh
e9fe620fa9
increase mimir and loki rate limits 2026-04-20 12:01:36 +02:00
goeranh
ef8607e38e
include monitoring module per default 2026-04-20 11:55:49 +02:00
goeranh
5ef710f8f2
dont generate domains, doesnt work for mon.adm.htw for example 2026-04-20 11:52:40 +02:00
goeranh
d435d8d487
use three letter domains 2026-04-20 11:52:26 +02:00
goeranh
9beef4e013
use recommended proxy settings 2026-04-20 11:40:07 +02:00
goeranh
641feb1b84
monitoring host# 2026-04-20 11:40:07 +02:00
goeranh
8c358daf56 Merge pull request 'proxy-protocol' (#7) from proxy-protocol into master
Reviewed-on: https://codeberg.org/stura-htw-dresden/stura-infra/pulls/7
2026-04-20 10:28:37 +02:00
goeranh
334c977988
enable proxy protocol for redmine 2026-04-20 10:26:54 +02:00
goeranh
29cff6eee8
enable proxy protocol for wiki 2026-04-20 10:26:46 +02:00
goeranh
f91ac73b72
enable proxy protocol in nextcloud 2026-04-20 10:26:33 +02:00
goeranh
5b2eb482df
formatting in proxy 2026-04-20 10:24:30 +02:00
goeranh
582822cd5b
remove explicit proxy, its in this flake 2026-04-20 09:45:47 +02:00
goeranh
279e106427
fix cloud duplicate 2026-04-20 09:17:36 +02:00
goeranh
a96f976be1
does not work on port 80 with acme 2026-04-20 09:02:20 +02:00
goeranh
9041fe3d69
conditionally send proxy protocol 2026-04-20 08:56:40 +02:00
goeranh
fe6650622f
haproxy maxconn 2026-04-10 15:38:30 +02:00
oxce
ca8c213e74 Änderung der adresse vom smtp mailserver 2026-03-27 18:11:47 +01:00
goeranh
9e3fa025cd
redirect bbb 2026-03-20 17:09:01 +01:00
goeranh
5bed1bbba1
remove git hooks 2026-03-20 16:24:09 +01:00
10 changed files with 849 additions and 205 deletions

View file

@ -1 +0,0 @@
/nix/store/1w2s62i701n28sj08gn1445qr4v3vijp-pre-commit-config.json

122
flake.lock generated
View file

@ -15,11 +15,11 @@
"uv2nix": "uv2nix" "uv2nix": "uv2nix"
}, },
"locked": { "locked": {
"lastModified": 1772909021, "lastModified": 1776085803,
"narHash": "sha256-hcstQ1Z9aQSJM3AVCLb0/OPTicbME9nhP01GiPrOjZM=", "narHash": "sha256-JvvWVbXJYSY8qOReMbAOD4lxcN2cjKV6lg/jLz8CEuY=",
"owner": "nix-community", "owner": "nix-community",
"repo": "authentik-nix", "repo": "authentik-nix",
"rev": "7e4730351fb6df479c46a1bf7e23d46a0b0c5d46", "rev": "4370b561c8bafb59773ce3a518506bcf1161dbdb",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -47,16 +47,16 @@
"authentik-src": { "authentik-src": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1772567399, "lastModified": 1775573258,
"narHash": "sha256-0Vpf1hj9C8r+rhrCgwoNazpQ+mwgjdjDhuoKCxYQFWw=", "narHash": "sha256-Xq7JGI/8ppIydIuWd9KRJKUrh7UpeniwvZ4NAtXbYJ4=",
"owner": "goauthentik", "owner": "goauthentik",
"repo": "authentik", "repo": "authentik",
"rev": "0dccbd4193c45c581e9fb7cd89df0c1487510f1f", "rev": "5249546862986202b901c2afd860992ec48c6ef6",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "goauthentik", "owner": "goauthentik",
"ref": "version/2026.2.1", "ref": "version/2026.2.2",
"repo": "authentik", "repo": "authentik",
"type": "github" "type": "github"
} }
@ -84,11 +84,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1773025010, "lastModified": 1776613567,
"narHash": "sha256-khlHllTsovXgT2GZ0WxT4+RvuMjNeR5OW0UYeEHPYQo=", "narHash": "sha256-gC9Cp5ibBmGD5awCA9z7xy6MW6iJufhazTYJOiGlCUI=",
"owner": "nix-community", "owner": "nix-community",
"repo": "disko", "repo": "disko",
"rev": "7b9f7f88ab3b339f8142dc246445abb3c370d3d3", "rev": "32f4236bfc141ae930b5ba2fb604f561fed5219d",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -118,25 +118,9 @@
"locked": { "locked": {
"lastModified": 1767039857, "lastModified": 1767039857,
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
"owner": "NixOS",
"repo": "flake-compat",
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "flake-compat",
"type": "github"
}
},
"flake-compat_3": {
"flake": false,
"locked": {
"lastModified": 1761588595,
"narHash": "sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4=",
"owner": "edolstra", "owner": "edolstra",
"repo": "flake-compat", "repo": "flake-compat",
"rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5", "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -186,9 +170,13 @@
}, },
"git-hooks": { "git-hooks": {
"inputs": { "inputs": {
"flake-compat": "flake-compat_2", "flake-compat": [
"mailserver",
"flake-compat"
],
"gitignore": "gitignore", "gitignore": "gitignore",
"nixpkgs": [ "nixpkgs": [
"mailserver",
"nixpkgs" "nixpkgs"
] ]
}, },
@ -206,54 +194,7 @@
"type": "github" "type": "github"
} }
}, },
"git-hooks_2": {
"inputs": {
"flake-compat": [
"mailserver",
"flake-compat"
],
"gitignore": "gitignore_2",
"nixpkgs": [
"mailserver",
"nixpkgs"
]
},
"locked": {
"lastModified": 1763319842,
"narHash": "sha256-YG19IyrTdnVn0l3DvcUYm85u3PaqBt6tI6VvolcuHnA=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "7275fa67fbbb75891c16d9dee7d88e58aea2d761",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "git-hooks.nix",
"type": "github"
}
},
"gitignore": { "gitignore": {
"inputs": {
"nixpkgs": [
"git-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"gitignore_2": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
"mailserver", "mailserver",
@ -278,16 +219,16 @@
"mailserver": { "mailserver": {
"inputs": { "inputs": {
"blobs": "blobs", "blobs": "blobs",
"flake-compat": "flake-compat_3", "flake-compat": "flake-compat_2",
"git-hooks": "git-hooks_2", "git-hooks": "git-hooks",
"nixpkgs": "nixpkgs_2" "nixpkgs": "nixpkgs_2"
}, },
"locked": { "locked": {
"lastModified": 1773313890, "lastModified": 1773912645,
"narHash": "sha256-NXm/kOAk7HLziH1uWaUbNb9MhDS8yxFfQ8fMK5eN8/A=", "narHash": "sha256-QHzRqq6gh+t3F/QU9DkP7X63dDDcuIQmaDz12p7ANTg=",
"ref": "nixos-25.11", "ref": "nixos-25.11",
"rev": "9cdd6869e513df8153db4b920c8f15d394e150f7", "rev": "25e6dbb8fca3b6e779c5a46fd03bd760b2165bb5",
"revCount": 842, "revCount": 843,
"type": "git", "type": "git",
"url": "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver" "url": "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver"
}, },
@ -356,11 +297,11 @@
}, },
"nixpkgs_2": { "nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1764020296, "lastModified": 1773831496,
"narHash": "sha256-6zddwDs2n+n01l+1TG6PlyokDdXzu/oBmEejcH5L5+A=", "narHash": "sha256-JW2/QPyCVzmouqEp1H9kNa8JXd7xEhlam9sy3TYfhDY=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "a320ce8e6e2cc6b4397eef214d202a50a4583829", "rev": "826430a188181a750ffa5948daff334039c5d741",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -372,11 +313,11 @@
}, },
"nixpkgs_3": { "nixpkgs_3": {
"locked": { "locked": {
"lastModified": 1773222311, "lastModified": 1776734388,
"narHash": "sha256-BHoB/XpbqoZkVYZCfXJXfkR+GXFqwb/4zbWnOr2cRcU=", "narHash": "sha256-vl3dkhlE5gzsItuHoEMVe+DlonsK+0836LIRDnm6MXQ=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "0590cd39f728e129122770c029970378a79d076a", "rev": "10e7ad5bbcb421fe07e3a4ad53a634b0cd57ffac",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -440,7 +381,6 @@
"inputs": { "inputs": {
"authentik": "authentik", "authentik": "authentik",
"disko": "disko", "disko": "disko",
"git-hooks": "git-hooks",
"mailserver": "mailserver", "mailserver": "mailserver",
"nixpkgs": "nixpkgs_3", "nixpkgs": "nixpkgs_3",
"sops": "sops" "sops": "sops"
@ -453,11 +393,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1773096132, "lastModified": 1776771786,
"narHash": "sha256-M3zEnq9OElB7zqc+mjgPlByPm1O5t2fbUrH3t/Hm5Ag=", "narHash": "sha256-DRFGPfFV6hbrfO9a1PH1FkCi7qR5FgjSqsQGGvk1rdI=",
"owner": "Mic92", "owner": "Mic92",
"repo": "sops-nix", "repo": "sops-nix",
"rev": "d1ff3b1034d5bab5d7d8086a7803c5a5968cd784", "rev": "bef289e2248991f7afeb95965c82fbcd8ff72598",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -18,10 +18,6 @@
url = "github:nix-community/disko"; url = "github:nix-community/disko";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
git-hooks = {
url = "github:cachix/git-hooks.nix";
inputs.nixpkgs.follows = "nixpkgs";
};
}; };
outputs = outputs =
@ -32,7 +28,6 @@
mailserver, mailserver,
disko, disko,
sops, sops,
git-hooks,
}: }:
let let
sshkeys = [ sshkeys = [
@ -47,12 +42,6 @@
devShells.x86_64-linux.default = devShells.x86_64-linux.default =
let let
pkgs = nixpkgs.legacyPackages.x86_64-linux; pkgs = nixpkgs.legacyPackages.x86_64-linux;
pre-commit-check = git-hooks.lib.x86_64-linux.run {
src = ./.;
hooks = {
nixfmt-rfc-style.enable = true;
};
};
in in
pkgs.mkShell { pkgs.mkShell {
# Import GPG keys from keys directory # Import GPG keys from keys directory
@ -64,15 +53,11 @@
# Isolate sops GPG keys to .git/gnupg (optional) # Isolate sops GPG keys to .git/gnupg (optional)
# sopsCreateGPGHome = true; # sopsCreateGPGHome = true;
shellHook = ''
${pre-commit-check.shellHook}
'';
nativeBuildInputs = [ nativeBuildInputs = [
sops.packages.x86_64-linux.sops-import-keys-hook sops.packages.x86_64-linux.sops-import-keys-hook
]; ];
buildInputs = pre-commit-check.enabledPackages ++ [ buildInputs = [
pkgs.sops pkgs.sops
]; ];
}; };
@ -208,6 +193,7 @@
[ [
./hosts/${input} ./hosts/${input}
./default.nix ./default.nix
./modules/monitoring.nix
disko.nixosModules.disko disko.nixosModules.disko
authentik.nixosModules.default authentik.nixosModules.default
mailserver.nixosModules.mailserver mailserver.nixosModules.mailserver

View file

@ -0,0 +1,246 @@
{
config,
lib,
pkgs,
modulesPath,
...
}:
{
imports = [
"${modulesPath}/virtualisation/proxmox-lxc.nix"
];
networking = {
hostName = "monitoring";
fqdn = "monitoring.adm.htw.stura-dresden.de";
interfaces.eth0.ipv4.addresses = [
{
address = "141.56.51.20";
prefixLength = 24;
}
];
defaultGateway = {
address = "141.56.51.254";
interface = "eth0";
};
firewall = {
enable = true;
allowedTCPPorts = [
80
443
4317 # OTLP gRPC (Proxmox)
4318 # OTLP HTTP (Proxmox)
];
};
};
# Loki - Log aggregation system
services.loki = {
enable = true;
configuration = {
auth_enabled = false;
server = {
http_listen_port = 3100;
grpc_listen_port = 9096;
};
common = {
path_prefix = "/var/lib/loki";
storage.filesystem = {
chunks_directory = "/var/lib/loki/chunks";
rules_directory = "/var/lib/loki/rules";
};
replication_factor = 1;
ring = {
instance_addr = "127.0.0.1";
kvstore.store = "inmemory";
};
};
limits_config = {
ingestion_rate_mb = 32;
ingestion_burst_size_mb = 64;
per_stream_rate_limit = "32MB";
per_stream_rate_limit_burst = "64MB";
max_query_series = 100000;
retention_period = "672h"; # 28 days
};
compactor = {
retention_enabled = true;
working_directory = "/var/lib/loki/compactor";
delete_request_store = "filesystem";
};
schema_config = {
configs = [
{
from = "2024-01-01";
store = "tsdb";
object_store = "filesystem";
schema = "v13";
index = {
prefix = "index_";
period = "24h";
};
}
];
};
};
};
# Mimir - Scalable metrics storage
services.mimir = {
enable = true;
configuration = {
multitenancy_enabled = false;
memberlist = {
bind_addr = [ "0.0.0.0" ];
bind_port = 7946;
advertise_addr = "141.56.51.20";
join_members = [ "141.56.51.20:7946" ];
};
blocks_storage = {
backend = "filesystem";
filesystem = {
dir = "/var/lib/mimir/data";
};
};
compactor = {
data_dir = "/var/lib/mimir/compactor";
};
distributor = {
ring = {
kvstore.store = "memberlist";
};
};
ingester = {
ring = {
kvstore.store = "memberlist";
replication_factor = 1;
};
};
ruler_storage = {
backend = "filesystem";
filesystem = {
dir = "/var/lib/mimir/rules";
};
};
server = {
http_listen_port = 9009;
grpc_listen_port = 9095;
};
limits = {
ingestion_rate = 100000;
ingestion_burst_size = 200000;
max_global_series_per_user = 0;
compactor_blocks_retention_period = "672h"; # 28 days
};
store_gateway = {
sharding_ring = {
replication_factor = 1;
kvstore.store = "memberlist";
};
};
};
};
# Grafana - Visualization and dashboarding
services.grafana = {
enable = true;
settings = {
server = {
http_addr = "127.0.0.1";
http_port = 3000;
domain = "mon.adm.htw.stura-dresden.de";
root_url = "https://mon.adm.htw.stura-dresden.de";
};
security = {
admin_user = "admin";
admin_password = "$__file{/var/lib/grafana/admin_password}";
};
};
provision = {
enable = true;
datasources.settings.datasources = [
{
name = "Mimir";
type = "prometheus";
url = "http://localhost:9009/prometheus";
isDefault = true;
}
{
name = "Loki";
type = "loki";
url = "http://localhost:3100";
}
];
};
};
# Nginx reverse proxy with ACME certificates
services.nginx = {
enable = true;
virtualHosts."log.adm.htw.stura-dresden.de" = {
forceSSL = true;
enableACME = true;
locations."/" = {
proxyPass = "http://127.0.0.1:3100";
proxyWebsockets = true;
recommendedProxySettings = true;
};
};
virtualHosts."met.adm.htw.stura-dresden.de" = {
forceSSL = true;
enableACME = true;
locations."/" = {
proxyPass = "http://127.0.0.1:9009";
recommendedProxySettings = true;
};
};
virtualHosts."mon.adm.htw.stura-dresden.de" = {
forceSSL = true;
enableACME = true;
locations."/" = {
proxyPass = "http://127.0.0.1:3000";
proxyWebsockets = true;
recommendedProxySettings = true;
};
};
};
# Vector - receive OpenTelemetry data from Proxmox and forward to Loki/Mimir
services.vector.settings = {
sources.proxmox_otlp = {
type = "opentelemetry";
grpc.address = "0.0.0.0:4317";
http.address = "0.0.0.0:4318";
};
transforms.proxmox_normalize_logs = {
type = "remap";
inputs = [ "proxmox_otlp.logs" ];
source = ''
.host = string(.resources."host.name") ?? "proxmox"
.unit = string(.attributes."service.name") ?? "proxmox"
'';
};
transforms.proxmox_normalize_metrics = {
type = "remap";
inputs = [ "proxmox_otlp.metrics" ];
source = ''
.tags.host = string(.resources."host.name") ?? "proxmox"
'';
};
};
stura.monitoring = {
extraMetricInputs = [ "proxmox_normalize_metrics" ];
extraLogInputs = [ "proxmox_normalize_logs" ];
};
services.openssh.enable = true;
system.stateVersion = "25.11";
}

View file

@ -87,6 +87,11 @@
recommendedProxySettings = true; recommendedProxySettings = true;
recommendedTlsSettings = true; recommendedTlsSettings = true;
commonHttpConfig = ''
real_ip_header proxy_protocol;
set_real_ip_from 141.56.51.1/32;
'';
logError = '' logError = ''
/dev/null emerg /dev/null emerg
''; '';
@ -94,9 +99,21 @@
virtualHosts.${config.networking.fqdn} = { virtualHosts.${config.networking.fqdn} = {
forceSSL = true; forceSSL = true;
enableACME = true; enableACME = true;
extraConfig = '' listen = [
access_log off; {
''; port = 80;
addr = "0.0.0.0";
}
{
port = 443;
addr = "0.0.0.0";
ssl = true;
proxyProtocol = true;
}
];
# extraConfig = ''
# access_log off;
# '';
}; };
# virtualHosts."cloud.htw.stura-dresden.de" = { # virtualHosts."cloud.htw.stura-dresden.de" = {
# forceSSL = true; # forceSSL = true;

View file

@ -20,25 +20,99 @@
} }
]; ];
defaultGateway.address = "141.56.51.254"; defaultGateway.address = "141.56.51.254";
firewall = { firewall.enable = false;
allowedTCPPorts = [
22
53 # DNS
80
443
1005
2142
];
allowedUDPPorts = [
53 # DNS
123 # NTP
];
};
nftables = { nftables = {
enable = true; enable = true;
ruleset = ''
table inet filter {
set blacklist4 {
type ipv4_addr
flags interval
# manage: nft add element inet filter blacklist4 { 1.2.3.0/24 }
}
set blacklist6 {
type ipv6_addr
flags interval
# manage: nft add element inet filter blacklist6 { 2001:db8::/32 }
}
chain input {
type filter hook input priority filter; policy drop;
iif "lo" accept
ct state established,related accept
ip saddr 141.56.51.0/24 accept
ip saddr @blacklist4 drop
ip6 saddr @blacklist6 drop
# public ports
tcp dport { 80, 443, 1005, 2142 } accept
# lan-only: dns and ntp
ip saddr 141.56.51.0/24 tcp dport 53 accept
ip saddr 141.56.51.0/24 udp dport { 53, 123 } accept
}
chain forward {
type filter hook forward priority filter; policy drop;
}
chain output {
type filter hook output priority filter; policy accept;
}
}
'';
}; };
}; };
# Phase 1: Kernel-Level TCP Tuning
boot.kernel.sysctl = {
# Connection tracking - prevents "table full" errors
"net.netfilter.nf_conntrack_max" = 262144; # Conservative limit matching current kernel
"net.netfilter.nf_conntrack_buckets" = 65536; # 4:1 ratio
# Reduce connection tracking timeouts (defaults are excessive)
"net.netfilter.nf_conntrack_tcp_timeout_established" = 600; # 10 min (down from 5 days)
"net.netfilter.nf_conntrack_tcp_timeout_time_wait" = 30; # 30s
"net.netfilter.nf_conntrack_tcp_timeout_close_wait" = 15; # 15s
"net.netfilter.nf_conntrack_tcp_timeout_fin_wait" = 30; # 30s
# TCP connection handling
"net.core.somaxconn" = 65535; # Must be >= HAProxy maxconn
"net.core.netdev_max_backlog" = 16384;
"net.ipv4.tcp_max_syn_backlog" = 8192;
# TCP buffer auto-tuning (16MB max)
"net.ipv4.tcp_rmem" = "4096 87380 16777216";
"net.ipv4.tcp_wmem" = "4096 65536 16777216";
"net.core.rmem_max" = 16777216;
"net.core.wmem_max" = 16777216;
# TCP optimization
"net.ipv4.tcp_fin_timeout" = 15;
"net.ipv4.tcp_keepalive_time" = 300; # 5 min
"net.ipv4.tcp_keepalive_probes" = 3;
"net.ipv4.tcp_keepalive_intvl" = 15;
# TCP Fast Open
"net.ipv4.tcp_fastopen" = 3;
# BBR congestion control for better throughput
"net.ipv4.tcp_congestion_control" = "bbr";
"net.core.default_qdisc" = "fq";
# Ephemeral port range
"net.ipv4.ip_local_port_range" = "10000 65535";
# TIME_WAIT socket reuse
"net.ipv4.tcp_tw_reuse" = 1;
};
# Enable BBR kernel module
boot.kernelModules = [ "tcp_bbr" ];
# wenn instanzen in die flake migriert sind könnte man das autogenerierien # wenn instanzen in die flake migriert sind könnte man das autogenerierien
services = services =
let let
@ -52,96 +126,112 @@
domain = "docs.adm.htw.stura-dresden.de"; domain = "docs.adm.htw.stura-dresden.de";
httpPort = 8080; httpPort = 8080;
httpsPort = 8443; httpsPort = 8443;
sendProxy = false;
}; };
plone = { plone = {
dest = "141.56.51.3"; dest = "141.56.51.3";
domain = "stura.htw-dresden.de"; domain = "stura.htw-dresden.de";
httpPort = 80; httpPort = 80;
httpsPort = 443; httpsPort = 443;
sendProxy = true;
}; };
plone_alt = { plone_alt = {
dest = "141.56.51.3"; dest = "141.56.51.3";
domain = "www.stura.htw-dresden.de"; domain = "www.stura.htw-dresden.de";
httpPort = 80; httpPort = 80;
httpsPort = 443; httpsPort = 443;
sendProxy = true;
}; };
plone_neu = { plone_neu = {
dest = "141.56.51.3"; dest = "141.56.51.3";
domain = "www.htw.stura-dresden.de"; domain = "www.htw.stura-dresden.de";
httpPort = 80; httpPort = 80;
httpsPort = 443; httpsPort = 443;
sendProxy = true;
}; };
plone_neu2 = { plone_neu2 = {
dest = "141.56.51.3"; dest = "141.56.51.3";
domain = "htw.stura-dresden.de"; domain = "htw.stura-dresden.de";
httpPort = 80; httpPort = 80;
httpsPort = 443; httpsPort = 443;
sendProxy = true;
}; };
tix = { tix = {
dest = "141.56.51.220"; dest = "141.56.51.220";
domain = "tix.htw.stura-dresden.de"; domain = "tix.htw.stura-dresden.de";
httpPort = 80; httpPort = 80;
httpsPort = 443; httpsPort = 443;
sendProxy = false;
}; };
post = { post = {
dest = "141.56.51.56"; dest = "141.56.51.56";
domain = "post.htw.stura-dresden.de"; domain = "post.htw.stura-dresden.de";
httpPort = 80; httpPort = 80;
httpsPort = 443; httpsPort = 443;
sendProxy = false;
}; };
vot = { vot = {
dest = "141.56.51.57"; dest = "141.56.51.57";
domain = "vot.htw.stura-dresden.de"; domain = "vot.htw.stura-dresden.de";
httpPort = 80; httpPort = 80;
httpsPort = 443; httpsPort = 443;
sendProxy = false;
}; };
mail = { mail = {
dest = "141.56.51.14"; dest = "141.56.51.14";
domain = "mail.htw.stura-dresden.de"; domain = "mail.htw.stura-dresden.de";
httpPort = 80; httpPort = 80;
httpsPort = 443; httpsPort = 443;
sendProxy = false;
}; };
lists = { lists = {
dest = "141.56.51.14"; dest = "141.56.51.14";
domain = "lists.htw.stura-dresden.de"; domain = "lists.htw.stura-dresden.de";
httpPort = 80; httpPort = 80;
httpsPort = 443; httpsPort = 443;
sendProxy = false;
}; };
dat = { dat = {
dest = "141.56.51.17"; dest = "141.56.51.17";
domain = "dat.stu.htw.stura-dresden.de"; domain = "dat.stu.htw.stura-dresden.de";
httpPort = 80; httpPort = 80;
httpsPort = 443; httpsPort = 443;
}; sendProxy = false;
pro = {
dest = "141.56.51.15";
domain = "pro.htw.stura-dresden.de";
httpPort = 80;
httpsPort = 443;
};
cloud = {
dest = "141.56.51.16";
domain = "cloud.htw.stura-dresden.de";
httpPort = 80;
httpsPort = 443;
}; };
wiki = { wiki = {
dest = "141.56.51.13"; dest = "141.56.51.13";
domain = "wiki.htw.stura-dresden.de"; domain = "wiki.htw.stura-dresden.de";
httpPort = 80; httpPort = 80;
httpsPort = 443; httpsPort = 443;
sendProxy = true;
}; };
beach = { beach = {
dest = "141.56.51.51"; dest = "141.56.51.51";
domain = "beach.htw.stura-dresden.de"; domain = "beach.htw.stura-dresden.de";
httpPort = 80; httpPort = 80;
httpsPort = 443; httpsPort = 443;
sendProxy = false;
}; };
studicloud = { studicloud = {
dest = "141.56.51.17"; dest = "141.56.51.17";
domain = "dat.stu.htw.stura-dresden.de"; domain = "dat.stu.htw.stura-dresden.de";
httpPort = 80; httpPort = 80;
httpsPort = 443; httpsPort = 443;
sendProxy = false;
};
bbb = {
dest = "141.56.51.94";
domain = "bbb.htw.stura-dresden.de";
httpPort = 80;
httpsPort = 443;
sendProxy = false;
};
bbb-test = {
dest = "141.56.51.94";
domain = "bbb.test.htw.stura-dresden.de";
httpPort = 80;
httpsPort = 443;
sendProxy = false;
}; };
} }
# zusätzlich zu den oben definierten wird hier noch ein redirect für jeden nginx virtualhost in diese flake generiert # zusätzlich zu den oben definierten wird hier noch ein redirect für jeden nginx virtualhost in diese flake generiert
@ -160,6 +250,15 @@
prev prev
// (builtins.foldl' ( // (builtins.foldl' (
val: vhost: val: vhost:
let
proxyProtocol =
if
self.nixosConfigurations.${name}.config.services.nginx.virtualHosts.${vhost}.listen == [ ]
then
false
else
true;
in
val val
// { // {
"${vhost}" = { "${vhost}" = {
@ -167,6 +266,7 @@
domain = vhost; domain = vhost;
httpsPort = 443; httpsPort = 443;
httpPort = 80; httpPort = 80;
sendProxy = proxyProtocol;
}; };
} }
) { } vhosts) ) { } vhosts)
@ -223,43 +323,43 @@
"127.0.0.1" "127.0.0.1"
]; ];
listenOnIpv6 = [ ]; listenOnIpv6 = [ ];
zones = { # zones = {
"htw.stura-dresden.de" = { # "htw.stura-dresden.de" = {
master = true; # master = true;
file = pkgs.writeText "htw.stura-dresden.de.zone" '' # file = pkgs.writeText "htw.stura-dresden.de.zone" ''
$TTL 3600 # $TTL 3600
@ IN SOA proxy.htw.stura-dresden.de. hostmaster.htw.stura-dresden.de. ( # @ IN SOA proxy.htw.stura-dresden.de. hostmaster.htw.stura-dresden.de. (
2026031301 ; Serial (YYYYMMDDNN) # 2026031301 ; Serial (YYYYMMDDNN)
3600 ; Refresh (1 hour) # 3600 ; Refresh (1 hour)
1800 ; Retry (30 minutes) # 1800 ; Retry (30 minutes)
604800 ; Expire (1 week) # 604800 ; Expire (1 week)
86400 ) ; Minimum TTL (1 day) # 86400 ) ; Minimum TTL (1 day)
#
; Name servers # ; Name servers
@ IN NS proxy.htw.stura-dresden.de. # @ IN NS proxy.htw.stura-dresden.de.
#
; Proxy host - main IPv4 gateway # ; Proxy host - main IPv4 gateway
proxy IN A 141.56.51.1 # proxy IN A 141.56.51.1
proxy IN AAAA 2a01:4f8:1c19:96f8::1 # proxy IN AAAA 2a01:4f8:1c19:96f8::1
#
; Auto-generated CNAME records for all subdomains pointing to proxy # ; Auto-generated CNAME records for all subdomains pointing to proxy
${lib.foldlAttrs ( # ${lib.foldlAttrs (
prev: name: value: # prev: name: value:
let # let
zoneSuffix = ".htw.stura-dresden.de"; # zoneSuffix = ".htw.stura-dresden.de";
# Check if this domain belongs to our zone # # Check if this domain belongs to our zone
isInZone = lib.hasSuffix zoneSuffix value.domain; # isInZone = lib.hasSuffix zoneSuffix value.domain;
# Extract subdomain by removing the zone suffix # # Extract subdomain by removing the zone suffix
subdomain = lib.removeSuffix zoneSuffix value.domain; # subdomain = lib.removeSuffix zoneSuffix value.domain;
in # in
if isInZone && subdomain != "" && subdomain != "htw.stura-dresden.de" then # if isInZone && subdomain != "" && subdomain != "htw.stura-dresden.de" then
prev + "${subdomain}${" "}IN${" "}CNAME${" "}proxy.htw.stura-dresden.de.\n" # prev + "${subdomain}${" "}IN${" "}CNAME${" "}proxy.htw.stura-dresden.de.\n"
else # else
prev # prev
) "" forwards} # ) "" forwards}
''; # '';
}; # };
}; # };
}; };
# Chrony NTP server for the internal network # Chrony NTP server for the internal network
@ -333,20 +433,37 @@
enable = true; enable = true;
config = '' config = ''
global global
# schreibe globalen log ins journal ip -> app # schreibe globalen log ins journal ip -> app
log /dev/log format raw local0 log /dev/log format raw local0
maxconn 50000 maxconn 60000 # Safe limit below kernel conntrack (262144)
# man könnte metriken über einen socket file statt einen lokalen port machen für user permission control
# stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners # Buffer optimizations (Phase 2)
tune.bufsize 32762 tune.bufsize 32768 # Power of 2 (was 32762)
tune.maxrewrite 8192
# Connection handling
tune.maxaccept 500 # Prevent accept starvation
tune.maxpollevents 300
# TCP buffer sizes (64KB)
tune.rcvbuf.client 65536
tune.rcvbuf.server 65536
tune.sndbuf.client 65536
tune.sndbuf.server 65536
defaults defaults
log global log global
mode tcp mode tcp
option tcplog option tcplog
timeout connect 5s
timeout client 30s # Optimized timeouts (Phase 5)
timeout server 30s timeout connect 3s # Reduce from 5s
timeout client 60s # Increase from 30s
timeout server 60s # Increase from 30s
timeout queue 5s # Prevent indefinite queueing
# Performance
option splice-auto # Zero-copy kernel splicing
# stats seite zeigt backend connection status, wenn check gesetzt ist # stats seite zeigt backend connection status, wenn check gesetzt ist
frontend stats frontend stats
@ -354,13 +471,21 @@
mode http mode http
stats enable stats enable
stats uri /stats stats uri /stats
stats refresh 10s stats refresh 5s # Reduce from 10s for real-time monitoring
stats show-legends stats show-legends
stats show-node stats show-node
stats show-modules stats show-modules
stats admin if TRUE # Enable admin operations
http-request use-service prometheus-exporter if { path /metrics }
frontend http-in frontend http-in
bind *:80 bind *:80
mode http
tcp-request connection expect-proxy layer4 if { src 178.104.18.93 }
maxconn 60000
backlog 8192
option dontlognull
option http-keep-alive # Reuse connections for redirects
# hier wird eine regel pro domain aus der forwarder liste generiert # hier wird eine regel pro domain aus der forwarder liste generiert
${lib.foldlAttrs ( ${lib.foldlAttrs (
@ -379,8 +504,8 @@
prev: name: value: prev: name: value:
prev prev
+ '' + ''
use_backend ${name}_80 if is_${name}
http-request redirect scheme https code 301 if !is_acme is_${name} http-request redirect scheme https code 301 if !is_acme is_${name}
use_backend ${name}_80 if is_${name}
'' ''
) "" forwards} ) "" forwards}
@ -401,10 +526,18 @@
frontend sni_router frontend sni_router
bind *:443 bind *:443
mode tcp mode tcp
# mehrere pakete puffern und connection beenden wenn es kein ssl handshake sieht tcp-request connection expect-proxy layer4 if { src 178.104.18.93 }
tcp-request inspect-delay 1s
# Reduce inspection delay - SNI is in first packet (Phase 3)
tcp-request inspect-delay 500ms # Was 1s
tcp-request content accept if { req_ssl_hello_type 1 } tcp-request content accept if { req_ssl_hello_type 1 }
# Connection handling
option clitcpka # Enable client TCP keep-alive
maxconn 60000
backlog 16384 # Increase from default 1024
option dontlognull # Skip logging of monitoring probes
# tcp redirect der anwendung basierend auf ssl_sni handshake parameter # tcp redirect der anwendung basierend auf ssl_sni handshake parameter
${lib.foldlAttrs ( ${lib.foldlAttrs (
prev: name: value: prev: name: value:
@ -435,14 +568,118 @@
server ${name} ${value.dest}:${builtins.toString value.httpPort} server ${name} ${value.dest}:${builtins.toString value.httpPort}
backend ${name}_443 backend ${name}_443
mode tcp mode tcp
server ${name} ${value.dest}:${builtins.toString value.httpsPort} check option tcpka # Enable server TCP keep-alive (Phase 4)
timeout server 60s # Increase from 30s for long-lived HTTPS
timeout connect 3s # Reduce from 5s (local network)
server ${name} ${value.dest}:${builtins.toString value.httpsPort} ${
if value.sendProxy == true then "send-proxy-v2" else ""
} check inter 3000 rise 2 fall 3 maxconn 5000
'' ''
) "" forwards} ) "" forwards}
''; '';
}; };
vector.settings = {
enrichment_tables.geoip_table = {
type = "mmdb";
path = "/var/lib/GeoIP/GeoLite2-City.mmdb";
};
sources.haproxy_metrics = {
type = "prometheus_scrape";
endpoints = [ "http://127.0.0.1:8404/metrics" ];
scrape_interval_secs = 15;
};
transforms = {
add_host_label_haproxy = {
type = "remap";
inputs = [ "haproxy_metrics" ];
source = ''
.tags.host = get_hostname!()
'';
};
haproxy_logs_filter = {
type = "filter";
inputs = [ "journald_logs" ];
condition = ''."_SYSTEMD_UNIT" == "haproxy.service"'';
};
haproxy_logs_parse = {
type = "remap";
inputs = [ "haproxy_logs_filter" ];
source = ''
.host = get_hostname!()
.unit = "haproxy"
# IPv4: "1.2.3.4:port" IPv6: "[2001:db8::1]:port"
parsed, err = parse_regex(.message, r'^(?:\[(?P<ipv6>[0-9a-fA-F:]+)\]|(?P<ipv4>[\d.]+)):\d+')
if err == null {
if is_null(parsed.ipv6) {
.client_ip = parsed.ipv4
} else {
.client_ip = parsed.ipv6
}
}
'';
};
haproxy_geoip = {
type = "remap";
inputs = [ "haproxy_logs_parse" ];
source = ''
if exists(.client_ip) && !is_null(.client_ip) {
.geoip = get_enrichment_table_record("geoip_table", {"ip": string!(.client_ip)}) ?? {}
}
'';
};
};
sinks.mimir.inputs = lib.mkForce [
"add_host_label_metrics"
"add_host_label_haproxy"
];
};
}; };
stura.monitoring.extraLogInputs = [ "haproxy_geoip" ];
users.users.root.packages = [
(pkgs.writeShellScriptBin "nft-blacklist" ''
set -euo pipefail
usage() {
echo "Usage: nft-blacklist <add|del> <ip-or-cidr>"
echo " add - add entry to blacklist set"
echo " del - remove entry from blacklist set"
exit 1
}
[[ $# -ne 2 ]] && usage
ACTION="$1"
ADDR="$2"
if [[ "$ADDR" == *:* ]]; then
SET="blacklist6"
elif [[ "$ADDR" == *.* ]]; then
SET="blacklist4"
else
echo "Error: cannot determine address family for '$ADDR'" >&2
exit 1
fi
case "$ACTION" in
add)
${pkgs.nftables}/bin/nft add element inet filter "$SET" "{ $ADDR }"
echo "Added $ADDR to $SET"
;;
del)
${pkgs.nftables}/bin/nft delete element inet filter "$SET" "{ $ADDR }"
echo "Removed $ADDR from $SET"
;;
*)
usage
;;
esac
'')
];
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
]; ];

View file

@ -90,7 +90,9 @@
services.redmine.settings.production.email_delivery = { services.redmine.settings.production.email_delivery = {
delivery_method = ":smtp"; delivery_method = ":smtp";
smtp_settings = { smtp_settings = {
address = "mail.${config.networking.domain}"; # @tan 27-03-2026: muss an "alten" mailserver senden
#address = "mail.${config.networking.domain}";
address = "mail.stura.htw-dresden.de";
port = 25; port = 25;
}; };
#### Alternativ waere vielleicht auch das Versand von Mails durch das Programm sendmail (als lokale Installation) moeglich. #### Alternativ waere vielleicht auch das Versand von Mails durch das Programm sendmail (als lokale Installation) moeglich.
@ -132,13 +134,29 @@
#### Der StuRa speichert nicht! #### Der StuRa speichert nicht!
services.nginx.logError = ''/dev/null emerg''; services.nginx.logError = ''/dev/null emerg'';
services.nginx.appendHttpConfig = '' # services.nginx.appendHttpConfig = ''
access_log off; # access_log off;
# '';
services.nginx.commonHttpConfig = ''
real_ip_header proxy_protocol;
set_real_ip_from 141.56.51.1/32;
''; '';
#### Anscheinend kann mit nix nur die Konfiguration fuer eine konkrete (manuelle) Konfiguration fuer den Dienst web server. #### Anscheinend kann mit nix nur die Konfiguration fuer eine konkrete (manuelle) Konfiguration fuer den Dienst web server.
services.nginx.virtualHosts."${config.networking.fqdn}" = { services.nginx.virtualHosts."${config.networking.fqdn}" = {
#### https://search.nixos.org/options?show=services.nginx.virtualHosts.<name>.default #### https://search.nixos.org/options?show=services.nginx.virtualHosts.<name>.default
listen = [
{
port = 80;
addr = "0.0.0.0";
}
{
port = 443;
addr = "0.0.0.0";
ssl = true;
proxyProtocol = true;
}
];
default = true; default = true;
locations."/" = { locations."/" = {
proxyPass = "http://127.0.0.1:${toString config.services.redmine.port}"; proxyPass = "http://127.0.0.1:${toString config.services.redmine.port}";

View file

@ -38,15 +38,44 @@
"9.9.9.9" "9.9.9.9"
"1.1.1.1" "1.1.1.1"
]; ];
firewall = { firewall.enable = false;
allowedTCPPorts = [
22
80
443
];
};
nftables = { nftables = {
enable = true; enable = true;
ruleset = ''
table inet filter {
set blacklist4 {
type ipv4_addr
flags interval
# manage at runtime: nft add element inet filter blacklist4 { 1.2.3.0/24 }
}
set blacklist6 {
type ipv6_addr
flags interval
# manage at runtime: nft add element inet filter blacklist6 { 2001:db8::/32 }
}
chain input {
type filter hook input priority filter; policy drop;
iif "lo" accept
ct state established,related accept
ip saddr @blacklist4 drop
ip6 saddr @blacklist6 drop
tcp dport { 22, 80, 443 } accept
}
chain forward {
type filter hook forward priority filter; policy drop;
}
chain output {
type filter hook output priority filter; policy accept;
}
}
'';
}; };
}; };
@ -96,12 +125,50 @@
server proxy 141.56.51.1:80 server proxy 141.56.51.1:80
backend http_443 backend http_443
mode tcp mode tcp
server proxy 141.56.51.1:443 server proxy 141.56.51.1:443 send-proxy-v2
''; '';
}; };
}; };
environment.systemPackages = with pkgs; [ users.users.root.packages = [
(pkgs.writeShellScriptBin "nft-blacklist" ''
set -euo pipefail
usage() {
echo "Usage: nft-blacklist <add|del> <ip-or-cidr>"
echo " add - add entry to blacklist set"
echo " del - remove entry from blacklist set"
exit 1
}
[[ $# -ne 2 ]] && usage
ACTION="$1"
ADDR="$2"
if [[ "$ADDR" == *:* ]]; then
SET="blacklist6"
elif [[ "$ADDR" == *.* ]]; then
SET="blacklist4"
else
echo "Error: cannot determine address family for '$ADDR'" >&2
exit 1
fi
case "$ACTION" in
add)
${pkgs.nftables}/bin/nft add element inet filter "$SET" "{ $ADDR }"
echo "Added $ADDR to $SET"
;;
del)
${pkgs.nftables}/bin/nft delete element inet filter "$SET" "{ $ADDR }"
echo "Removed $ADDR from $SET"
;;
*)
usage
;;
esac
'')
]; ];
system.stateVersion = "25.11"; system.stateVersion = "25.11";

View file

@ -99,6 +99,17 @@
services.mediawiki.database.passwordFile = "/var/lib/mediawiki/mediawiki-dbpassword"; services.mediawiki.database.passwordFile = "/var/lib/mediawiki/mediawiki-dbpassword";
services.httpd = {
extraModules = [ "remoteip" ];
extraConfig = ''
# Trust HAProxy's address (adjust to your HAProxy IP/subnet)
RemoteIPProxyProtocol On
# RemoteIPProxyProtocolExceptions 127.0.0.1 ::1
RemoteIPTrustedProxy 141.56.51.1/32
'';
};
#### 2024-02-17 vater: #### 2024-02-17 vater:
#### trace: warning: The option `services.mediawiki.virtualHost' defined in `/etc/nixos/configuration.nix' has been renamed to `services.mediawiki.httpd.virtualHost'. #### trace: warning: The option `services.mediawiki.virtualHost' defined in `/etc/nixos/configuration.nix' has been renamed to `services.mediawiki.httpd.virtualHost'.
# services.mediawiki.virtualHost.hostName = "wiki.stura.htw-dresden.de"; # services.mediawiki.virtualHost.hostName = "wiki.stura.htw-dresden.de";
@ -150,8 +161,8 @@
Lockdown = pkgs.fetchzip { Lockdown = pkgs.fetchzip {
# url = "https://extdist.wmflabs.org/dist/extensions/Lockdown-REL1_43-7ac8966.tar.gz"; # url = "https://extdist.wmflabs.org/dist/extensions/Lockdown-REL1_43-7ac8966.tar.gz";
# url = "https://extdist.wmflabs.org/dist/extensions/Lockdown-REL1_44-af1f4df.tar.gz"; # url = "https://extdist.wmflabs.org/dist/extensions/Lockdown-REL1_44-af1f4df.tar.gz";
url = "https://extdist.wmflabs.org/dist/extensions/Lockdown-REL1_45-a46dbea.tar.gz"; url = "https://extdist.wmflabs.org/dist/extensions/CategoryLockdown-REL1_45-a715472.tar.gz";
sha256 = "sha256-zTTpbQiqudLILPSzmKGjKr6wZjh0YUttGmqwjPpAToc="; sha256 = "sha256-1gl5m9xkmLrdjoR0M13gcQHLtZt4Bt0PUXDiDEqjpvk=";
}; };
#### Hinzufuegen der Erweiterung ConfirmEdit fuer eine zusaetzliche Bestaetigung bei Bearbeitungen, etwa um Herausforderungen (aka CAPTCHA) zu stellen #### Hinzufuegen der Erweiterung ConfirmEdit fuer eine zusaetzliche Bestaetigung bei Bearbeitungen, etwa um Herausforderungen (aka CAPTCHA) zu stellen
@ -168,8 +179,8 @@
#### Hinzufuegen der Erweiterung ContributionScores fuer eine Statistik von Beitraegen nach Beitragenden #### Hinzufuegen der Erweiterung ContributionScores fuer eine Statistik von Beitraegen nach Beitragenden
#### https://www.mediawiki.org/wiki/Extension:ContributionScores #### https://www.mediawiki.org/wiki/Extension:ContributionScores
ContributionScores = pkgs.fetchzip { ContributionScores = pkgs.fetchzip {
url = "https://extdist.wmflabs.org/dist/extensions/ContributionScores-REL1_45-cd4c94b.tar.gz"; url = "https://extdist.wmflabs.org/dist/extensions/ContributionCredits-REL1_45-22c28de.tar.gz";
sha256 = "sha256-8ClNtEQ66deKM1DsRYaaZ3KlRl4yCt6UhpXcozRQzQ8="; sha256 = "sha256-9T67jCEYQyU7P9sN7tYbnevU5+FX6Y1nydXGEdzQS9k=";
}; };
#### Hinzufuegen der Erweiterung Interwiki fuer das Verwenden von Verweisen als eine Art Namensraum, wie beispielweise auf Wikipedia oder selbst festgelegte Verweise #### Hinzufuegen der Erweiterung Interwiki fuer das Verwenden von Verweisen als eine Art Namensraum, wie beispielweise auf Wikipedia oder selbst festgelegte Verweise
@ -190,8 +201,8 @@
#### https://www.mediawiki.org/wiki/Extension:UserMerge #### https://www.mediawiki.org/wiki/Extension:UserMerge
UserMerge = pkgs.fetchzip { UserMerge = pkgs.fetchzip {
# url = "https://extdist.wmflabs.org/dist/extensions/UserMerge-REL1_43-ed4a689.tar.gz"; # url = "https://extdist.wmflabs.org/dist/extensions/UserMerge-REL1_43-ed4a689.tar.gz";
url = "https://extdist.wmflabs.org/dist/extensions/UserMerge-REL1_45-446566b.tar.gz"; url = "https://extdist.wmflabs.org/dist/extensions/UserMerge-REL1_45-433f6c2.tar.gz";
sha256 = "sha256-DTDKlzet3lThh/sRLucyb8b9lhK5FYZ+dMgwrThFFBM="; sha256 = "sha256-JyY4pJNBKQ9bOKrilPWCheZ5ihWwPM6ZJ0qHsZ3coPk=";
}; };
}; };

123
modules/monitoring.nix Normal file
View file

@ -0,0 +1,123 @@
{ pkgs, lib, config, ... }:
let
cfg = config.stura.monitoring;
in {
options.stura.monitoring = {
extraLogFiles = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [];
description = "Additional log file paths for vector to scrape and forward to Loki.";
example = [ "/var/log/nginx/access.log" "/var/log/nginx/error.log" ];
};
extraGroups = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [];
description = "Supplementary groups added to the vector systemd service to allow reading protected log files.";
example = [ "nginx" "postfix" ];
};
extraMetricInputs = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [];
description = "Additional vector component IDs to feed into the mimir sink alongside host_metrics.";
example = [ "proxmox_normalize_metrics" ];
};
extraLogInputs = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [];
description = "Additional vector component IDs to feed into the loki sink alongside journald_logs.";
example = [ "proxmox_normalize_logs" ];
};
};
config = {
networking.hosts = {
# rewrite these host entries on each system, this does not go through proxy
"141.56.51.20" = [
"mon.adm.htw.stura-dresden.de"
"log.adm.htw.stura-dresden.de"
"met.adm.htw.stura-dresden.de"
];
};
services.vector = {
enable = true;
settings = {
sources = {
host_metrics = {
type = "host_metrics";
collectors = [
"cpu"
"disk"
"filesystem"
"load"
"host"
"memory"
"network"
"process"
];
};
journald_logs = {
type = "journald";
include_units = []; # empty = collect all units
};
} // lib.optionalAttrs (cfg.extraLogFiles != [] || config.services.nginx.enable) {
extra_log_files = {
type = "file";
include = lib.optional config.services.nginx.enable "/var/log/nginx/access.log"
++ cfg.extraLogFiles;
};
};
transforms = {
add_host_label_metrics = {
type = "remap";
inputs = [ "host_metrics" ];
source = ''
.tags.host = get_hostname!()
del(.tags.command)
'';
};
add_host_label_logs = {
type = "remap";
inputs = [ "journald_logs" ] ++ lib.optional (cfg.extraLogFiles != [] || config.services.nginx.enable) "extra_log_files";
source = ''
.host = get_hostname!()
.unit = string(."_SYSTEMD_UNIT") ?? "file"
'';
};
};
sinks = {
mimir = {
type = "prometheus_remote_write";
inputs = [ "add_host_label_metrics" ] ++ cfg.extraMetricInputs;
endpoint = "https://met.adm.htw.stura-dresden.de/api/v1/push";
tls.verify_certificate = false;
healthcheck.enabled = false;
};
loki = {
type = "loki";
inputs = [ "add_host_label_logs" ] ++ cfg.extraLogInputs;
endpoint = "https://log.adm.htw.stura-dresden.de";
labels = {
host = "{{ host }}";
unit = "{{ unit }}";
};
tls.verify_certificate = false;
encoding.codec = "json";
};
};
};
};
systemd.services.vector.serviceConfig.SupplementaryGroups =
[ "systemd-journal" ]
++ lib.optional config.services.nginx.enable "nginx"
++ cfg.extraGroups;
};
}