mirror of
https://codeberg.org/polyteknisk-radiogruppe/the_prg_server_configuration.git
synced 2026-10-21 03:15:46 +02:00
Compare commits
No commits in common. "fe289e0600699af0547016334cf251cc0ab9828c" and "7f3b5afbf6d4a2965b9490a5f37e625ab2463d67" have entirely different histories.
fe289e0600
...
7f3b5afbf6
9 changed files with 4 additions and 291 deletions
|
|
@ -35,7 +35,3 @@ creation_rules:
|
||||||
- age:
|
- age:
|
||||||
- *admin_christine
|
- *admin_christine
|
||||||
- *server_build_machine
|
- *server_build_machine
|
||||||
- path_regex: nix-system-configs/secrets/mail/[^/]+\.(yaml|json|env|ini)$
|
|
||||||
key_groups:
|
|
||||||
- age:
|
|
||||||
- *admin_christine
|
|
||||||
|
|
@ -16,7 +16,6 @@ configs=(
|
||||||
"nixos-traefik"
|
"nixos-traefik"
|
||||||
"nixos-build-machine"
|
"nixos-build-machine"
|
||||||
"nixos-logs"
|
"nixos-logs"
|
||||||
"nixos-mail"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if [[ -n "$1" ]]; then
|
if [[ -n "$1" ]]; then
|
||||||
|
|
|
||||||
|
|
@ -57,11 +57,6 @@
|
||||||
inherit system;
|
inherit system;
|
||||||
modules = [./nix-system-configs/modules/system/gramethus.nix];
|
modules = [./nix-system-configs/modules/system/gramethus.nix];
|
||||||
};
|
};
|
||||||
|
|
||||||
"nixos-mail" = nixpkgs.lib.nixosSystem {
|
|
||||||
inherit system;
|
|
||||||
modules = [./nix-system-configs/modules/system/mail-server.nix];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,58 +0,0 @@
|
||||||
{
|
|
||||||
config,
|
|
||||||
pkgs,
|
|
||||||
lib,
|
|
||||||
...
|
|
||||||
}: {
|
|
||||||
imports = let
|
|
||||||
# replace this with an actual commit id or tag
|
|
||||||
commit = "17eea6f3816ba6568b8c81db8a4e6ca438b30b7c";
|
|
||||||
in [
|
|
||||||
"${builtins.fetchTarball {
|
|
||||||
url = "https://github.com/Mic92/sops-nix/archive/${commit}.tar.gz";
|
|
||||||
# replace this with an actual hash
|
|
||||||
sha256 = "ktjWTq+D5MTXQcL9N6cDZXUf9kX8JBLLBLT0ZyOTSYY=";
|
|
||||||
}}/modules/sops"
|
|
||||||
];
|
|
||||||
|
|
||||||
# This will add secrets.yml to the nix store
|
|
||||||
# You can avoid this by adding a string to the full path instead, i.e.
|
|
||||||
# sops.defaultSopsFile = "/root/.sops/secrets/example.yaml";
|
|
||||||
sops.defaultSopsFile = ../../secrets/mail/secrets.yaml;
|
|
||||||
# This will automatically import SSH keys as age keys
|
|
||||||
#sops.age.sshKeyPaths = ["/home/nixosdd/.ssh/id_ed25519"];
|
|
||||||
# This is using an age key that is expected to already be in the filesystem
|
|
||||||
sops.age.keyFile = "/var/lib/sops-nix/key.txt";
|
|
||||||
# This will generate a new key if the key specified above does not exist
|
|
||||||
sops.age.generateKey = true;
|
|
||||||
|
|
||||||
# Export individual WireGuard keys from the SOPS YAML as text secrets so they
|
|
||||||
# are available both as strings and as files (.path)
|
|
||||||
sops.secrets."admin-password" = {
|
|
||||||
format = "yaml";
|
|
||||||
sopsFile = ../../secrets/mail/secrets.yaml;
|
|
||||||
owner = "root";
|
|
||||||
mode = "0400";
|
|
||||||
};
|
|
||||||
|
|
||||||
sops.secrets."board-member-password" = {
|
|
||||||
format = "yaml";
|
|
||||||
sopsFile = ../../secrets/mail/secrets.yaml;
|
|
||||||
owner = "root";
|
|
||||||
mode = "0400";
|
|
||||||
};
|
|
||||||
|
|
||||||
sops.secrets."cloudflare-dns-token" = {
|
|
||||||
format = "yaml";
|
|
||||||
sopsFile = ../../secrets/mail/secrets.yaml;
|
|
||||||
owner = "root";
|
|
||||||
mode = "0444";
|
|
||||||
};
|
|
||||||
|
|
||||||
sops.secrets."cloudflare-username" = {
|
|
||||||
format = "yaml";
|
|
||||||
sopsFile = ../../secrets/mail/secrets.yaml;
|
|
||||||
owner = "root";
|
|
||||||
mode = "0444";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -35,7 +35,6 @@ in {
|
||||||
(choose [./modules/bootloader/seabios-assigned-iso-at-birth.nix ../bootloader/seabios-assigned-iso-at-birth.nix])
|
(choose [./modules/bootloader/seabios-assigned-iso-at-birth.nix ../bootloader/seabios-assigned-iso-at-birth.nix])
|
||||||
(choose [./modules/lix-default.nix ../lix-default.nix])
|
(choose [./modules/lix-default.nix ../lix-default.nix])
|
||||||
(choose [./modules/secrets-config/sops-the-blank-system.nix ../secrets-config/sops-the-blank-system.nix])
|
(choose [./modules/secrets-config/sops-the-blank-system.nix ../secrets-config/sops-the-blank-system.nix])
|
||||||
(choose [./modules/toolsets/grafana_metric.nix ../toolsets/grafana_metric.nix])
|
|
||||||
];
|
];
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ in {
|
||||||
server = {
|
server = {
|
||||||
DOMAIN = "git.prg-radio.org";
|
DOMAIN = "git.prg-radio.org";
|
||||||
ROOT_URL = "https://git.prg-radio.org/";
|
ROOT_URL = "https://git.prg-radio.org/";
|
||||||
HTTP_PORT = 30000;
|
HTTP_PORT = 3000;
|
||||||
# SSH integration
|
# SSH integration
|
||||||
SSH_PORT = lib.head config.services.openssh.ports;
|
SSH_PORT = lib.head config.services.openssh.ports;
|
||||||
};
|
};
|
||||||
|
|
@ -197,7 +197,7 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
# Open ports in the firewall.
|
# Open ports in the firewall.
|
||||||
networking.firewall.allowedTCPPorts = [30000];
|
networking.firewall.allowedTCPPorts = [3000];
|
||||||
|
|
||||||
system.stateVersion = "25.11";
|
system.stateVersion = "25.11";
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,135 +0,0 @@
|
||||||
{
|
|
||||||
config,
|
|
||||||
pkgs,
|
|
||||||
lib,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
choose = paths: lib.findFirst builtins.pathExists null paths;
|
|
||||||
in {
|
|
||||||
options.local = {
|
|
||||||
hostname = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "nixos-default";
|
|
||||||
description = "System hostname";
|
|
||||||
};
|
|
||||||
username = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "user";
|
|
||||||
description = "Primary user username";
|
|
||||||
};
|
|
||||||
userDescription = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "NixOS User";
|
|
||||||
description = "Primary user description";
|
|
||||||
};
|
|
||||||
address = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "10.1.1.100";
|
|
||||||
description = "Static IP address";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
imports = lib.filter (x: x != null) [
|
|
||||||
(choose [./modules/desktop-manager/sway_greetd_homemanager.nix ../desktop-manager/sway_greetd_homemanager.nix])
|
|
||||||
(choose [./modules/local/hostname_username.nix ../local/hostname_username.nix])
|
|
||||||
(choose [./modules/local/networking_local.nix ../local/networking_local.nix])
|
|
||||||
(choose [./modules/bootloader/seabios-assigned-proxmox-at-birth.nix ../bootloader/seabios-assigned-proxmox-at-birth.nix])
|
|
||||||
(choose [./modules/lix-default.nix ../lix-default.nix])
|
|
||||||
(choose [./modules/secrets-config/sops-the-blank-system.nix ../secrets-config/sops-the-blank-system.nix])
|
|
||||||
(choose [./modules/toolsets/grafana_metric.nix ../toolsets/grafana_metric.nix])
|
|
||||||
(choose [./modules/secrets-config/sops-mail.nix ../secrets-config/sops-mail.nix])
|
|
||||||
];
|
|
||||||
|
|
||||||
config = {
|
|
||||||
local.hostname = "nixos-mailserver";
|
|
||||||
local.username = "mailprg";
|
|
||||||
local.userDescription = "NixOS PRG Mailing Service";
|
|
||||||
local.address = "10.1.1.15";
|
|
||||||
system.stateVersion = "25.11";
|
|
||||||
|
|
||||||
services.stalwart-mail = {
|
|
||||||
enable = true;
|
|
||||||
openFirewall = true;
|
|
||||||
settings = {
|
|
||||||
server = {
|
|
||||||
hostname = "mail.prg-radio.org";
|
|
||||||
tls = {
|
|
||||||
enable = true;
|
|
||||||
implicit = true;
|
|
||||||
};
|
|
||||||
listener = {
|
|
||||||
smtp = {
|
|
||||||
protocol = "smtp";
|
|
||||||
bind = "[::]:25";
|
|
||||||
proxy.trusted-networks = [
|
|
||||||
"10.1.1.250/32"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
submissions = {
|
|
||||||
bind = "[::]:465";
|
|
||||||
protocol = "smtp";
|
|
||||||
tls.implicit = true;
|
|
||||||
# Also trust proxy for SMTPS
|
|
||||||
proxy.trusted-networks = ["10.1.1.250/32"];
|
|
||||||
};
|
|
||||||
imaps = {
|
|
||||||
bind = "[::]:993";
|
|
||||||
protocol = "imap";
|
|
||||||
tls.implicit = true;
|
|
||||||
proxy.trusted-networks = ["10.1.1.250/32"];
|
|
||||||
};
|
|
||||||
jmap = {
|
|
||||||
bind = "[::]:8080";
|
|
||||||
url = "https://mail.prg-radio.org";
|
|
||||||
protocol = "http";
|
|
||||||
};
|
|
||||||
management = {
|
|
||||||
bind = ["127.0.0.1:8080"];
|
|
||||||
protocol = "http";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
lookup.default = {
|
|
||||||
hostname = "mail.prg-radio.org";
|
|
||||||
domain = "prg-radio.org";
|
|
||||||
};
|
|
||||||
acme."letsencrypt" = {
|
|
||||||
directory = "https://acme-v02.api.letsencrypt.org/directory";
|
|
||||||
challenge = "dns-01";
|
|
||||||
contact = config.sops.secrets."cloudflare-username".path;
|
|
||||||
domains = ["prg-radio.org" "mail.prg-radio.org"];
|
|
||||||
provider = "cloudflare";
|
|
||||||
secret = config.sops.secrets."cloudflare-dns-token".path;
|
|
||||||
};
|
|
||||||
session.auth = {
|
|
||||||
mechanisms = "[plain]";
|
|
||||||
directory = "'in-memory'";
|
|
||||||
};
|
|
||||||
storage.directory = "in-memory";
|
|
||||||
session.rcpt.directory = "'in-memory'";
|
|
||||||
directory."imap".lookup.domains = ["prg-radio.org"];
|
|
||||||
directory."in-memory" = {
|
|
||||||
type = "memory";
|
|
||||||
principals = [
|
|
||||||
{
|
|
||||||
class = "individual";
|
|
||||||
name = "Polyteknisk Radiogruppe Board Member";
|
|
||||||
secret = config.sops.secrets."board-member-password".path;
|
|
||||||
email = ["board@prg-radio.org"];
|
|
||||||
}
|
|
||||||
{
|
|
||||||
class = "individual";
|
|
||||||
name = "postmaster";
|
|
||||||
secret = config.sops.secrets."board-member-password".path;
|
|
||||||
email = ["postmaster@prg-radio.org"];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
authentication.fallback-admin = {
|
|
||||||
user = "admin";
|
|
||||||
secret = config.sops.secrets."admin-password".path;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -265,20 +265,6 @@ in {
|
||||||
teamspeak-data = {
|
teamspeak-data = {
|
||||||
address = "[::]:30033/tcp";
|
address = "[::]:30033/tcp";
|
||||||
};
|
};
|
||||||
|
|
||||||
# Mail entrypoints: plain SMTP, implicit SMTPS (465) and IMAPS (993)
|
|
||||||
#smtp = {
|
|
||||||
# # plain SMTP (port 25) - TCP passthrough to backend
|
|
||||||
# address = "[::]:25";
|
|
||||||
# };
|
|
||||||
smtps = {
|
|
||||||
# implicit TLS SMTP (port 465) - passthrough to backend
|
|
||||||
address = "[::]:465";
|
|
||||||
};
|
|
||||||
imaps = {
|
|
||||||
# implicit TLS IMAP (port 993) - passthrough to backend
|
|
||||||
address = "[::]:993";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
log = {
|
log = {
|
||||||
level = "INFO";
|
level = "INFO";
|
||||||
|
|
@ -364,14 +350,6 @@ in {
|
||||||
tls = {};
|
tls = {};
|
||||||
middlewares = ["anubisForwardAuth"];
|
middlewares = ["anubisForwardAuth"];
|
||||||
};
|
};
|
||||||
|
|
||||||
# Mail HTTP (JMAP / web) - terminate TLS at Traefik and forward to Stalwart JMAP HTTP listener
|
|
||||||
mail = {
|
|
||||||
rule = "Host(`mail.prg-radio.org`)";
|
|
||||||
service = "mail-jmap";
|
|
||||||
entryPoints = ["websecure"];
|
|
||||||
tls = {certresolver = "acme";};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
http.services = {
|
http.services = {
|
||||||
|
|
@ -384,7 +362,7 @@ in {
|
||||||
|
|
||||||
forgejo.loadBalancer = {
|
forgejo.loadBalancer = {
|
||||||
servers = [
|
servers = [
|
||||||
{url = "http://10.1.1.4:30000";}
|
{url = "http://10.1.1.4:3000";}
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
matrix.loadBalancer = {
|
matrix.loadBalancer = {
|
||||||
|
|
@ -409,11 +387,6 @@ in {
|
||||||
{url = "http://10.1.1.10:3000";}
|
{url = "http://10.1.1.10:3000";}
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
# Mail JMAP HTTP backend
|
|
||||||
mail-jmap.loadBalancer = {
|
|
||||||
servers = [{url = "http://10.1.1.15:8080";}];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# TCP routing for TeamSpeak
|
# TCP routing for TeamSpeak
|
||||||
|
|
@ -451,30 +424,6 @@ in {
|
||||||
passthrough = true;
|
passthrough = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# Mail TCP routers: SMTP (25), SMTPS (465 implicit TLS), IMAPS (993 implicit TLS)
|
|
||||||
#mail-smtp = {
|
|
||||||
# # catch-all TCP router for port 25
|
|
||||||
# rule = "HostSNI(`*`)";
|
|
||||||
# service = "mail-smtp";
|
|
||||||
# entryPoints = ["smtp"];
|
|
||||||
# };
|
|
||||||
|
|
||||||
mail-smtps = {
|
|
||||||
# SMTPS implicit TLS - passthrough to backend
|
|
||||||
rule = "HostSNI(`*`)";
|
|
||||||
service = "mail-smtps";
|
|
||||||
entryPoints = ["smtps"];
|
|
||||||
tls = {passthrough = true;};
|
|
||||||
};
|
|
||||||
|
|
||||||
mail-imaps = {
|
|
||||||
# IMAPS implicit TLS - passthrough to backend
|
|
||||||
rule = "HostSNI(`*`)";
|
|
||||||
service = "mail-imaps";
|
|
||||||
entryPoints = ["imaps"];
|
|
||||||
tls = {passthrough = true;};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
tcp.services = {
|
tcp.services = {
|
||||||
|
|
@ -493,19 +442,6 @@ in {
|
||||||
{address = "10.1.1.248:12244";}
|
{address = "10.1.1.248:12244";}
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
# Mail TCP services
|
|
||||||
# mail-smtp.loadBalancer = {
|
|
||||||
# servers = [ { address = "10.1.1.15:25"; } ];
|
|
||||||
# };
|
|
||||||
|
|
||||||
mail-smtps.loadBalancer = {
|
|
||||||
servers = [{address = "10.1.1.15:465";}];
|
|
||||||
};
|
|
||||||
|
|
||||||
mail-imaps.loadBalancer = {
|
|
||||||
servers = [{address = "10.1.1.15:993";}];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# UDP routing for TeamSpeak voice
|
# UDP routing for TeamSpeak voice
|
||||||
|
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
admin-password: ENC[AES256_GCM,data:o8nD9CDNzufxVjfH7TqUY4QO6Xkz1xbpFu74jMVRR57NDKpKsg3ijRmBvvq1/QuJ2TM=,iv:xVGjzrRFpCyjriW6yB/UjuGiNhK4oeBiDA+Pk/BTOWc=,tag:H/ZuqffTDGsGTWTTKplvvA==,type:str]
|
|
||||||
board-member-password: ENC[AES256_GCM,data:8KLyqyGFi/ehvbNU6HsWilMO42UnXYL6puc/OOPgMDiU2fuDM2o7TibUCn1BXi9UyiE=,iv:UyLOFSARK/5p/zin7vqQic9C5qlryd/O/mjcw3eZ3ao=,tag:N2RJC6nZC+V3XoAw/eWYfA==,type:str]
|
|
||||||
cloudflare-dns-token: ENC[AES256_GCM,data:W0S9WWmhQMwjKbKI60vBjYlSb0chZUYcVs3A4DsVRfJwErcIqDWoJg==,iv:nRH8hLvCavydVC16M93N+r/t9WwNY4339CE4zGSINsk=,tag:yIUKs/XB3arhApGeik6p1A==,type:str]
|
|
||||||
cloudflare-username: ENC[AES256_GCM,data:5QCWOZcv6RKlk1/5LWjjCW0m,iv:9VzhRDlLq36pMfv0tu7POxheLFKdXP8tLLiKlTOr/30=,tag:MiijON1+mKJj6VMdnaJTkA==,type:str]
|
|
||||||
sops:
|
|
||||||
age:
|
|
||||||
- recipient: age1746rvsvsc3snxfl7cndm222wd5kck4aqj3x7nednlegq0gdjhfcqx0qv7m
|
|
||||||
enc: |
|
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBseTM3bTJtamFBVzRkOVpp
|
|
||||||
bEZNQlJoNUVjTFd0NGl3VktmUUdHWi9wMTM0CnE3bTh5QmM1KzVqTnI3RHdmbXhN
|
|
||||||
a0NWRkthbG9OZ3pZMEZkU3hjWUNyd1UKLS0tIE5KdXgzQmRRWTVBbDFTSEkzQW9o
|
|
||||||
ZWE0ci9wSmhpWmc1OHZwb09aTjk1TUUKitmILkhief6sapPh3gZAEDsaHqcv3se0
|
|
||||||
+6w+hs05ChkXHQ+JlXOTznd5ZNS4hwOAk5KOconNbauBaKWDplnHhA==
|
|
||||||
-----END AGE ENCRYPTED FILE-----
|
|
||||||
lastmodified: "2026-02-15T14:13:19Z"
|
|
||||||
mac: ENC[AES256_GCM,data:7hFjuvictSbcXLqXwG0VgWErKJpFsy1PfDyepQQXpszpMT4Z/BwvXlk4ppKo8C0PaCLv2qi86yBmFm/O6xUBhsMEFWYHQ+mJpYtqLX0GDvj1cn4LwDEnRa+2SiHkkZeHSwrtOHCBw8vE2R2sXBaNMkUoSXkcQ4lPS6YjulpO1vw=,iv:5aZxEnPymcvNpsUyGvvRI3o7hnfExSFWlBrzoIhQkFQ=,tag:6JJGvBL9XeiPw+TdN2qEgA==,type:str]
|
|
||||||
unencrypted_suffix: _unencrypted
|
|
||||||
version: 3.11.0
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue