This should enable DNS-01 acme for all khs openstack servers, thus removing the pain of setting up acme for those servers. Do note that this might not really be needed that much anymore, as I should be able to hit them over IPv6, but for ease of mind, this will enable ACME trivially, also for non https workloads, as well as servers without open ports. Do note that currently there's a global unifi firewall rule in place to allow port 80 and 443 to my own servers over ipv6, I'd like to remove this and have Nix configure firewall rules for each server individually, as requested in the setup.
141 lines
4.9 KiB
Nix
141 lines
4.9 KiB
Nix
{
|
|
config,
|
|
lib,
|
|
pkgs,
|
|
modulesPath,
|
|
...
|
|
}:
|
|
let
|
|
cfg = config.khscodes.services.nginx;
|
|
locationOptions = import "${modulesPath}/services/web-servers/nginx/location-options.nix" {
|
|
inherit lib config;
|
|
};
|
|
vhostOption = lib.khscodes.mkSubmodule {
|
|
description = "nginx vhost";
|
|
options = {
|
|
acme = lib.mkOption {
|
|
description = "If a simple certificate for the virtual host name itself is not desired auto configured, then set this option. If set to a string it will be used as `useAcmeHost` from NixOS nginx service configuration. Otherwise set to the acme submodule and configure the desired certificate that way";
|
|
type = lib.types.nullOr (
|
|
lib.types.oneOf [
|
|
lib.types.str
|
|
(lib.types.mkSubmodule {
|
|
description = "acme certificate";
|
|
options = {
|
|
domains = lib.mkOption {
|
|
type = lib.types.listOf lib.types.str;
|
|
description = "Domain names the certificate should be requested for, should include the virtual host itself";
|
|
};
|
|
};
|
|
})
|
|
]
|
|
);
|
|
default = null;
|
|
};
|
|
globalRedirect = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.str;
|
|
default = null;
|
|
description = "If set, all requests for this host are redirected (defaults to 301, configurable with redirectCode) to the given hostname.";
|
|
};
|
|
redirectCode = lib.mkOption {
|
|
type = lib.types.int;
|
|
default = 301;
|
|
description = "HTTP status used by globalRedirect and forceSSL. Possible usecases include temporary (302, 307) redirects, keeping the request method and body (307, 308), or explicitly resetting the method to GET (303). See https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections.";
|
|
};
|
|
extraConfig = lib.mkOption {
|
|
type = lib.types.lines;
|
|
description = "Extra configuration to inject into the generated nginx config";
|
|
default = '''';
|
|
};
|
|
locations = lib.mkOption {
|
|
type = lib.types.attrsOf (
|
|
lib.khscodes.mkSubmodule {
|
|
description = "nginx virtual host location";
|
|
options = locationOptions;
|
|
}
|
|
);
|
|
default = { };
|
|
};
|
|
};
|
|
};
|
|
dns01Enabled = config.khscodes.security.acme.dns01Enabled;
|
|
useAcmeConfiguration = lib.attrsets.foldlAttrs (
|
|
acc: name: item:
|
|
acc || (item.acme != null && !lib.attrsets.isAttrs item.acme)
|
|
) false cfg.virtualHosts;
|
|
in
|
|
{
|
|
options.khscodes.services.nginx = {
|
|
enable = lib.mkEnableOption "Enables nginx";
|
|
virtualHosts = lib.mkOption {
|
|
type = lib.types.attrsOf vhostOption;
|
|
description = "Virtual hosts settings";
|
|
default = { };
|
|
};
|
|
};
|
|
config = lib.mkIf cfg.enable {
|
|
assertions = [
|
|
{
|
|
assertion = !useAcmeConfiguration || dns01Enabled;
|
|
message = "Cannot use `config.khscodes.services.nginx.virtualHosts.<name>.acme = {}` without setting config.khscodes.security.acme.dns01Enabled";
|
|
}
|
|
];
|
|
khscodes.security.acme.enable = true;
|
|
security.dhparams.enable = true;
|
|
security.dhparams.params."nginx".bits = 4096;
|
|
services.nginx = {
|
|
enable = true;
|
|
package = lib.mkDefault pkgs.nginxStable;
|
|
sslDhparam = lib.mkDefault "${config.security.dhparams.params."nginx".path}";
|
|
recommendedTlsSettings = lib.mkDefault true;
|
|
recommendedGzipSettings = lib.mkDefault true;
|
|
recommendedOptimisation = lib.mkDefault true;
|
|
recommendedZstdSettings = lib.mkDefault true;
|
|
recommendedProxySettings = lib.mkDefault true;
|
|
virtualHosts = lib.attrsets.mapAttrs (name: value: {
|
|
inherit (value)
|
|
extraConfig
|
|
locations
|
|
globalRedirect
|
|
redirectCode
|
|
;
|
|
forceSSL = true;
|
|
enableACME = value.acme == null && !dns01Enabled;
|
|
useACMEHost =
|
|
if lib.strings.isString value.acme then
|
|
value.acme
|
|
else if lib.attrsets.isAttrs value.acme || dns01Enabled then
|
|
name
|
|
else
|
|
null;
|
|
}) cfg.virtualHosts;
|
|
};
|
|
networking.firewall.allowedTCPPorts = [
|
|
80
|
|
443
|
|
];
|
|
networking.firewall.allowedUDPPorts = [ 443 ];
|
|
users.users.nginx.extraGroups = lib.lists.optional dns01Enabled "acme";
|
|
security.acme.certs = lib.mkIf dns01Enabled (
|
|
lib.attrsets.foldlAttrs (
|
|
acc: name: value:
|
|
(
|
|
acc
|
|
// (lib.attrsets.optionalAttrs (lib.attrsets.isAttrs value.acme || dns01Enabled) {
|
|
"${name}" =
|
|
if value.acme == null then
|
|
{
|
|
domain = name;
|
|
reloadServices = [ "nginx" ];
|
|
}
|
|
else
|
|
{
|
|
domain = lib.lists.head value.acme.domains;
|
|
extraDomainNames = lib.lists.tail value.acme.domains;
|
|
reloadServices = [ "nginx" ];
|
|
};
|
|
})
|
|
)
|
|
) { } cfg.virtualHosts
|
|
);
|
|
};
|
|
}
|