Add an nginx helper
- This will allow us to easily make nginx servers without having to worry about
the normal nginx boilerplate/syntax
Change-Id: I87225864ea8983ef9742bec9c624471794be54d2
diff --git a/nginx.nix b/nginx.nix
new file mode 100644
index 0000000..1fce41b
--- /dev/null
+++ b/nginx.nix
@@ -0,0 +1,179 @@
+{ pkgs, ... }: let
+ lib = pkgs.lib;
+in {
+ Host = host: service: {
+ inherit host service;
+ extraHosts = [];
+ secure = true;
+ type = "hosts";
+ };
+ Hosts = hosts: service: {
+ inherit service;
+ host = elemAt hosts 0;
+ extraHosts = tail hosts;
+ secure = true;
+ type = "hosts";
+ };
+ InsecureHost = host: service: {
+ inherit host service;
+ extraHosts = [];
+ secure = false;
+ type = "hosts";
+ };
+ InsecureHosts = hosts: service: {
+ inherit service;
+ host = elemAt hosts 0;
+ extraHosts = tail hosts;
+ secure = false;
+ type = "hosts";
+ };
+ ReverseProxy = to: {
+ inherit to;
+ type = "reverseproxy";
+ };
+ PHP = root: socket: {
+ inherit root socket;
+ type = "php";
+ };
+ Redirect = to: permanent: {
+ inherit to permanent;
+ type = "redirect";
+ };
+ Directory = root: {
+ inherit root;
+ private = false;
+ type = "directory";
+ };
+ PrivateDirectory = root: {
+ inherit root;
+ private = true;
+ type = "directory";
+ };
+ File = path: {
+ inherit path;
+ type = "file";
+ };
+ Compose = services: {
+ inherit services;
+ type = "compose";
+ };
+ Path = path: service: {
+ inherit path service;
+ type = "path";
+ };
+
+ Merge = let
+ # builtins.length and count up
+ _iterateCompose = services: currentConfig: currentPath: secure: priority: i:
+ if i > length services
+ then currentConfig
+ else _iterateCompose services (_merge (elemAt services i) currentConfig currentPath secure priority+i) currentPath secure priority (i+1);
+
+ _iterateMerge = i: current: services:
+ if i > length services
+ then current
+ else _iterateMerge (i+1) (current++[_merge (elemAt services i) {} "/" true 1000]) services;
+
+ _merge = service: currentConfig: currentPath: secure: priority:
+ if service.type == "hosts"
+ then _merge service.service (lib.mkMerge currentConfig {
+ name = service.host;
+ value = {
+ serverAliases = service.extraHosts;
+
+ enableACME = service.secure;
+ forceSSL = service.secure;
+ listen = [
+ {
+ addr = "0.0.0.0";
+ port = if service.secure then 443 else 80;
+ ssl = service.secure;
+ }
+ ];
+ };
+ }) currentPath service.secure priority
+ else if service.type == "reverseproxy"
+ then (lib.mkMerge currentConfig {
+ value.locations.${currentPath} = {
+ proxyPass = service.to;
+ proxyWebsockets = true;
+ recommendedProxySettings = true;
+ };
+ })
+ else if service.type == "php"
+ then (lib.mkMerge currentConfig {
+ value.locations.${currentPath} = {
+ root = service.root;
+ index = "index.php index.html index.htm";
+ tryFiles = "$uri $uri/ ${currentPath}index.php?$query_string =404";
+ };
+ value.locations."~ ^${currentPath}.*\.php$" = {
+ tryFiles = "$uri $uri/ ${currentPath}index.php?$query_string =404";
+ extraConfig = ''
+ include ${pkgs.nginx}/conf/fastcgi_params;
+ fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+ fastcgi_param REDIRECT_STATUS 200;
+ fastcgi_pass unix:${service.socket};
+ fastcgi_intercept_errors on;
+ ${lib.optionalString secure "fastcgi_param HTTPS on;"}
+ '';
+ };
+ })
+ else if service.type == "redirect"
+ then (lib.mkMerge currentConfig {
+ value.locations.${currentPath}.return =
+ if service.permanent
+ then "308 ${service.to}"
+ else "307 ${service.to}";
+ })
+ else if service.type == "directory"
+ then (lib.mkMerge currentConfig {
+ value.locations.${currentPath} = {
+ root = service.root;
+ index = "index.html index.htm";
+ tryFiles = "$uri $uri/ =404";
+ extraConfig = lib.optionalString !service.private "autoindex on;";
+ };
+ })
+ else if service.type == "file"
+ then (lib.mkMerge currentConfig {
+ value.locations.${currentPath} = {
+ tryFiles = "${service.path} =404";
+ };
+ })
+ else if service.type == "path"
+ then _merge service.service currentConfig service.path service.secure
+ else if service.type == "compose"
+ then (_iterateCompose service.services currentConfig currentPath secure priority 0)
+ else throw "Unknown service type: ${service.type}";
+ in (services: lib.pipe services [
+ (_iterateMerge 0 [])
+ builtins.listToAttrs
+ ]);
+
+ # https://www.nginx.com/resources/wiki/start/topics/examples/full/
+
+ /**
+ Internal needs to be a string that is both a host and a port, e.g. generic:1000
+ External should only be a port
+ Protocol should be TCP or UDP
+ */
+ Stream = external: internal: protocol: ''
+ server {
+ listen ${builtins.toString external} ${protocol};
+ proxy_pass ${internal};
+ }
+ '';
+
+ Alias = host: alias: {
+ inherit host;
+ aliases = [ alias ];
+ type = "aliases";
+ };
+
+ Aliases = host: aliases: {
+ inherit host aliases;
+ type = "aliases";
+ };
+}
+