liminix

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

module-https-proxy.nix (2628B)


      1 # This is "contrib"-level code. This module solves a particular
      2 # problem for my particular setup and is provided as is, as an example
      3 # of how you might write something similar if you had a similar
      4 # problem. Don't expect it to work unmolested in your setup (you will
      5 # at the absolute minimum have to change the domain name), nor even to
      6 # continue to exist without possibly being changed beyond recognition.
      7 
      8 # The computers on my LAN have globally unique routable IPv6
      9 # addresses, but I have only one public IPv4 address. I want to expose
     10 # HTTPS services to the Internet _whatever_ machine is hosting them,
     11 # so I publish an AAAA record to the machine itself, and an A record
     12 # to the public v4 address of the router which is running this nginx.
     13 # This nginx checks the SNI in the incoming connection and forwards
     14 # the connection to the (IPv6 address of the) same hostname
     15 
     16 # See https://ww.telent.net/2020/12/2/six_into_4_won_t_go for
     17 # the original solution to this problem, which used sniproxy (now
     18 # unmaintained) instead of nginx
     19 
     20 { config, pkgs, ... }:
     21 let
     22   inherit (pkgs.liminix.services) longrun;
     23   inherit (pkgs) writeText;
     24   nginx_uid = 62;
     25 in
     26 {
     27   config = {
     28     users.nginx = {
     29       uid = nginx_uid;
     30       gid = nginx_uid;
     31       dir = "/run/";
     32       shell = "/bin/false";
     33     };
     34     groups.nginx = {
     35       gid = nginx_uid;
     36       usernames = [ "nginx" ];
     37     };
     38 
     39     services.sniproxy =
     40       let
     41         nginx = pkgs.nginx-small.override {
     42           pcre = null;
     43           zlib = null;
     44           options = [
     45             "stream"
     46             "stream_ssl_module"
     47             "stream_ssl_preread_module"
     48             "stream_map_module"
     49           ];
     50         };
     51         conf = writeText "nginx.conf" ''
     52           worker_processes auto;
     53           error_log /proc/self/fd/1 info;
     54           pid /dev/null;
     55           user nginx;
     56           daemon off;
     57           events {
     58               worker_connections 1024;
     59           }
     60 
     61           stream {
     62               log_format proxy '$remote_addr -> $ssl_target';
     63               access_log /proc/self/fd/1 proxy;
     64               map $ssl_preread_server_name $ssl_target {
     65                   hostnames;
     66                   .telent.net    $ssl_preread_server_name:443;
     67               }
     68 
     69               server {
     70                   listen 443;
     71                   resolver 127.0.0.1 ipv6=on ipv4=off;
     72                   resolver_timeout 1s;
     73                   proxy_pass $ssl_target;
     74                   ssl_preread on;
     75               }
     76           }
     77         '';
     78       in
     79       longrun {
     80         name = "sniproxy";
     81         run = ''
     82           ${nginx}/bin/nginx -c ${conf}
     83         '';
     84       };
     85   };
     86 }