211 lines
5.9 KiB
Nix
211 lines
5.9 KiB
Nix
{
|
|
name,
|
|
hostInfo,
|
|
dsl,
|
|
lib,
|
|
containers,
|
|
...
|
|
}:
|
|
let
|
|
inherit (dsl) mkContainer collectContainers;
|
|
inherit (hostInfo.paths) data;
|
|
|
|
mkNginxConfig =
|
|
{
|
|
email,
|
|
vhosts,
|
|
resolver,
|
|
}:
|
|
let
|
|
mkVhostEntries =
|
|
{
|
|
domain,
|
|
upstream ? null,
|
|
websockets ? true,
|
|
redirect ? true,
|
|
listenHttp ? false,
|
|
extraLocations ? { },
|
|
}:
|
|
let
|
|
httpsListen = {
|
|
addr = "0.0.0.0";
|
|
port = 443;
|
|
ssl = true;
|
|
};
|
|
httpListen = {
|
|
addr = "0.0.0.0";
|
|
port = 80;
|
|
ssl = false;
|
|
};
|
|
defaultLoc = lib.optionalAttrs (upstream != null) {
|
|
"/" = {
|
|
proxyWebsockets = websockets;
|
|
extraConfig = ''
|
|
set $backend "${upstream.container.name}:${toString upstream.port}";
|
|
proxy_pass http://$backend;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
proxy_set_header X-Forwarded-Host $host;
|
|
proxy_set_header X-Forwarded-Server $hostname;
|
|
'';
|
|
};
|
|
};
|
|
acmePrimaryOnMain = !redirect && listenHttp;
|
|
mainVhost = lib.nameValuePair domain (
|
|
{
|
|
listen = [ httpsListen ] ++ lib.optional listenHttp httpListen;
|
|
locations = defaultLoc // extraLocations;
|
|
}
|
|
// (
|
|
if acmePrimaryOnMain then
|
|
{
|
|
addSSL = true;
|
|
enableACME = true;
|
|
}
|
|
else
|
|
{
|
|
onlySSL = true;
|
|
useACMEHost = domain;
|
|
}
|
|
)
|
|
);
|
|
redirectVhost = lib.nameValuePair "${domain}-redirect" {
|
|
serverName = domain;
|
|
enableACME = true;
|
|
listen = [ httpListen ];
|
|
locations = {
|
|
"/" = {
|
|
return = "301 https://$host$request_uri";
|
|
};
|
|
};
|
|
};
|
|
in
|
|
[ mainVhost ] ++ lib.optional redirect redirectVhost;
|
|
in
|
|
{
|
|
access = map (v: {
|
|
to = v.upstream.container.name;
|
|
tcp = [ v.upstream.port ];
|
|
}) (lib.filter (v: v.upstream or null != null) vhosts);
|
|
|
|
containerConfig =
|
|
{
|
|
lib,
|
|
config,
|
|
...
|
|
}:
|
|
{
|
|
services.nginx = {
|
|
enable = true;
|
|
recommendedTlsSettings = true;
|
|
recommendedOptimisation = true;
|
|
recommendedGzipSettings = true;
|
|
recommendedProxySettings = true;
|
|
clientMaxBodySize = "100M";
|
|
appendHttpConfig = ''
|
|
access_log syslog:server=unix:/dev/log,tag=nginx combined;
|
|
'';
|
|
resolver = {
|
|
addresses = [ resolver ];
|
|
ipv6 = false;
|
|
valid = "30s";
|
|
};
|
|
virtualHosts = lib.listToAttrs (lib.concatLists (map mkVhostEntries vhosts)) // {
|
|
"_" = {
|
|
listen = [
|
|
{
|
|
addr = "0.0.0.0";
|
|
port = 443;
|
|
extraParameters = [
|
|
"ssl"
|
|
"default_server"
|
|
];
|
|
}
|
|
{
|
|
addr = "0.0.0.0";
|
|
port = 80;
|
|
extraParameters = [ "default_server" ];
|
|
}
|
|
];
|
|
extraConfig = "ssl_reject_handshake on;";
|
|
locations."/".return = "404";
|
|
};
|
|
};
|
|
};
|
|
security.acme = {
|
|
acceptTerms = true;
|
|
defaults.email = email;
|
|
};
|
|
systemd.services =
|
|
lib.mapAttrs' (
|
|
cert: _:
|
|
lib.nameValuePair "acme-${cert}" {
|
|
after = [ "container-ready.target" ];
|
|
wants = [ "container-ready.target" ];
|
|
}
|
|
) config.security.acme.certs
|
|
// {
|
|
nginx.serviceConfig.FailureAction = "exit-force";
|
|
};
|
|
};
|
|
};
|
|
|
|
up = container: port: { inherit container port; };
|
|
|
|
discovered = collectContainers "nginx" containers;
|
|
|
|
discoveredVhosts = map (
|
|
{ container, data }:
|
|
{
|
|
inherit (data) domain;
|
|
}
|
|
// lib.optionalAttrs (data ? port) { upstream = up container data.port; }
|
|
// lib.optionalAttrs (data ? websockets) { inherit (data) websockets; }
|
|
// lib.optionalAttrs (data ? redirect) { inherit (data) redirect; }
|
|
// lib.optionalAttrs (data ? listenHttp) { inherit (data) listenHttp; }
|
|
// lib.optionalAttrs (data ? extraLocations) { inherit (data) extraLocations; }
|
|
) discovered;
|
|
|
|
extraVhosts = [
|
|
{
|
|
domain = "utils.floweytf.com";
|
|
redirect = false;
|
|
listenHttp = true;
|
|
extraLocations = {
|
|
"/static/" = {
|
|
alias = "/usr/share/nginx/static/";
|
|
extraConfig = "autoindex on;";
|
|
};
|
|
};
|
|
}
|
|
];
|
|
|
|
upstreamContainers = map (e: e.container) (lib.filter ({ data, ... }: data ? port) discovered);
|
|
|
|
setup = mkNginxConfig {
|
|
email = "floweydev@gmail.com";
|
|
resolver = hostAddr;
|
|
vhosts = discoveredVhosts ++ extraVhosts;
|
|
};
|
|
c = mkContainer {
|
|
inherit name;
|
|
net.access = setup.access ++ [ { to = "@internet"; } ];
|
|
svc.autoStart = true;
|
|
svc.depends = upstreamContainers;
|
|
net.forward.tcp = [
|
|
80
|
|
443
|
|
];
|
|
resources.fs."/var/lib/acme" = {
|
|
hostPath = "${data}/core/nginx/acme";
|
|
isReadOnly = false;
|
|
};
|
|
miscProperties.acmeDomains = map (v: v.domain) (discoveredVhosts ++ extraVhosts);
|
|
inherit (setup) containerConfig;
|
|
};
|
|
inherit (c) hostAddr;
|
|
in
|
|
c
|