feat[server]: improve nginx config

This commit is contained in:
Leon Schwarzäugl 2025-11-17 22:45:08 +01:00
parent 6d930c3fa4
commit 4464041c31
Signed by: swarsel
GPG key ID: 26A54C31F2A4FD84
2 changed files with 192 additions and 2 deletions

View file

@ -7049,9 +7049,60 @@ Here we just define some aliases for rebuilding the system, and we allow some in
inherit (config.repo.secrets.common) dnsProvider;
inherit (config.repo.secrets.common.mail) address3;
serviceUser = "nginx";
serviceGroup = serviceUser;
sslBasePath = "/etc/ssl";
dhParamsPathBase = "${sslBasePath}/dhparams.pem";
dhParamsPath =
if config.swarselsystems.isImpermanence then
"/persist/${dhParamsPathBase}"
else
"${dhParamsPathBase}";
in
{
options.swarselmodules.server.nginx = lib.mkEnableOption "enable nginx on server";
options.services.nginx = {
recommendedSecurityHeaders = lib.mkEnableOption "additional security headers by default in each location block.";
virtualHosts = lib.mkOption {
type = lib.types.attrsOf (
lib.types.submodule {
options.locations = lib.mkOption {
type = lib.types.attrsOf (
lib.types.submodule (submod: {
options = {
recommendedSecurityHeaders = lib.mkOption {
type = lib.types.bool;
default = config.services.nginx.recommendedSecurityHeaders;
description = "Whether to add additional security headers to this location.";
};
X-Frame-Options = lib.mkOption {
type = lib.types.str;
default = "DENY";
description = "The value to use for X-Frame-Options";
};
};
config = lib.mkIf submod.config.recommendedSecurityHeaders {
extraConfig = lib.mkBefore ''
# Enable HTTP Strict Transport Security (HSTS)
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
# Minimize information leaked to other domains
add_header Referrer-Policy "origin-when-cross-origin";
add_header X-XSS-Protection "1; mode=block";
add_header X-Frame-Options "${submod.config.X-Frame-Options}";
add_header X-Content-Type-Options "nosniff";
'';
};
})
);
};
}
);
};
};
config = lib.mkIf config.swarselmodules.server.nginx {
environment.systemPackages = with pkgs; [
lego
@ -7064,24 +7115,68 @@ Here we just define some aliases for rebuilding the system, and we allow some in
'';
};
users.groups.acme.members = [ "nginx" ];
security.acme = {
acceptTerms = true;
defaults = {
inherit dnsProvider;
email = address3;
environmentFile = "${config.sops.templates."certs.secret".path}";
reloadServices = [ "nginx" ];
dnsPropagationCheck = true;
};
};
networking.firewall.allowedTCPPorts = [ 80 443 ];
environment.persistence."/persist" = lib.mkIf config.swarselsystems.isImpermanence {
files = [ dhParamsPathBase ];
};
services.nginx = {
enable = true;
user = serviceUser;
group = serviceGroup;
statusPage = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
recommendedOptimisation = true;
recommendedGzipSettings = true;
# virtualHosts are defined in the respective sections
recommendedBrotliSettings = true;
recommendedSecurityHeaders = true;
sslCiphers = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:!aNULL";
sslDhparam = dhParamsPathBase;
virtualHosts.fallback = {
default = true;
rejectSSL = true;
locations."/".extraConfig = ''
deny all;
'';
};
};
system.activationScripts."createPersistentStorageDirs" = lib.mkIf config.swarselsystems.isImpermanence {
deps = [ "generateDHParams" "users" "groups" ];
};
system.activationScripts."generateDHParams" =
{
text = ''
set -eu
${pkgs.coreutils}/bin/install -d -m 0755 ${sslBasePath}
${if config.swarselsystems.isImpermanence then "${pkgs.coreutils}/bin/install -d -m 0755 /persist${sslBasePath}" else ""}
if [ ! -f "${dhParamsPathBase}" ]; then
${pkgs.openssl}/bin/openssl dhparam -out ${dhParamsPath} 4096
chmod 0644 ${dhParamsPath}
chown ${serviceUser}:${serviceGroup} ${dhParamsPath}
fi
'';
deps = [
"etc"
(lib.mkIf config.swarselsystems.isImpermanence "specialfs")
];
};
};
}
#+end_src

View file

@ -3,9 +3,60 @@ let
inherit (config.repo.secrets.common) dnsProvider;
inherit (config.repo.secrets.common.mail) address3;
serviceUser = "nginx";
serviceGroup = serviceUser;
sslBasePath = "/etc/ssl";
dhParamsPathBase = "${sslBasePath}/dhparams.pem";
dhParamsPath =
if config.swarselsystems.isImpermanence then
"/persist/${dhParamsPathBase}"
else
"${dhParamsPathBase}";
in
{
options.swarselmodules.server.nginx = lib.mkEnableOption "enable nginx on server";
options.services.nginx = {
recommendedSecurityHeaders = lib.mkEnableOption "additional security headers by default in each location block.";
virtualHosts = lib.mkOption {
type = lib.types.attrsOf (
lib.types.submodule {
options.locations = lib.mkOption {
type = lib.types.attrsOf (
lib.types.submodule (submod: {
options = {
recommendedSecurityHeaders = lib.mkOption {
type = lib.types.bool;
default = config.services.nginx.recommendedSecurityHeaders;
description = "Whether to add additional security headers to this location.";
};
X-Frame-Options = lib.mkOption {
type = lib.types.str;
default = "DENY";
description = "The value to use for X-Frame-Options";
};
};
config = lib.mkIf submod.config.recommendedSecurityHeaders {
extraConfig = lib.mkBefore ''
# Enable HTTP Strict Transport Security (HSTS)
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
# Minimize information leaked to other domains
add_header Referrer-Policy "origin-when-cross-origin";
add_header X-XSS-Protection "1; mode=block";
add_header X-Frame-Options "${submod.config.X-Frame-Options}";
add_header X-Content-Type-Options "nosniff";
'';
};
})
);
};
}
);
};
};
config = lib.mkIf config.swarselmodules.server.nginx {
environment.systemPackages = with pkgs; [
lego
@ -18,23 +69,67 @@ in
'';
};
users.groups.acme.members = [ "nginx" ];
security.acme = {
acceptTerms = true;
defaults = {
inherit dnsProvider;
email = address3;
environmentFile = "${config.sops.templates."certs.secret".path}";
reloadServices = [ "nginx" ];
dnsPropagationCheck = true;
};
};
networking.firewall.allowedTCPPorts = [ 80 443 ];
environment.persistence."/persist" = lib.mkIf config.swarselsystems.isImpermanence {
files = [ dhParamsPathBase ];
};
services.nginx = {
enable = true;
user = serviceUser;
group = serviceGroup;
statusPage = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
recommendedOptimisation = true;
recommendedGzipSettings = true;
# virtualHosts are defined in the respective sections
recommendedBrotliSettings = true;
recommendedSecurityHeaders = true;
sslCiphers = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:!aNULL";
sslDhparam = dhParamsPathBase;
virtualHosts.fallback = {
default = true;
rejectSSL = true;
locations."/".extraConfig = ''
deny all;
'';
};
};
system.activationScripts."createPersistentStorageDirs" = lib.mkIf config.swarselsystems.isImpermanence {
deps = [ "generateDHParams" "users" "groups" ];
};
system.activationScripts."generateDHParams" =
{
text = ''
set -eu
${pkgs.coreutils}/bin/install -d -m 0755 ${sslBasePath}
${if config.swarselsystems.isImpermanence then "${pkgs.coreutils}/bin/install -d -m 0755 /persist${sslBasePath}" else ""}
if [ ! -f "${dhParamsPathBase}" ]; then
${pkgs.openssl}/bin/openssl dhparam -out ${dhParamsPath} 4096
chmod 0644 ${dhParamsPath}
chown ${serviceUser}:${serviceGroup} ${dhParamsPath}
fi
'';
deps = [
"etc"
(lib.mkIf config.swarselsystems.isImpermanence "specialfs")
];
};
};
}