refactor(nginx): Clean up nginx configuration
This commit is contained in:
parent
d82c353329
commit
767a14ab6e
8 changed files with 177 additions and 171 deletions
|
|
@ -27,7 +27,7 @@
|
|||
./services/wireguard.nix
|
||||
# ./services/starbound.nix -- Not currently used
|
||||
./services/postgres.nix
|
||||
./nginx.nix
|
||||
./nginx
|
||||
./sops.nix
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -1,77 +0,0 @@
|
|||
{ config, lib, ... }:
|
||||
{
|
||||
services = {
|
||||
nginx = {
|
||||
enable = true;
|
||||
recommendedTlsSettings = true;
|
||||
recommendedOptimisation = true;
|
||||
recommendedGzipSettings = true;
|
||||
recommendedProxySettings = true;
|
||||
clientMaxBodySize = "10G";
|
||||
|
||||
statusPage = true; # For metrics, should be accessible only from localhost
|
||||
|
||||
commonHttpConfig = ''
|
||||
log_format upstream_time '$remote_addr - $remote_user [$time_local] '
|
||||
'"$request" $status $body_bytes_sent '
|
||||
'"$http_referer" "$http_user_agent" '
|
||||
'rt=$request_time uct="$upstream_connect_time" '
|
||||
'uht="$upstream_header_time" urt="$upstream_response_time"';
|
||||
'';
|
||||
};
|
||||
|
||||
logrotate.settings = {
|
||||
# Override the default, just keep fewer logs
|
||||
nginx.rotate = 6;
|
||||
}
|
||||
// lib.mapAttrs' (
|
||||
virtualHost: _:
|
||||
lib.nameValuePair "/var/log/nginx/${virtualHost}/access.log" {
|
||||
frequency = "daily";
|
||||
rotate = 2;
|
||||
compress = true;
|
||||
delaycompress = true;
|
||||
su = "${config.services.nginx.user} ${config.services.nginx.group}";
|
||||
postrotate = "[ ! -f /var/run/nginx/nginx.pid ] || kill -USR1 `cat /var/run/nginx/nginx.pid`";
|
||||
}
|
||||
) config.services.nginx.virtualHosts;
|
||||
|
||||
backups.acme = {
|
||||
user = "acme";
|
||||
paths = lib.mapAttrsToList (
|
||||
virtualHost: _: "/var/lib/acme/${virtualHost}"
|
||||
) config.services.nginx.virtualHosts;
|
||||
};
|
||||
};
|
||||
|
||||
systemd.tmpfiles.rules = lib.mapAttrsToList (
|
||||
virtualHost: _:
|
||||
#
|
||||
"d /var/log/nginx/${virtualHost} 0750 ${config.services.nginx.user} ${config.services.nginx.group}"
|
||||
) config.services.nginx.virtualHosts;
|
||||
|
||||
security.acme = {
|
||||
defaults.email = "tm@tlater.net";
|
||||
acceptTerms = true;
|
||||
|
||||
certs."tlater.net" = {
|
||||
extraDomainNames = [
|
||||
"*.tlater.net"
|
||||
"tlater.com"
|
||||
"*.tlater.com"
|
||||
];
|
||||
dnsProvider = "porkbun";
|
||||
group = "ssl-cert";
|
||||
credentialFiles = {
|
||||
PORKBUN_API_KEY_FILE = config.sops.secrets."porkbun/api-key".path;
|
||||
PORKBUN_SECRET_API_KEY_FILE = config.sops.secrets."porkbun/secret-api-key".path;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
users.groups.ssl-cert = { };
|
||||
|
||||
systemd.services.nginx.serviceConfig.SupplementaryGroups = [
|
||||
config.security.acme.certs."tlater.net".group
|
||||
];
|
||||
}
|
||||
22
configuration/nginx/default.nix
Normal file
22
configuration/nginx/default.nix
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{ lib, ... }:
|
||||
{
|
||||
imports = [
|
||||
./logging.nix
|
||||
./ssl.nix
|
||||
];
|
||||
|
||||
options.services.nginx.domain = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "The base domain name to append to virtual domain names";
|
||||
};
|
||||
|
||||
config.services.nginx = {
|
||||
enable = true;
|
||||
recommendedTlsSettings = true;
|
||||
recommendedOptimisation = true;
|
||||
recommendedGzipSettings = true;
|
||||
recommendedProxySettings = true;
|
||||
clientMaxBodySize = "10G";
|
||||
statusPage = true; # For metrics, should be accessible only from localhost
|
||||
};
|
||||
}
|
||||
84
configuration/nginx/logging.nix
Normal file
84
configuration/nginx/logging.nix
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
{ config, lib, ... }:
|
||||
let
|
||||
hostNames = lib.attrNames config.services.nginx.virtualHosts;
|
||||
logPath = name: "/var/log/nginx/${name}/access.log";
|
||||
logFormat = lib.concatStringsSep " " [
|
||||
"$remote_addr - $remote_user [$time_local]"
|
||||
''"$request" $status $body_bytes_sent''
|
||||
''"$http_referer" "$http_user_agent"''
|
||||
''rt=$request_time uct="$upstream_connect_time"''
|
||||
''uht="$upstream_header_time" urt="$upstream_response_time"''
|
||||
];
|
||||
in
|
||||
{
|
||||
# Extend the default configuration for nginx virtual hosts; we'd
|
||||
# like to create log files for each of them, so that the prometheus
|
||||
# nginxlog exporter can process per-host logs.
|
||||
options.services.nginx.virtualHosts = lib.mkOption {
|
||||
type = lib.types.attrsOf (
|
||||
lib.types.submodule (
|
||||
{ name, ... }:
|
||||
{
|
||||
config.extraConfig = ''
|
||||
access_log ${logPath name} upstream_time;
|
||||
'';
|
||||
}
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
config = {
|
||||
# Create directories for host-specific logs with systemd tmpfiles
|
||||
systemd.tmpfiles.settings."10-nginx-logs" = lib.listToAttrs (
|
||||
map (
|
||||
name:
|
||||
lib.nameValuePair "/var/log/nginx/${name}" {
|
||||
d = {
|
||||
inherit (config.services.nginx) user group;
|
||||
mode = "0750";
|
||||
};
|
||||
}
|
||||
) hostNames
|
||||
);
|
||||
|
||||
services = {
|
||||
# Set the nginx-wide log format
|
||||
nginx.commonHttpConfig = ''
|
||||
log_format upstream_time '${logFormat}';
|
||||
'';
|
||||
|
||||
# Set up nginxlog to read the file and log format defined above
|
||||
# for each virtual host
|
||||
prometheus.exporters.nginxlog = {
|
||||
enable = true;
|
||||
listenAddress = "127.0.0.1";
|
||||
group = "nginx";
|
||||
|
||||
settings.namespaces = map (name: {
|
||||
inherit name;
|
||||
metrics_override.prefix = "nginxlog";
|
||||
namespace_label = "vhost";
|
||||
format = logFormat;
|
||||
source.files = [ (logPath name) ];
|
||||
}) hostNames;
|
||||
};
|
||||
|
||||
logrotate.settings = {
|
||||
# Override the nginx module default, just keep fewer logs
|
||||
nginx.rotate = 6;
|
||||
|
||||
# Configure logrotate for host-specific logs
|
||||
nginxVirtualHosts = {
|
||||
files = map logPath hostNames;
|
||||
|
||||
frequency = "daily";
|
||||
rotate = 2;
|
||||
compress = true;
|
||||
delaycompress = true;
|
||||
su = "${config.services.nginx.user} ${config.services.nginx.group}";
|
||||
postrotate = "[ ! -f /var/run/nginx/nginx.pid ] || kill -USR1 `cat /var/run/nginx/nginx.pid`";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
68
configuration/nginx/ssl.nix
Normal file
68
configuration/nginx/ssl.nix
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
{
|
||||
pkgs,
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
{
|
||||
options = {
|
||||
# Add a custom per-host option to enable HSTS
|
||||
services.nginx.virtualHosts = lib.mkOption {
|
||||
type = lib.types.attrsOf (
|
||||
lib.types.submodule (
|
||||
{ config, ... }:
|
||||
{
|
||||
options.enableHSTS = lib.mkEnableOption "HSTS";
|
||||
config.extraConfig = lib.mkIf config.enableHSTS ''
|
||||
add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
|
||||
'';
|
||||
}
|
||||
)
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
# Certificate settings
|
||||
security.acme = {
|
||||
defaults.email = "tm@tlater.net";
|
||||
acceptTerms = true;
|
||||
|
||||
certs."tlater.net" = {
|
||||
extraDomainNames = [
|
||||
"*.tlater.net"
|
||||
"tlater.com"
|
||||
"*.tlater.com"
|
||||
];
|
||||
dnsProvider = "porkbun";
|
||||
group = config.users.groups.ssl-cert.name;
|
||||
credentialFiles = {
|
||||
PORKBUN_API_KEY_FILE = config.sops.secrets."porkbun/api-key".path;
|
||||
PORKBUN_SECRET_API_KEY_FILE = config.sops.secrets."porkbun/secret-api-key".path;
|
||||
};
|
||||
};
|
||||
};
|
||||
users.groups.ssl-cert = { };
|
||||
|
||||
# Back up the SSL certificate, just in case
|
||||
services.backups.acme = {
|
||||
user = "acme";
|
||||
paths = [ "/var/lib/acme/tlater.net" ];
|
||||
};
|
||||
|
||||
systemd.services = {
|
||||
nginx.serviceConfig.SupplementaryGroups = [ config.security.acme.certs."tlater.net".group ];
|
||||
|
||||
# Don't attempt to retrieve a certificate if the domain name
|
||||
# doesn't *actually* match the cert name
|
||||
#
|
||||
# TODO(tlater): Set up pebble to retrieve certs "properly"
|
||||
# instead
|
||||
"acme-tlater.net".serviceConfig.ExecCondition =
|
||||
let
|
||||
confirm = ''[[ "tlater.net" = "${config.services.nginx.domain}" ]]'';
|
||||
in
|
||||
''${pkgs.runtimeShell} -c '${confirm}' '';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -1,9 +1,4 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
{ pkgs, ... }:
|
||||
let
|
||||
yaml = pkgs.formats.yaml { };
|
||||
in
|
||||
|
|
@ -68,28 +63,6 @@ in
|
|||
enable = true;
|
||||
listenAddress = "127.0.0.1";
|
||||
};
|
||||
|
||||
nginxlog = {
|
||||
enable = true;
|
||||
listenAddress = "127.0.0.1";
|
||||
group = "nginx";
|
||||
|
||||
settings.namespaces = lib.mapAttrsToList (name: _: {
|
||||
inherit name;
|
||||
metrics_override.prefix = "nginxlog";
|
||||
namespace_label = "vhost";
|
||||
|
||||
format = lib.concatStringsSep " " [
|
||||
"$remote_addr - $remote_user [$time_local]"
|
||||
''"$request" $status $body_bytes_sent''
|
||||
''"$http_referer" "$http_user_agent"''
|
||||
''rt=$request_time uct="$upstream_connect_time"''
|
||||
''uht="$upstream_header_time" urt="$upstream_response_time"''
|
||||
];
|
||||
|
||||
source.files = [ "/var/log/nginx/${name}/access.log" ];
|
||||
}) config.services.nginx.virtualHosts;
|
||||
};
|
||||
};
|
||||
|
||||
# TODO(tlater):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue