(define-module (tw services web) #:use-module (gnu services) #:use-module (gnu services configuration) #:use-module (gnu services certbot) #:use-module (gnu services web) #:use-module (guix gexp) #:use-module (guix records) #:use-module ((srfi srfi-1) #:select (concatenate)) #:export (%nginx-cert-deploy-hook https-reverse-proxy-service-type https-reverse-proxy-configuration)) (define %nginx-cert-deploy-hook (program-file "nginx-cert-deploy-hook" #~(kill (call-with-input-file "/var/run/nginx/pid" read) SIGHUP))) (define-configuration/no-serialization https-reverse-proxy-configuration (domains list-of-strings "List of domain names that nginx should proxy requests for.") (destination-port integer "The port number of the service that should be proxied to.") (destination-ip (string "127.0.0.1") "The IP address of the server that should be proxied to. Usually, this should be localhost.") (destination-protocol (string "http") "The protocol that the proxied service speaks. Set to @code{\"https\"} if you want to proxy HTTPS-to-HTTPS.")) (define (reverse-proxy-certificate config) (match-record config (domains) (certificate-configuration (domains domains) (deploy-hook %nginx-cert-deploy-hook)))) (define (reverse-proxy-nginx-server config) (match-record config (domains destination-port destination-ip) (nginx-server-configuration (listen '("443 ssl http2")) (server-name domains) (ssl-certificate (string-append "/etc/letsencrypt/live/" (car domains) "/fullchain.pem")) (ssl-certificate-key (string-append "/etc/letsencrypt/live/" (car domains) "/privkey.pem")) (server-tokens? #f) (locations (list (nginx-location-configuration (uri "/") (body `(("proxy_pass http://" ,destination-ip ":" ,(number->string destination-port) ";") ;; For Grafana: https://grafana.com/tutorials/run-grafana-behind-a-proxy/#configure-nginx "proxy_set_header Host $http_host;")))))))) (define (reverse-proxy-certificates configs) (map reverse-proxy-certificate configs)) (define (reverse-proxy-nginx-servers configs) (map reverse-proxy-nginx-server configs)) (define https-reverse-proxy-service-type (service-type (name 'reverse-proxy) (extensions (list (service-extension nginx-service-type reverse-proxy-nginx-servers) (service-extension certbot-service-type reverse-proxy-certificates))) (default-value '()) (compose concatenate) (extend append) (description "Configure nginx as a reverse proxy proxying external HTTPS requests to another host or a local port over plain HTTP.")))