feat: use ACME and nginx instead of caddy
This commit is contained in:
parent
5cf48868b0
commit
29e183b0c7
|
@ -58,6 +58,7 @@
|
|||
inputs.nixos-hardware.nixosModules.raspberry-pi-4
|
||||
./pie
|
||||
self.nixosModules.yule
|
||||
self.nixosModules.acme
|
||||
self.nixosModules.docker
|
||||
self.nixosModules.invoiceplane
|
||||
];
|
||||
|
@ -69,6 +70,7 @@
|
|||
self.nixosModules.base
|
||||
./frikandel
|
||||
self.nixosModules.yule
|
||||
self.nixosModules.acme
|
||||
self.nixosModules.docker
|
||||
];
|
||||
};
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
./configuration.nix
|
||||
|
||||
./networking.nix
|
||||
./nginx.nix
|
||||
./wireguard.nix
|
||||
./email.nix
|
||||
./website.nix
|
||||
|
|
|
@ -5,16 +5,16 @@
|
|||
lib,
|
||||
...
|
||||
}: let
|
||||
restartMaddyOnCertRenewal = pkgs.writeShellScriptBin "restart-maddy-on-cert-renewal" ''
|
||||
if [ "$1" == "mail.b12f.io"]; then
|
||||
${pkgs.systemd}/bin/systemctl restart maddy.service;
|
||||
fi
|
||||
dkimDNSb12fio = ''
|
||||
default._domainkey IN TXT ( "v=DKIM1; k=rsa; "
|
||||
"p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyla9hW3TvoXvZQxwzaJ4SZ9ict1HU3E6+FWlwNIgE6tIpTCyRJtiSIUDqB8TLTIBoxIs+QQBXZi+QUi3Agu6OSY2RiV0EwO8+oOOqOD9pERftc/aqe51cXuv4kPqwvpXEBwrXFWVM+VxivEubUJ7eKkFyXJpelv0LslXv/MmYbUyed6dF+reOGZCsvnbiRv74qdxbAL/25j62E8WrnxzJwhUtx/JhdBOjsHBvuw9hy6rZsVJL9eXayWyGRV6qmsLRzsRSBs+mDrgmKk4dugADd11+A03ics3i8hplRoWDkqnNKz1qy4f5TsV6v9283IANrAzRfHwX8EvNiFsBz+ZCQIDAQAB" ) ;
|
||||
'';
|
||||
in {
|
||||
age.secrets."b12f.io-dkim-private-rsa" = {
|
||||
file = "${flake.self}/secrets/b12f.io-dkim-private-rsa.age";
|
||||
path = "/var/lib/maddy/dkim_keys/b12f.io_default.key";
|
||||
mode = "400";
|
||||
owner = "rspamd";
|
||||
owner = "maddy";
|
||||
};
|
||||
|
||||
age.secrets."mail@b12f.io-password" = {
|
||||
|
@ -23,23 +23,20 @@ in {
|
|||
owner = "maddy";
|
||||
};
|
||||
|
||||
services.caddy = {
|
||||
globalConfig = ''
|
||||
events {
|
||||
on cert_obtained exec ${restartMaddyOnCertRenewal}/bin/restart-maddy-on-cert-renewal {event.data.name}
|
||||
}
|
||||
'';
|
||||
security.acme.certs = {
|
||||
"mail.b12f.io" = {
|
||||
reloadServices = [ "maddy" ];
|
||||
group = "maddy";
|
||||
};
|
||||
"mta-sts.b12f.io" = {};
|
||||
};
|
||||
|
||||
virtualHosts = {
|
||||
"mail.b12f.io".extraConfig = ''
|
||||
respond "404 Not Found"
|
||||
'';
|
||||
|
||||
"mta-sts.b12f.io".extraConfig = ''
|
||||
encode gzip
|
||||
file_server
|
||||
root * ${
|
||||
pkgs.runCommand "testdir" {} ''
|
||||
services.nginx.virtualHosts = {
|
||||
"mta-sts.b12f.io" = {
|
||||
forceSSL = true;
|
||||
useACMEHost = "mta-sts.b12f.io";
|
||||
locations."/" = {
|
||||
root = pkgs.runCommand "create-well-known-mta-sts" {} ''
|
||||
mkdir -p "$out/.well-known"
|
||||
echo "
|
||||
version: STSv1
|
||||
|
@ -47,53 +44,183 @@ in {
|
|||
max_age: 604800
|
||||
mx: mail.b12f.io
|
||||
" > "$out/.well-known/mta-sts.txt"
|
||||
''
|
||||
}
|
||||
'';
|
||||
tryFiles = "$uri $uri/ =404";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
"d '/run/maddy' 0750 maddy maddy - -"
|
||||
];
|
||||
|
||||
system.activationScripts.makeMaddyDKIMDNS = lib.stringAfter [ "var" ] ''
|
||||
mkdir -p /var/lib/maddy/dkim_keys
|
||||
|
||||
echo '${dkimDNSb12fio}' >> /var/lib/maddy/dkim_keys/b12f.io_default.dns
|
||||
'';
|
||||
|
||||
services.maddy = {
|
||||
enable = false;
|
||||
|
||||
enable = true;
|
||||
openFirewall = true;
|
||||
|
||||
hostname = "mail.b12f.io";
|
||||
|
||||
primaryDomain = "b12f.io";
|
||||
|
||||
ensureAccounts = [
|
||||
"mail@b12f.io"
|
||||
];
|
||||
|
||||
ensureCredentials = {
|
||||
# Do not use this in production. This will make passwords world-readable
|
||||
# in the Nix store
|
||||
"mail@b12f.io".passwordFile = config.age.secrets."mail@b12f.io-password".path;
|
||||
};
|
||||
|
||||
tls = {
|
||||
loader = "file";
|
||||
certificates = [
|
||||
{
|
||||
keyPath = "/var/lib/caddy/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/mail.b12f.io/mail.b12f.io.key";
|
||||
certPath = "/var/lib/caddy/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/mail.b12f.io/mail.b12f.io.crt";
|
||||
keyPath = "${config.security.acme.certs."mail.b12f.io".directory}/key.pem";
|
||||
certPath = "${config.security.acme.certs."mail.b12f.io".directory}/cert.pem";
|
||||
}
|
||||
];
|
||||
};
|
||||
config = ''
|
||||
# Minimal configuration with TLS disabled, adapted from upstream example
|
||||
# configuration here https://github.com/foxcpp/maddy/blob/master/maddy.conf
|
||||
# Do not use this in production!
|
||||
|
||||
config = (builtins.replaceStrings ["msgpipeline local_routing {"] [''msgpipeline local_routing {
|
||||
auth.pass_table local_authdb {
|
||||
table sql_table {
|
||||
driver sqlite3
|
||||
dsn credentials.db
|
||||
table_name passwords
|
||||
}
|
||||
}
|
||||
|
||||
storage.imapsql local_mailboxes {
|
||||
driver sqlite3
|
||||
dsn imapsql.db
|
||||
}
|
||||
|
||||
table.chain local_rewrites {
|
||||
optional_step regexp "(.+)\+(.+)@(.+)" "$1@$3"
|
||||
optional_step static {
|
||||
entry postmaster postmaster@$(primary_domain)
|
||||
}
|
||||
optional_step file /etc/maddy/aliases
|
||||
}
|
||||
|
||||
msgpipeline local_routing {
|
||||
check {
|
||||
rspamd {
|
||||
api_path http://localhost:11334
|
||||
}
|
||||
}''] config.services.maddy.config.default) ++ ''
|
||||
}
|
||||
|
||||
destination b12f.io {
|
||||
modify {
|
||||
domains b12f.io
|
||||
selector default
|
||||
key_path ${config.age.secrets."b12f.io-dkim-private-rsa".path}
|
||||
replace_rcpt regexp ".*" "mail@b12f.io"
|
||||
}
|
||||
deliver_to &local_mailboxes
|
||||
}
|
||||
|
||||
destination postmaster $(local_domains) {
|
||||
modify {
|
||||
replace_rcpt &local_rewrites
|
||||
}
|
||||
deliver_to &local_mailboxes
|
||||
}
|
||||
|
||||
default_destination {
|
||||
reject 550 5.1.1 "User doesn't exist"
|
||||
}
|
||||
}
|
||||
|
||||
smtp tcp://0.0.0.0:25 {
|
||||
limits {
|
||||
all rate 20 1s
|
||||
all concurrency 10
|
||||
}
|
||||
dmarc yes
|
||||
check {
|
||||
require_mx_record
|
||||
dkim
|
||||
spf
|
||||
}
|
||||
source $(local_domains) {
|
||||
reject 501 5.1.8 "Use Submission for outgoing SMTP"
|
||||
}
|
||||
default_source {
|
||||
destination postmaster $(local_domains) {
|
||||
deliver_to &local_routing
|
||||
}
|
||||
default_destination {
|
||||
reject 550 5.1.1 "User doesn't exist"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
submission tcp://0.0.0.0:587 {
|
||||
limits {
|
||||
all rate 50 1s
|
||||
}
|
||||
auth &local_authdb
|
||||
source $(local_domains) {
|
||||
check {
|
||||
authorize_sender {
|
||||
prepare_email &local_rewrites
|
||||
user_to_email identity
|
||||
}
|
||||
}
|
||||
destination postmaster $(local_domains) {
|
||||
deliver_to &local_routing
|
||||
}
|
||||
default_destination {
|
||||
modify {
|
||||
dkim $(primary_domain) $(local_domains) default
|
||||
}
|
||||
deliver_to &remote_queue
|
||||
}
|
||||
}
|
||||
default_source {
|
||||
reject 501 5.1.8 "Non-local sender domain"
|
||||
}
|
||||
}
|
||||
|
||||
target.remote outbound_delivery {
|
||||
limits {
|
||||
destination rate 20 1s
|
||||
destination concurrency 10
|
||||
}
|
||||
mx_auth {
|
||||
dane
|
||||
mtasts {
|
||||
cache fs
|
||||
fs_dir mtasts_cache/
|
||||
}
|
||||
local_policy {
|
||||
min_tls_level encrypted
|
||||
min_mx_level none
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
target.queue remote_queue {
|
||||
target &outbound_delivery
|
||||
autogenerated_msg_domain $(primary_domain)
|
||||
bounce {
|
||||
destination postmaster $(local_domains) {
|
||||
deliver_to &local_routing
|
||||
}
|
||||
default_destination {
|
||||
reject 550 5.0.0 "Refusing to send DSNs to non-local addresses"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
imap tcp://0.0.0.0:143 {
|
||||
auth &local_authdb
|
||||
storage &local_mailboxes
|
||||
}
|
||||
'';
|
||||
|
||||
};
|
||||
|
||||
services.rspamd = {
|
||||
|
|
|
@ -32,15 +32,4 @@
|
|||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
||||
|
||||
# Caddy reverse proxy for local services like cups
|
||||
services.caddy = {
|
||||
enable = true;
|
||||
globalConfig = ''
|
||||
default_bind 128.140.109.213 2a01:4f8:c2c:b60::
|
||||
# auto_https off
|
||||
email acme@benjaminbaedorf.eu
|
||||
# acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
|
23
hosts/frikandel/nginx.nix
Normal file
23
hosts/frikandel/nginx.nix
Normal file
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
flake,
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: {
|
||||
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
|
||||
recommendedOptimisation = true;
|
||||
recommendedGzipSettings = true;
|
||||
recommendedTlsSettings = true;
|
||||
recommendedProxySettings = true;
|
||||
|
||||
defaultListenAddresses = [
|
||||
"128.140.109.213"
|
||||
"[2a01:4f8:c2c:b60::]"
|
||||
];
|
||||
};
|
||||
}
|
|
@ -22,25 +22,27 @@
|
|||
'';
|
||||
};
|
||||
in {
|
||||
services.caddy.virtualHosts = {
|
||||
security.acme.certs = {
|
||||
"benjaminbaedorf.eu" = {};
|
||||
"b12f.io" = {};
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts = {
|
||||
"benjaminbaedorf.eu" = {
|
||||
extraConfig = ''
|
||||
redir https://b12f.io{uri} temporary
|
||||
'';
|
||||
forceSSL = true;
|
||||
useACMEHost = "benjaminbaedorf.eu";
|
||||
locations."/".return = "302 https://b12f.io$request_uri";
|
||||
};
|
||||
|
||||
"b12f.io" = {
|
||||
extraConfig = ''
|
||||
handle {
|
||||
root * ${bbeu}
|
||||
try_files {path}.html {path}
|
||||
file_server
|
||||
}
|
||||
forceSSL = true;
|
||||
useACMEHost = "b12f.io";
|
||||
|
||||
handle_errors {
|
||||
respond "{http.error.status_code} {http.error.status_text}"
|
||||
}
|
||||
'';
|
||||
locations."/" = {
|
||||
root = bbeu;
|
||||
index = "index.html";
|
||||
tryFiles = "$uri $uri/ =404";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
{
|
||||
flake,
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
psCfg = config.pub-solar;
|
||||
xdg = config.home-manager.users."${psCfg.user.name}".xdg;
|
||||
|
||||
getIP4 = with pkgs; writeShellScriptBin "getIP" ''
|
||||
${curl}/bin/curl -4 https://ipcheck-ds.wieistmeineip.de/callback/ | ${coreutils}/bin/tail -c +2 | ${coreutils}/bin/head -c -1 | ${jq}/bin/jq '.ip' -r
|
||||
'';
|
||||
getIP6 = with pkgs; writeShellScriptBin "getIP" ''
|
||||
echo "2a02:908:5b1:e3c0:2::"
|
||||
'';
|
||||
in {
|
||||
imports = [
|
||||
flake.self.nixosModules.ddclient
|
||||
];
|
||||
|
||||
services.ddclient = {
|
||||
enable = true;
|
||||
protocol = "dyndns1";
|
||||
domains = [
|
||||
"pie.b12f.io"
|
||||
"droppie.b12f.io"
|
||||
];
|
||||
server = "ddns.hosting.de";
|
||||
username = "b12f";
|
||||
usev4 = "cmdv4, cmdv4=${getIP4}/bin/getIP";
|
||||
usev6 = "cmdv6, cmdv6=${getIP6}/bin/getIP";
|
||||
verbose = true;
|
||||
passwordFile = "/run/agenix/dyndns.key";
|
||||
interval = "1min";
|
||||
};
|
||||
|
||||
age.secrets."dyndns.key" = {
|
||||
file = "${flake.self}/secrets/dyndns.key.age";
|
||||
mode = "400";
|
||||
owner = "root";
|
||||
};
|
||||
}
|
|
@ -4,12 +4,12 @@
|
|||
./configuration.nix
|
||||
|
||||
./networking.nix
|
||||
./nginx.nix
|
||||
./wireguard.nix
|
||||
./backup.nix
|
||||
./unbound.nix
|
||||
./dhcpd.nix
|
||||
./wake-droppie.nix
|
||||
./ddclient.nix
|
||||
./paperless.nix
|
||||
./firefly.nix
|
||||
./invoiceplane.nix
|
||||
|
|
|
@ -29,24 +29,22 @@ in {
|
|||
mode = "400";
|
||||
};
|
||||
|
||||
services.caddy = {
|
||||
enable = true;
|
||||
extraConfig = ''
|
||||
firefly.b12f.io {
|
||||
reverse_proxy 127.0.0.1:8080
|
||||
security.acme.certs = {
|
||||
"firefly.b12f.io" = {};
|
||||
"firefly-importer.b12f.io" = {};
|
||||
};
|
||||
|
||||
basicauth * {
|
||||
b12f $2a$05$/xM7USOzLczswXmiacO6UOdg1YNPIw/KJMbMVerEkpsCtNUFwte4a
|
||||
}
|
||||
}
|
||||
firefly-importer.b12f.io {
|
||||
reverse_proxy 127.0.0.1:8081
|
||||
|
||||
basicauth * {
|
||||
b12f $2a$05$/xM7USOzLczswXmiacO6UOdg1YNPIw/KJMbMVerEkpsCtNUFwte4a
|
||||
}
|
||||
}
|
||||
'';
|
||||
services.nginx.virtualHosts = {
|
||||
"firefly.b12f.io" = {
|
||||
forceSSL = true;
|
||||
useACMEHost = "firefly.b12f.io";
|
||||
locations."/".proxyPass = "http://127.0.0.1:8080";
|
||||
};
|
||||
"firefly-importer.b12f.io" = {
|
||||
forceSSL = true;
|
||||
useACMEHost = "firefly.b12f.io";
|
||||
locations."/".proxyPass = "http://127.0.0.1:8081";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services."docker-network-firefly" = let
|
||||
|
|
|
@ -20,7 +20,20 @@ in {
|
|||
mode = "400";
|
||||
};
|
||||
|
||||
security.acme.certs = {
|
||||
"invoicing.b12f.io" = {};
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts = {
|
||||
"invoicing.b12f.io" = {
|
||||
forceSSL = true;
|
||||
useACMEHost = "invoicing.b12f.io";
|
||||
};
|
||||
};
|
||||
|
||||
services.invoiceplane.webserver = "nginx";
|
||||
services.invoiceplane.sites."invoicing.b12f.io" = {
|
||||
# nginx is not supported
|
||||
enable = true;
|
||||
|
||||
database = {
|
||||
|
|
|
@ -24,17 +24,5 @@
|
|||
];
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
||||
|
||||
services.openssh.openFirewall = true;
|
||||
|
||||
# Caddy reverse proxy for local services like cups
|
||||
services.caddy = {
|
||||
globalConfig = ''
|
||||
default_bind 192.168.178.2 2a02:908:5b1:e3c0:2:: 10.0.1.2 fd00:b12f:acab:1312:acab:2::
|
||||
# auto_https off
|
||||
email acme@benjaminbaedorf.eu
|
||||
# acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
|
25
hosts/pie/nginx.nix
Normal file
25
hosts/pie/nginx.nix
Normal file
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
flake,
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: {
|
||||
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
|
||||
recommendedOptimisation = true;
|
||||
recommendedGzipSettings = true;
|
||||
recommendedTlsSettings = true;
|
||||
recommendedProxySettings = true;
|
||||
|
||||
defaultListenAddresses = [
|
||||
"192.168.178.2"
|
||||
# "2a02:908:5b1:e3c0:2::"
|
||||
"10.0.1.2"
|
||||
"[fd00:b12f:acab:1312:acab:2::]"
|
||||
];
|
||||
};
|
||||
}
|
|
@ -47,18 +47,16 @@ in {
|
|||
};
|
||||
};
|
||||
|
||||
services.caddy = {
|
||||
enable = true;
|
||||
extraConfig = ''
|
||||
paperless.b12f.io {
|
||||
request_header Host localhost:${builtins.toString config.services.paperless.port}
|
||||
reverse_proxy 127.0.0.1:${builtins.toString config.services.paperless.port}
|
||||
security.acme.certs = {
|
||||
"paperless.b12f.io" = {};
|
||||
};
|
||||
|
||||
basicauth * {
|
||||
b12f $2a$05$/xM7USOzLczswXmiacO6UOdg1YNPIw/KJMbMVerEkpsCtNUFwte4a
|
||||
}
|
||||
}
|
||||
'';
|
||||
services.nginx.virtualHosts = {
|
||||
"paperless.b12f.io" = {
|
||||
forceSSL = true;
|
||||
useACMEHost = "paperless.b12f.io";
|
||||
locations."/".proxyPass = "http://127.0.0.1:${builtins.toString config.services.paperless.port}";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
|
|
|
@ -61,16 +61,13 @@
|
|||
"fd00:b12f:acab:1312::/64 allow"
|
||||
];
|
||||
local-zone = [
|
||||
"\"b12f.io\" static"
|
||||
"\"b12f.io\" transparent"
|
||||
"\"local\" static"
|
||||
"\"box\" static"
|
||||
];
|
||||
local-data = [
|
||||
"\"brwb8763f64a364.local. 10800 IN A 192.168.178.4\""
|
||||
|
||||
"\"droppie.local. 10800 IN A 192.168.178.3\""
|
||||
"\"droppie.local. 10800 IN AAAA 2a02:908:5b1:e3c0:3::\""
|
||||
|
||||
"\"droppie.b12f.io. 10800 IN A 10.0.1.3\""
|
||||
"\"droppie.b12f.io. 10800 IN AAAA fd00:b12f:acab:1312:acab:3::\""
|
||||
"\"backup.b12f.io. 10800 IN A 10.0.1.3\""
|
||||
|
@ -102,6 +99,7 @@
|
|||
|
||||
tls-cert-bundle = "/etc/ssl/certs/ca-certificates.crt";
|
||||
};
|
||||
|
||||
forward-zone = [
|
||||
{
|
||||
name = ".";
|
||||
|
@ -111,7 +109,7 @@
|
|||
"185.253.5.0#dns0.eu"
|
||||
"2a0f:fc81::#dns0.eu"
|
||||
];
|
||||
# forward-tls-upstream = "yes";
|
||||
forward-tls-upstream = "yes";
|
||||
}
|
||||
];
|
||||
|
||||
|
|
27
modules/acme/default.nix
Normal file
27
modules/acme/default.nix
Normal file
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
flake,
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: {
|
||||
age.secrets."hosting-de-acme-secrets" = {
|
||||
file = "${flake.self}/secrets/hosting-de-acme-secrets.age";
|
||||
mode = "400";
|
||||
owner = "acme";
|
||||
};
|
||||
|
||||
security.acme = {
|
||||
acceptTerms = true;
|
||||
|
||||
defaults = {
|
||||
email = "acme@benjaminbaedorf.eu";
|
||||
# server = "https://acme-staging-v02.api.letsencrypt.org/directory";
|
||||
dnsProvider = "hostingde";
|
||||
dnsPropagationCheck = true;
|
||||
credentialsFile = config.age.secrets."hosting-de-acme-secrets".path;
|
||||
group = "nginx";
|
||||
webroot = null;
|
||||
};
|
||||
};
|
||||
}
|
|
@ -9,7 +9,7 @@
|
|||
systemd.services.NetworkManager-wait-online.enable = lib.mkDefault false;
|
||||
systemd.services.systemd-networkd-wait-online.enable = lib.mkDefault false;
|
||||
|
||||
networking.hosts = (flake.self.lib.addLocalHostname ["caddy.local"]) // {
|
||||
networking.hosts = {
|
||||
"128.140.109.213" = [ "vpn.b12f.io" ];
|
||||
"2a01:4f8:c2c:b60::" = [ "vpn.b12f.io" ];
|
||||
"2a02:908:5b1:e3c0:2::" = [ "pie-wg.b12f.io" ];
|
||||
|
|
|
@ -1,245 +0,0 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.services.ddclient;
|
||||
boolToStr = bool: if bool then "yes" else "no";
|
||||
dataDir = "/var/lib/ddclient";
|
||||
StateDirectory = builtins.baseNameOf dataDir;
|
||||
RuntimeDirectory = StateDirectory;
|
||||
|
||||
usev4 = if cfg.usev4 != "" then "usev4=${cfg.usev4}" else "";
|
||||
usev6 = if cfg.usev6 != "" then "usev6=${cfg.usev6}" else "";
|
||||
|
||||
configFile' = pkgs.writeText "ddclient.conf" ''
|
||||
# This file can be used as a template for configFile or is automatically generated by Nix options.
|
||||
use=no
|
||||
${usev4}
|
||||
${usev6}
|
||||
cache=${dataDir}/ddclient.cache
|
||||
foreground=yes
|
||||
login=${cfg.username}
|
||||
password=${if cfg.protocol == "nsupdate" then "/run/${RuntimeDirectory}/ddclient.key" else "@password_placeholder@"}
|
||||
protocol=${cfg.protocol}
|
||||
${lib.optionalString (cfg.script != "") "script=${cfg.script}"}
|
||||
${lib.optionalString (cfg.server != "") "server=${cfg.server}"}
|
||||
${lib.optionalString (cfg.zone != "") "zone=${cfg.zone}"}
|
||||
ssl=${boolToStr cfg.ssl}
|
||||
wildcard=yes
|
||||
quiet=${boolToStr cfg.quiet}
|
||||
verbose=${boolToStr cfg.verbose}
|
||||
${cfg.extraConfig}
|
||||
${lib.concatStringsSep "," cfg.domains}
|
||||
'';
|
||||
configFile = if (cfg.configFile != null) then cfg.configFile else configFile';
|
||||
|
||||
preStart = ''
|
||||
install --mode=600 --owner=$USER ${configFile} /run/${RuntimeDirectory}/ddclient.conf
|
||||
${lib.optionalString (cfg.configFile == null) (if (cfg.protocol == "nsupdate") then ''
|
||||
install --mode=600 --owner=$USER ${cfg.passwordFile} /run/${RuntimeDirectory}/ddclient.key
|
||||
'' else if (cfg.passwordFile != null) then ''
|
||||
"${pkgs.replace-secret}/bin/replace-secret" "@password_placeholder@" "${cfg.passwordFile}" "/run/${RuntimeDirectory}/ddclient.conf"
|
||||
'' else ''
|
||||
sed -i '/^password=@password_placeholder@$/d' /run/${RuntimeDirectory}/ddclient.conf
|
||||
'')}
|
||||
'';
|
||||
in with lib; {
|
||||
disabledModules = [
|
||||
"services/networking/ddclient.nix"
|
||||
];
|
||||
|
||||
imports = [
|
||||
(mkChangedOptionModule [ "services" "ddclient" "domain" ] [ "services" "ddclient" "domains" ]
|
||||
(config:
|
||||
let value = getAttrFromPath [ "services" "ddclient" "domain" ] config;
|
||||
in if value != "" then [ value ] else []))
|
||||
(mkRemovedOptionModule [ "services" "ddclient" "homeDir" ] "")
|
||||
(mkRemovedOptionModule [ "services" "ddclient" "password" ] "Use services.ddclient.passwordFile instead.")
|
||||
];
|
||||
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
services.ddclient = with lib.types; {
|
||||
enable = mkOption {
|
||||
default = false;
|
||||
type = bool;
|
||||
description = lib.mdDoc ''
|
||||
Whether to synchronise your machine's IP address with a dynamic DNS provider (e.g. dyndns.org).
|
||||
'';
|
||||
};
|
||||
|
||||
package = mkOption {
|
||||
type = package;
|
||||
default = pkgs.ddclient;
|
||||
defaultText = lib.literalExpression "pkgs.ddclient";
|
||||
description = lib.mdDoc ''
|
||||
The ddclient executable package run by the service.
|
||||
'';
|
||||
};
|
||||
|
||||
domains = mkOption {
|
||||
default = [ "" ];
|
||||
type = listOf str;
|
||||
description = lib.mdDoc ''
|
||||
Domain name(s) to synchronize.
|
||||
'';
|
||||
};
|
||||
|
||||
username = mkOption {
|
||||
# For `nsupdate` username contains the path to the nsupdate executable
|
||||
default = lib.optionalString (config.services.ddclient.protocol == "nsupdate") "${pkgs.bind.dnsutils}/bin/nsupdate";
|
||||
defaultText = "";
|
||||
type = str;
|
||||
description = lib.mdDoc ''
|
||||
User name.
|
||||
'';
|
||||
};
|
||||
|
||||
passwordFile = mkOption {
|
||||
default = null;
|
||||
type = nullOr str;
|
||||
description = lib.mdDoc ''
|
||||
A file containing the password or a TSIG key in named format when using the nsupdate protocol.
|
||||
'';
|
||||
};
|
||||
|
||||
interval = mkOption {
|
||||
default = "10min";
|
||||
type = str;
|
||||
description = lib.mdDoc ''
|
||||
The interval at which to run the check and update.
|
||||
See {command}`man 7 systemd.time` for the format.
|
||||
'';
|
||||
};
|
||||
|
||||
configFile = mkOption {
|
||||
default = null;
|
||||
type = nullOr path;
|
||||
description = lib.mdDoc ''
|
||||
Path to configuration file.
|
||||
When set this overrides the generated configuration from module options.
|
||||
'';
|
||||
example = "/root/nixos/secrets/ddclient.conf";
|
||||
};
|
||||
|
||||
protocol = mkOption {
|
||||
default = "dyndns2";
|
||||
type = str;
|
||||
description = lib.mdDoc ''
|
||||
Protocol to use with dynamic DNS provider (see https://sourceforge.net/p/ddclient/wiki/protocols).
|
||||
'';
|
||||
};
|
||||
|
||||
server = mkOption {
|
||||
default = "";
|
||||
type = str;
|
||||
description = lib.mdDoc ''
|
||||
Server address.
|
||||
'';
|
||||
};
|
||||
|
||||
ssl = mkOption {
|
||||
default = true;
|
||||
type = bool;
|
||||
description = lib.mdDoc ''
|
||||
Whether to use SSL/TLS to connect to dynamic DNS provider.
|
||||
'';
|
||||
};
|
||||
|
||||
quiet = mkOption {
|
||||
default = false;
|
||||
type = bool;
|
||||
description = lib.mdDoc ''
|
||||
Print no messages for unnecessary updates.
|
||||
'';
|
||||
};
|
||||
|
||||
script = mkOption {
|
||||
default = "";
|
||||
type = str;
|
||||
description = lib.mdDoc ''
|
||||
script as required by some providers.
|
||||
'';
|
||||
};
|
||||
|
||||
usev4 = mkOption {
|
||||
default = "webv4, webv4=checkip.dyndns.com/, webv4-skip='Current IP Address: '";
|
||||
type = str;
|
||||
description = lib.mdDoc ''
|
||||
Method to determine the IP address to send to the dynamic DNS provider.
|
||||
'';
|
||||
};
|
||||
|
||||
usev6 = mkOption {
|
||||
default = "";
|
||||
type = str;
|
||||
description = lib.mdDoc ''
|
||||
Method to determine the IP address to send to the dynamic DNS provider.
|
||||
'';
|
||||
};
|
||||
|
||||
verbose = mkOption {
|
||||
default = false;
|
||||
type = bool;
|
||||
description = lib.mdDoc ''
|
||||
Print verbose information.
|
||||
'';
|
||||
};
|
||||
|
||||
zone = mkOption {
|
||||
default = "";
|
||||
type = str;
|
||||
description = lib.mdDoc ''
|
||||
zone as required by some providers.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
default = "";
|
||||
type = lines;
|
||||
description = lib.mdDoc ''
|
||||
Extra configuration. Contents will be added verbatim to the configuration file.
|
||||
|
||||
::: {.note}
|
||||
`daemon` should not be added here because it does not work great with the systemd-timer approach the service uses.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
###### implementation
|
||||
|
||||
config = mkIf config.services.ddclient.enable {
|
||||
systemd.services.ddclient = {
|
||||
description = "Dynamic DNS Client";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
restartTriggers = optional (cfg.configFile != null) cfg.configFile;
|
||||
|
||||
serviceConfig = {
|
||||
DynamicUser = true;
|
||||
RuntimeDirectoryMode = "0700";
|
||||
inherit RuntimeDirectory;
|
||||
inherit StateDirectory;
|
||||
Type = "oneshot";
|
||||
ExecStartPre = "!${pkgs.writeShellScript "ddclient-prestart" preStart}";
|
||||
ExecStart = "${lib.getBin cfg.package}/bin/ddclient -file /run/${RuntimeDirectory}/ddclient.conf";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.timers.ddclient = {
|
||||
description = "Run ddclient";
|
||||
wantedBy = [ "timers.target" ];
|
||||
timerConfig = {
|
||||
OnBootSec = cfg.interval;
|
||||
OnUnitInactiveSec = cfg.interval;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -5,13 +5,13 @@
|
|||
}: {
|
||||
flake = {
|
||||
nixosModules = rec {
|
||||
acme = import ./acme;
|
||||
adb = import ./adb;
|
||||
arduino = import ./arduino;
|
||||
audio = import ./audio;
|
||||
bluetooth = import ./bluetooth;
|
||||
core = import ./core;
|
||||
crypto = import ./crypto;
|
||||
ddclient = import ./ddclient;
|
||||
desktop-extended = import ./desktop-extended;
|
||||
docker = import ./docker;
|
||||
gaming = import ./gaming;
|
||||
|
|
|
@ -226,7 +226,7 @@ in
|
|||
};
|
||||
|
||||
options.webserver = mkOption {
|
||||
type = types.enum [ "caddy" ];
|
||||
type = types.enum [ "caddy" "nginx" ];
|
||||
default = "caddy";
|
||||
description = lib.mdDoc ''
|
||||
Which webserver to use for virtual host management. Currently only
|
||||
|
@ -358,5 +358,25 @@ in
|
|||
};
|
||||
})
|
||||
|
||||
(mkIf (cfg.webserver == "nginx") {
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
virtualHosts = mapAttrs' (hostName: cfg: (
|
||||
nameValuePair "${hostName}" {
|
||||
locations."/" = {
|
||||
root = "${pkg hostName cfg}";
|
||||
extraConfig = ''
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_pass unix:${config.services.phpfpm.pools."invoiceplane-${hostName}".socket};
|
||||
include ${pkgs.nginx}/conf/fastcgi_params;
|
||||
include ${pkgs.nginx}/conf/fastcgi.conf;
|
||||
'';
|
||||
};
|
||||
}
|
||||
)) eachSite;
|
||||
};
|
||||
})
|
||||
|
||||
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -21,16 +21,4 @@
|
|||
] ++ (if (pkgs.system == "x86_64-linux")
|
||||
then [ pkgs.cups-brother-hl3140cw ]
|
||||
else []);
|
||||
|
||||
networking.hosts = flake.self.lib.addLocalHostname ["cups.local"];
|
||||
|
||||
services.caddy = {
|
||||
enable = true;
|
||||
extraConfig = ''
|
||||
cups.local {
|
||||
request_header Host localhost:631
|
||||
reverse_proxy unix//run/cups/cups.sock
|
||||
}
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
|
|
@ -36,7 +36,6 @@ in buildGoModule rec {
|
|||
src = fetchFromGitHub {
|
||||
owner = "caddyserver";
|
||||
repo = pname;
|
||||
# https://github.com/NixOS/nixpkgs/blob/nixos-21.11/pkgs/servers/caddy/default.nix
|
||||
rev = "v${version}";
|
||||
sha256 = "sha256-xNCxzoNpXkj8WF9+kYJfO18ux8/OhxygkGjA49+Q4vY=";
|
||||
};
|
||||
|
|
22
secrets/hosting-de-acme-secrets.age
Normal file
22
secrets/hosting-de-acme-secrets.age
Normal file
|
@ -0,0 +1,22 @@
|
|||
age-encryption.org/v1
|
||||
-> ssh-ed25519 8bHz7g 0fwjxxgvY3S/2oKgc+RxTWA9AuA7oS1MnMAqG0AZ2x4
|
||||
LReuCNO8r5UMlipXheXT1SLQKlwGMC8Gpu8VtAUI3/4
|
||||
-> ssh-ed25519 n71/yQ fiv1s9XA/ATrK/s8OkenXCCp3mUhn8gzp3I3S8h7BG4
|
||||
XhzPW7aFm41nzr7ZaBSzS2qfQoVttgODXUqPaF+FvPY
|
||||
-> ssh-rsa kFDS0A
|
||||
gLhS2ce3jBP1UbJJt9dJ/4SmkNiL7LBuUik8Zq1WflxHlMqrRslb56Uuc4BJHTlp
|
||||
KGt2zrzRRNEdSJgzJfK+AT1AHCza++C96ZZsxfhDexL/Gx7Lm6Bwp+D/XR9KYxEn
|
||||
UF511OWWjoCbDWldUQr17y5cbiG4z+VlMMOuKox8RWHymG0ABe+kZEOg1GBZ/bLj
|
||||
tUwgxdK/uGGI2/AJIs4tiiemiNo2cMup7fe+wBPqq1b/TcxxTGHfWuJopp3ISl5G
|
||||
Ov7o7/HVCyemFSlBQTF1K3t68rw4a0ZkMcX86RpEtbiRFrEhS2IuGXnwteEnypER
|
||||
OiafhbdIh56TnTvCKuxnTJdG1JobM1c15l9FhownRjKMwVjeQb39LKvQlJAkzGOr
|
||||
eBtkGu42p8UGNpltTawKgWNOTsZNy5BYHvHvS73SXDcuwGVhhP5fbeImUgeBRUyT
|
||||
2DWoK+vethjGL+tX+NNqeKM/Xr+k8QUGq+qehB6UoiTLL4NiwujeO230b9Afsh2/
|
||||
xtzDTMueqTUVTzxA0GbIRSXCKCfDNifdJh6+ebnvizx5NarANvMNlP6sfBQ5gANf
|
||||
N20IhtgnOxQ5l5URWqK/A5vk+cpP2GGkAGoW40m31gyug9AtuguNpEVRpLHJVtRn
|
||||
DpHh5k0EMzWz7iQhYIVavLTh3AtxofLg4wp/cQEkcQg
|
||||
-> OC`4fNF7-grease
|
||||
YhGHL0+BVF6h6InKVlS3
|
||||
--- NXJPtlRt28CuwumxjLQI8qY6i5GSbBPbBANxLpHmsHE
|
||||
‹×€aqê802.æ–´"R=SÙÚȳ ËŽlhª@ÄK¢¨F-³ö=;ž @ìåúiÕ°+àÚr¸£àð;4wI}ÕiËÑèõ1o—™
|
||||
„¼¬ƒN¼ÂÜòG>Tõ3–Œ7
|
Binary file not shown.
Binary file not shown.
|
@ -42,7 +42,7 @@ let
|
|||
];
|
||||
in {
|
||||
"dyndns.key.age".publicKeys = pieKeys ++ baseKeys;
|
||||
"hosting.de-api.key.age".publicKeys = baseKeys;
|
||||
"hosting-de-acme-secrets.age".publicKeys = pieKeys ++ frikandelKeys ++ baseKeys;
|
||||
|
||||
"droppie-ssh-root.key.age".publicKeys = droppieKeys ++ baseKeys;
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ resource "hostingde_record" "b12f-dkim" {
|
|||
zone_id = hostingde_zone.b12f.id
|
||||
name = "default._domainkey.b12f.io"
|
||||
type = "TXT"
|
||||
content = "\"v=DKIM1; k=rsa;\" \"p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyla9hW3TvoXvZQxwzaJ4SZ9ict1HU3E6+FWlwNIgE6tIpTCyRJtiSIUDqB8TLTIBoxIs+QQBXZi+QUi3Agu6OSY2RiV0EwO8+oOOqOD9pERftc/aqe51cXuv4kPqwvpXEBwrXFWVM+VxivEubUJ7eKkFyXJpelv0LslXv/MmYbUyed6dF+reOGZCsvnbiRv74qdxbAL/25j62E8Wr\" \"nxzJwhUtx/JhdBOjsHBvuw9hy6rZsVJL9eXayWyGRV6qmsLRzsRSBs+mDrgmKk4dugADd11+A03ics3i8hplRoWDkqnNKz1qy4f5TsV6v9283IANrAzRfHwX8EvNiFsBz+ZCQIDAQAB\""
|
||||
content = "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyla9hW3TvoXvZQxwzaJ4SZ9ict1HU3E6+FWlwNIgE6tIpTCyRJtiSIUDqB8TLTIBoxIs+QQBXZi+QUi3Agu6OSY2RiV0EwO8+oOOqOD9pERftc/aqe51cXuv4kPqwvpXEBwrXFWVM+VxivEubUJ7eKkFyXJpelv0LslXv/MmYbUyed6dF+reOGZCsvnbiRv74qdxbAL/25j62E8WrnxzJwhUtx/JhdBOjsHBvuw9hy6rZsVJL9eXayWyGRV6qmsLRzsRSBs+mDrgmKk4dugADd11+A03ics3i8hplRoWDkqnNKz1qy4f5TsV6v9283IANrAzRfHwX8EvNiFsBz+ZCQIDAQAB"
|
||||
ttl = 300
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue