initial commit
This commit is contained in:
@@ -0,0 +1,215 @@
|
||||
{
|
||||
name,
|
||||
hostInfo,
|
||||
dsl,
|
||||
lib,
|
||||
containers,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (dsl) mkContainer;
|
||||
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;
|
||||
# avoid startup error when containers aren't registered yet
|
||||
# proxyPass is left unset for that reason, so recommendedProxySettings
|
||||
# won't auto-include its headers here - set them manually to match
|
||||
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; };
|
||||
|
||||
nginxSetup =
|
||||
hostAddr:
|
||||
mkNginxConfig {
|
||||
email = "floweydev@gmail.com";
|
||||
resolver = hostAddr;
|
||||
vhosts = [
|
||||
{
|
||||
domain = "devenv.floweytf.com";
|
||||
upstream = up containers.devenv 8080;
|
||||
}
|
||||
{
|
||||
domain = "maven.floweytf.com";
|
||||
upstream = up containers.maven 8080;
|
||||
}
|
||||
{
|
||||
domain = "git.floweytf.com";
|
||||
upstream = up containers.git 3000;
|
||||
}
|
||||
{
|
||||
domain = "utils.floweytf.com";
|
||||
redirect = false;
|
||||
listenHttp = true;
|
||||
extraLocations = {
|
||||
"/static/" = {
|
||||
alias = "/usr/share/nginx/static/";
|
||||
extraConfig = "autoindex on;";
|
||||
};
|
||||
};
|
||||
}
|
||||
{
|
||||
# no upstream, vhost only exists for certs
|
||||
domain = "mail.floweytf.com";
|
||||
}
|
||||
];
|
||||
};
|
||||
in
|
||||
let
|
||||
setup = nginxSetup hostAddr;
|
||||
c = mkContainer {
|
||||
inherit name;
|
||||
net.access = setup.access ++ [ { to = "@internet"; } ];
|
||||
svc.autoStart = true;
|
||||
svc.depends = lib.attrVals [ "devenv" "maven" "git" ] containers;
|
||||
net.forward.tcp = [
|
||||
80
|
||||
443
|
||||
];
|
||||
resources.fs."/var/lib/acme" = {
|
||||
hostPath = "${data}/core/nginx/acme";
|
||||
isReadOnly = false;
|
||||
};
|
||||
inherit (setup) containerConfig;
|
||||
};
|
||||
hostAddr = c.hostAddr;
|
||||
in
|
||||
c
|
||||
Reference in New Issue
Block a user