Hi! I’m currently trying to figure out how to get NGINX on nas.example.org to terminate SSL and manage ACME. This is mostly a proof-of-concept right now — I can add proxies from NGINX to containers later. I only care about actual traffic on port 443 — so port 80 is only used for ACME HTTP-01 challenges. I could probably skip all this with a DNS-01 challenge but I really don’t want to rely on my DNS provider for that — I’m looking for a more portable solution.
When I disable SSL and ACME, this works fine. The principal error seems to come about with nixos-rebuild as Failed assertions: services.nginx.virtualHosts.<name>.enableACME requires a HTTP listener to answer to ACME requests. If I disable proxyProtocol on port 80, the error goes away but then NGINX doesn’t recieve packets from HAProxy.
Please help. How can I fix this?
As an aside, that listen attribute set list on nas.example.org is disgusting. Does anyone know how to map a: a // { proxyProtocol = true; } over the default generated value? Even more preferable, is there a way to skip manually defining the listen block altogether by setting proxy_protocol on all of the statements via a higher-level option?
Both systems are using Nix 2.28.5 and NixOS 25.05 — I’ll update soon, promise!
/etc/nixos/tunnel.nix - vps.example.org
{ config, pkgs, ...}:
{
networking.firewall.allowedUDPPorts = [ 51820 ];
networking.firewall.allowedTCPPorts = [ 80 443 ];
networking.nat = {
enable = true;
enableIPv6 = true;
externalInterface = "ens3";
internalInterfaces = [ "tun0" ];
};
networking.wireguard.enable = true;
networking.wireguard.interfaces.tun0 = {
ips = [ "10.16.0.1/24" ];
listenPort = 51820;
privateKeyFile = "/root/tun0.key";
peers = [
{
name = "nas.example.org";
publicKey = "<nas-pubkey>";
allowedIPs = [ "10.16.0.2/32" ];
persistentKeepalive = 25;
}
];
};
services.haproxy.enable = true;
services.haproxy.config = ''
log stdout format raw local0 info
defaults
log global
mode tcp
option http-server-close
timeout client 10s
timeout connect 5s
timeout server 10s
frontend haproxy_http
bind *:80
option tcplog
default_backend nas_http
frontend haproxy_https
bind *:443
option tcplog
default_backend nas_https
backend nas_http
balance roundrobin
server default 10.16.0.2:80 check send-proxy
backend nas_https
balance roundrobin
server default 10.16.0.2:443 check send-proxy
'';
}
/etc/nixos/tunnel-client.nix - nas.example.org
{config, pkgs, ...}:
{
networking.firewall.allowedUDPPorts = [ 51820 ];
networking.firewall.allowedTCPPorts = [ 80 443 ];
networking.firewall.checkReversePath = "loose";
networking.wireguard.enable = true;
networking.wireguard.interfaces.tun0 = {
ips = [ "10.16.0.2/32" ];
listenPort = 51820;
privateKeyFile = "/root/tun0.key";
peers = [
{
name = "vps.example.org";
publicKey = "<vps-pubkey>";
allowedIPs = [ "10.16.0.0/16" ];
endpoint = "vps.example.org:51820";
persistentKeepalive = 25;
}
];
};
services.nginx.enable = true;
services.nginx.recommendedProxySettings = true;
services.nginx.virtualHosts."test.example.org" = {
addSSL = true
enableACME = true;
default = true;
listen = [
{ addr = "0.0.0.0"; port = 80; proxyProtocol = true; }
{ addr = "0.0.0.0"; port = 443; ssl = true; proxyProtocol = true; }
{ addr = "[::0]"; port = 80; proxyProtocol = true; }
{ addr = "[::0]"; port = 443; ssl = true; proxyProtocol = true; }
];
locations."/" = {
return = "200 'Hello World!'";
};
};
security.acme.acceptTerms = true;
security.acme.defaults.email = "web+acme@example.org";
#users.users.nginx.extraGroups = [ "acme" ];
}