forked from Fachschaft/nixConfig
redirects and proxy passes working (except for ssl which needs to migrate to dns)
This commit is contained in:
parent
a7c1e37375
commit
42b0d35691
4 changed files with 295 additions and 12 deletions
202
nixos/modules/reverseProxy.nix
Normal file
202
nixos/modules/reverseProxy.nix
Normal file
|
@ -0,0 +1,202 @@
|
|||
# All our domains fall in one or more of three categories
|
||||
# proxyPass, basically handle the tls and pass the http traffick on
|
||||
# redirect, redirect to another uri
|
||||
# webHost, host the content of some directory under this domain
|
||||
# We will use this by defining helper functions that generates config
|
||||
# for those categories and then apply them to the required parameters.
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
cfg = config.services.reverseProxy;
|
||||
# the equivalent of library imports in other languages
|
||||
inherit (lib) isString mkEnableOption mkOption;
|
||||
inherit (lib.attrsets) concatMapAttrs;
|
||||
inherit (lib.lists) foldr;
|
||||
withGeneralHostConfig = virtualHostConfig:
|
||||
{
|
||||
forceSSL = true;
|
||||
useACMEHost = "mathebau.de";
|
||||
locations =
|
||||
{
|
||||
# notice that nix will also parse this string and we need to escape \
|
||||
# so after nix processing "~ /\.git/" will end up in the nginx config,
|
||||
# with the proper regex escape.
|
||||
# I find this behaiviour unexpected and a bit weird, but it catches some footguns
|
||||
# Note that this also applies to redirects.
|
||||
"~ /\\.git/" = {
|
||||
extraConfig = "deny all;";
|
||||
};
|
||||
"~ /\\.ht" = {
|
||||
extraConfig = "deny all;";
|
||||
};
|
||||
"/.well-known/security.txt" = {
|
||||
return = ''
|
||||
200 "Contact: mailto:root@mathebau.de
|
||||
Expires: 2029-12-31T23:00:00.000Z
|
||||
Preferred-Languages: de,en"
|
||||
'';
|
||||
};
|
||||
}
|
||||
// virtualHostConfig.locations;
|
||||
}
|
||||
// virtualHostConfig;
|
||||
# The function to generate proxyPass directives
|
||||
# We always proxy pass "/", but in theory this can also work for other paths
|
||||
proxyWithCache = let
|
||||
proxyHelper = {
|
||||
targetMachine,
|
||||
targetPort,
|
||||
websockets,
|
||||
}: {
|
||||
proxyPass = "http://${targetMachine}:${toString targetPort}";
|
||||
proxyWebsockets = websockets;
|
||||
recommendedProxySettings = true;
|
||||
};
|
||||
cacheHelper = targetData:
|
||||
proxyHelper targetData
|
||||
// {
|
||||
extraConfig = ''
|
||||
gzip on;
|
||||
gzip_proxied any;
|
||||
gzip_types *;
|
||||
expires max;
|
||||
'';
|
||||
};
|
||||
in
|
||||
concatMapAttrs (domain: domainData: {
|
||||
${domain}.locations =
|
||||
concatMapAttrs (path: targetData: {
|
||||
${path} = proxyHelper targetData;
|
||||
# this instruncts clients to cache files with this list of extension for 24h.
|
||||
# This might break things. For example if a machine tries to generate these
|
||||
# things dynamically, but might be load reducing, i don't get why atom, rss, xml and txt are in this list
|
||||
"~* ^${path}.+\\.(atom|bmp|bz2|doc|docx|eot|exe|gif|gz|ico|jpeg|jpg|mid|midi|mp4|ogg|ogv|otf|pdf|png|ppt|pptx|rar|rss|rtf|svg|svgz|swf|tar|tgz|ttf|txt|wav|webp|woff|woff2|xls|zip|css|js|xml)$" = cacheHelper targetData;
|
||||
})
|
||||
domainData;
|
||||
});
|
||||
proxyPasses = proxyWithCache cfg.proxies;
|
||||
redirect = let
|
||||
redirectHelper = {
|
||||
target,
|
||||
code ? "303",
|
||||
}: {return = code + " " + target;};
|
||||
in
|
||||
concatMapAttrs (
|
||||
domain: redirectData: {
|
||||
${domain}.locations =
|
||||
concatMapAttrs (
|
||||
path: targetData:
|
||||
if isString targetData
|
||||
then {
|
||||
${path} = redirectHelper {
|
||||
target = targetData;
|
||||
};
|
||||
}
|
||||
else {${path} = redirectHelper targetData;}
|
||||
)
|
||||
redirectData;
|
||||
}
|
||||
);
|
||||
# TODO import these from a file
|
||||
redirects = redirect cfg.redirects;
|
||||
# Helper function to merge all the different configurations together.
|
||||
# Later configurations take precedence.
|
||||
in {
|
||||
imports = [];
|
||||
|
||||
options.services.reverseProxy = {
|
||||
enable = mkEnableOption "mathebau reverse Proxy";
|
||||
redirects = mkOption {
|
||||
type = lib.types.attrsOf (lib.types.attrsOf (lib.types.either lib.types.str (lib.types.submodule {
|
||||
options = {
|
||||
code = mkOption {
|
||||
type = lib.types.str; # todo make matching regex
|
||||
description = "the http status code of the redirect";
|
||||
default = "303";
|
||||
};
|
||||
target = mkOption {
|
||||
type = lib.types.str;
|
||||
description = "the target url of the redirect, for more details on format see the nginx docu";
|
||||
};
|
||||
};
|
||||
})));
|
||||
description = "the redirects that this reverse proxy should serve";
|
||||
default = {};
|
||||
};
|
||||
proxies = mkOption {
|
||||
type = lib.types.attrsOf (lib.types.attrsOf (lib.types.submodule {
|
||||
options = {
|
||||
targetMachine = mkOption {
|
||||
type = lib.types.str;
|
||||
description = "the machine to proxy to";
|
||||
};
|
||||
targetPort = mkOption {
|
||||
type = lib.types.port;
|
||||
description = "the port the target machine listens on";
|
||||
default = 80;
|
||||
};
|
||||
websockets = mkOption {
|
||||
type = lib.types.bool;
|
||||
description = "wether or not websocket support should be enabled";
|
||||
default = false;
|
||||
};
|
||||
};
|
||||
}));
|
||||
description = "the proxy pass directive this reverse proxy should serve";
|
||||
default = {};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
virtualHosts = concatMapAttrs (name: config: {${name} = withGeneralHostConfig config;}) (foldr lib.attrsets.recursiveUpdate {} [redirects proxyPasses]);
|
||||
# We should already set this by default in roles/vm.nix for all vm that run nginx, but to be sure...
|
||||
recommendedTlsSettings = lib.mkForce true;
|
||||
# We set form-action to self so in general webforms are allowed. On a finer bases
|
||||
# we could set this to none for some hosts (or even locations) but this would clutter
|
||||
# the config. Same is true for base-uri
|
||||
appendHttpConfig = ''
|
||||
add_header Content-Security-Policy "base-uri 'self'; default-src 'self'; frame-ancestor 'none'; form-action 'self';" always;
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
'';
|
||||
};
|
||||
# TODO: we need to rebuild this for dns challenges,
|
||||
# this does not work with our proxy pass challenge hand through things.
|
||||
security.acme = {
|
||||
acceptTerms = true;
|
||||
certs."mathebau.de" = {
|
||||
webroot = "/var/lib/acme/acme-challenge";
|
||||
email = "root@mathebau.de";
|
||||
extraDomainNames = [
|
||||
"cloud.mathechor.de"
|
||||
"download.mathebau.de"
|
||||
"events.mathebau.de"
|
||||
"fb04184.mathematik.tu-darmstadt.de"
|
||||
"fswiki.mathebau.de"
|
||||
"gitea.mathebau.de"
|
||||
"imap.mathebau.de"
|
||||
"intern.mathebau.de"
|
||||
"lists.mathebau.de"
|
||||
"matheball.de"
|
||||
"matheball.mathebau.de"
|
||||
"mathechor.de"
|
||||
"meet.mathebau.de"
|
||||
"owowiki.mathebau.de"
|
||||
"smtp.mathebau.de"
|
||||
"sprechstunden.mathebau.de"
|
||||
"surveys.mathebau.de"
|
||||
"theateraufnahmen.mathebau.de"
|
||||
"theaterskript.mathebau.de"
|
||||
"www.koma89.tu-darmstadt.de"
|
||||
"www.matheball.de"
|
||||
"www.mathebau.de"
|
||||
"www.mathechor.de"
|
||||
];
|
||||
};
|
||||
};
|
||||
users.users.nginx.extraGroups = ["acme"];
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue