commit 2e513eb4a7982341866f29918c1b7abe9007aec8
parent f2e4e77d731ce3e132662487797d2e5fdcf09c77
Author: Daniel Barlow <dan@telent.net>
Date: Sun, 29 Dec 2024 23:34:15 +0000
example sni proxy using nginx
Diffstat:
1 file changed, 81 insertions(+), 0 deletions(-)
diff --git a/examples/module-https-proxy.nix b/examples/module-https-proxy.nix
@@ -0,0 +1,81 @@
+# This is "contrib"-level code. This module solves a particular
+# problem for my particular setup and is provided as is, as an example
+# of how you might write something similar if you had a similar
+# problem. Don't expect it to work unmolested in your setup (you will
+# at the absolute minimum have to change the domain name), nor even to
+# continue to exist without possibly being changed beyond recognition.
+
+# The computers on my LAN have globally unique routable IPv6
+# addresses, but I have only one public IPv4 address. I want to expose
+# HTTPS services to the Internet _whatever_ machine is hosting them,
+# so I publish an AAAA record to the machine itself, and an A record
+# to the public v4 address of the router which is running this nginx.
+# This nginx checks the SNI in the incoming connection and forwards
+# the connection to the (IPv6 address of the) same hostname
+
+# See https://ww.telent.net/2020/12/2/six_into_4_won_t_go for
+# the original solution to this problem, which used sniproxy (now
+# unmaintained) instead of nginx
+
+{ config, pkgs, ... }:
+let
+ inherit (pkgs.liminix.services) longrun;
+ inherit (pkgs) writeText;
+in {
+ config = {
+ users.nginx = {
+ uid = 52; gid= 52;
+ dir = "/run/";
+ shell = "/bin/false";
+ };
+ groups.nginx = {
+ gid= 52;
+ usernames = ["nginx"];
+ };
+
+ services.sniproxy =
+ let
+ nginx = pkgs.nginx-small.override {
+ pcre = null;
+ zlib = null;
+ options = [
+ "stream"
+ "stream_ssl_module" "stream_ssl_preread_module"
+ "stream_map_module"
+ ];
+ };
+ conf = writeText "nginx.conf" ''
+ worker_processes auto;
+ error_log /proc/self/fd/1 info;
+ pid /dev/null;
+ user nginx;
+ daemon off;
+ events {
+ worker_connections 1024;
+ }
+
+ stream {
+ log_format proxy '$remote_addr -> $ssl_target';
+ access_log /proc/self/fd/1 proxy;
+ map $ssl_preread_server_name $ssl_target {
+ hostnames;
+ .telent.net $ssl_preread_server_name:443;
+ }
+
+ server {
+ listen 443;
+ resolver 127.0.0.1 ipv6=on ipv4=off;
+ resolver_timeout 1s;
+ proxy_pass $ssl_target;
+ ssl_preread on;
+ }
+ }
+ '';
+ in longrun {
+ name = "sniproxy";
+ run = ''
+ ${nginx}/bin/nginx -c ${conf}
+ '';
+ };
+ };
+}