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 }