Nginx-certbot-config (Simple "reverse proxy" using Guix services"

Hello, all! Thought I’d share something I’ve been working on for the past few days. First, a little backstory:

When self-hosting software at home, I’ve been using either Caddy or Traefik for as my reverse proxy. I don’t like Traefik (For reasons we won’t go into here) and Caddy was having some weird issue where I couldn’t push more than 150Mb on my 2.5Gb network…

That leads me to my, now Guix-ified, solution:

(define-syntax nginx-certbot-config
  (syntax-rules ()
    ((_ domain host nginx-var certbot-var #:extra-config extra-config)
     (begin
       (define nginx-var
         (nginx-server-configuration
          (server-name `(,domain))
          (listen '("443 ssl"))
          (ssl-certificate (string-append "/etc/certs/" domain "/fullchain.pem"))
          (ssl-certificate-key (string-append "/etc/certs/" domain "/privkey.pem"))
          (locations
           (list
            (nginx-location-configuration
             (uri "/")
             (body (append (list (string-append "proxy_pass " host ";"))
                           extra-config)))))
          (raw-content extra-config)))
       (define certbot-var
         (certificate-configuration
          (domains (list domain))))))
    ((_ domain host nginx-var certbot-var)
     (nginx-certbot-config domain host nginx-var certbot-var
                            #:extra-config '()))))

What it does:

  1. Creates an nginx-server-configuration that points to the certificates at /etc/certs// and allows for extra body config (For headers and such)
  2. Creates a certificate-configuration pointed at the same domain
  3. Sets two variables equal to each of the configs, ready for export

Don’t worry about http-to-https redirect, Guix has that covered for free.

Here’s an example (With added bonus oci-container-service-type config for searxng):

(define-module (momo services searxng)
  #:use-module (gnu services docker)
  #:use-module (gnu services)
  #:use-module (gnu services web)
  #:use-module (gnu services certbot)
  #:use-module (momo nginx-certbot-config)
  #:export (searxng-service
            searxng-nginx-config
            searxng-certbot-config))

(define searxng-service
  (service oci-container-service-type
           (list
            (oci-container-configuration
             (image "paulgoio/searxng:production")
             (requirement '(searxng-redis))
             (provision "searxng")
             (ports
              '("8083:8080"))
             (environment
              '(("PUBLIC_INSTANCE" . "true")
                ("LIMITER" . "true")
                ("REDIS_URL" . "redis://searxng-redis:6379/0")
                ("IMAGE_PROXY" . "true")
                ("UWSGI_WORKERS" . "8")
                ("UWSGI_THREADS" . "4")
                ("BASE_URL" . "https://search.example.com")
                ("NAME" . "My Personal Search")
                ("SEARCH_DEFAULT_LANG" . "en-US")
                ("SEARCH_ENGINE_ACCESS_DENIED" . "60")))
             (network "backend")
             (extra-arguments
              '("--cap-drop=ALL"
                "--cap-add=NET_ADMIN"
                "--cap-add=SETGID"
                "--cap-add=SETUID"
                "--log-driver=json-file"
                "--log-opt=max-size=1m"
                "--log-opt=max-file=1")))
            (oci-container-configuration
             (image "redis:alpine")
             (provision "searxng-redis")
             (command '("redis-server" "--save" "" "--appendonly" "no"))
             (network "backend")
             (extra-arguments
              '("--tmpfs=/var/lib/redis"
                "--cap-drop=ALL"
                "--cap-add=SETGID"
                "--cap-add=SETUID"
                "--cap-add=DAC_OVERRIDE"))))))

(nginx-certbot-config "search.example.com" "http://localhost:8083"
                      searxng-nginx-config searxng-certbot-config)

As you can see, lots of boilerplate reduction.

Example usage in config.scm:

(service nginx-service-type
         (nginx-configuration
          (server-blocks
           (list
            searxng-nginx-config))))
(service certbot-service-type
         (certbot-configuration
          (email "email@example.com")
          (certificates
           (list
            searxng-certbot-config))))

Anyhow, I hope this helps anyone interested in getting your one-stop shop reverse proxying in Guix. On one final note: I have been getting a lot of troubleshooting in on the oci-container-type in this last week, feel free to drop me a DM or if enough interest is shown, I’ll put up a GitHub with some definitions I’ve been playing with.

3 Likes

This is really useful, thanks a lot for sharing it! I’d love to see the container service definitions you’ve been working on.