Vista Normal

Hay nuevos artículos disponibles. Pincha para refrescar la página.
Hoy — 21 Noviembre 2024Salida Principal

Let's Encrypt SSL Certificates Guide

There was a recent post asking for guidance on this topic and I wanted to share my experience, so that it might help those who are lost on this topic.

If you are self-hosting an application, such as AdGuard Home, then you will undoubtedly find yourself encountering a browser warning about the application being unsafe and requiring you to bypass the warning before continuing. This is particularly noticeable when you want to access your application via HTTPS instead of HTTP. The point is that any application with access to traffic on your LAN's subnet will be able to access unencrypted traffic. To avoid this issue and secure your self-hosted application, you ultimately want a trusted certificate being presented to your browser when navigating to the application.

  • Purchase a domain name - I use Namecheap, but any registrar should be fine.
  • I highly recommend using a separate nameserver, such as Cloudflare.

Depending on how you have implemented your applications, you may want to use a reverse proxy, such as Traefik or Nginx Proxy Manager, as the initial point of entry to your applications. For example, if you are running your applications via Docker on a single host machine, then this may be the best solution, as you can then link your applications to Traefik directly.

As an example, this is a Docker Compose file for running Traefik with a nginx-hello test application:

name: traefik-nginx-hello secrets: CLOUDFLARE_EMAIL: file: ./secrets/CLOUDFLARE_EMAIL CLOUDFLARE_DNS_API_TOKEN: file: ./secrets/CLOUDFLARE_DNS_API_TOKEN networks: proxy: external: true services: nginx: image: nginxdemos/nginx-hello labels: - traefik.enable=true - traefik.http.routers.nginx.rule=Host(`nginx.example.com`) - traefik.http.routers.nginx.entrypoints=https - traefik.http.routers.nginx.tls=true - traefik.http.services.nginx.loadbalancer.server.port=8080 networks: - proxy traefik: image: traefik:v3.1.4 restart: unless-stopped networks: - proxy labels: - traefik.enable=true - traefik.http.routers.traefik.entrypoints=http - traefik.http.routers.traefik.rule=Host(`traefik-dashboard.example.com`) - traefik.http.routers.traefik.middlewares=traefik-https-redirect - traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https - traefik.http.middlewares.sslheader.headers.customrequestheaders.X-Forwarded-Proto=https - traefik.http.routers.traefik-secure.entrypoints=https - traefik.http.routers.traefik-secure.rule=Host(`traefik-dashboard.example.com`) - traefik.http.routers.traefik-secure.service=api@internal - traefik.http.routers.traefik-secure.tls=true - traefik.http.routers.traefik-secure.tls.certresolver=cloudflare - traefik.http.routers.traefik-secure.tls.domains[0].main=example.com - traefik.http.routers.traefik-secure.tls.domains[0].sans=*.example.com ports: - 80:80 - 443:443 environment: - CLOUDFLARE_EMAIL_FILE=/run/secrets/CLOUDFLARE_EMAIL - CLOUDFLARE_DNS_API_TOKEN_FILE=/run/secrets/CLOUDFLARE_DNS_API_TOKEN secrets: - CLOUDFLARE_EMAIL - CLOUDFLARE_DNS_API_TOKEN security_opt: - no-new-privileges:true volumes: - /etc/localtime:/etc/localtime:ro - /var/run/docker.sock:/var/run/docker.sock:ro - ./data/traefik.yml:/etc/traefik/traefik.yml:ro - ./data/configs:/etc/traefik/configs:ro - ./data/certs/acme.json:/acme.json 

Note that this expects several files:

# ./data/traefik.yml api: dashboard: true debug: true entryPoints: http: address: ":80" http: redirections: entryPoint: to: https scheme: https https: address: ":443" serversTransport: insecureSkipVerify: true providers: docker: endpoint: "unix:///var/run/docker.sock" exposedByDefault: false file: directory: /etc/traefik/configs/ watch: true certificatesResolvers: cloudflare: acme: storage: acme.json # Production caServer: https://acme-v02.api.letsencrypt.org/directory # Staging # caServer: https://acme-staging-v02.api.letsencrypt.org/directory dnsChallenge: provider: cloudflare #disablePropagationCheck: true #delayBeforeCheck: 60s resolvers: - "1.1.1.1:53" - "1.0.0.1:53" # ./secrets/CLOUDFLARE_DNS_API_TOKEN your long and super secret api token # ./secrets/CLOUDFLARE_EMAIL Your Cloudflare account email 

You will also note that I included the option for additional dynamic configuration files to be included via './data/configs/[dynamic config files]'. This is particularly handy if you wish to manually add routes for services, such as Proxmox, that you don't have the ability to setup via Docker service labels.

# ./data/configs/proxmox.yml http: routers: proxmox: entryPoints: - "https" rule: "Host(`proxmox.nickfedor.dev`)" middlewares: - secured tls: certresolver: cloudflare service: proxmox services: proxmox: loadBalancer: servers: # - url: "https://192.168.50.51:8006" # - url: "https://192.168.50.52:8006" # - url: "https://192.168.50.53:8006" - url: "https://192.168.50.5:8006" passHostHeader: true 

Or middlewares:

# ./data/configs/middleware-chain-secured.yml http: middlewares: https-redirectscheme: redirectScheme: scheme: https permanent: true default-headers: headers: frameDeny: true browserXssFilter: true contentTypeNosniff: true forceSTSHeader: true stsIncludeSubdomains: true stsPreload: true stsSeconds: 15552000 customFrameOptionsValue: SAMEORIGIN customRequestHeaders: X-Forwarded-Proto: https default-whitelist: ipAllowList: sourceRange: - "10.0.0.0/8" - "192.168.0.0/16" - "172.16.0.0/12" secured: chain: middlewares: - https-redirectscheme - default-whitelist - default-headers 

Alternatively, if you are running your services via individual Proxmox LXC containers or VM's, then you may find yourself needing to request SSL certificates and pointing the applications to their respective certificate file paths.

In the case of AdGuard Home running as a VM or LXC Container, as an example, I have found that using Certbot to request SSL certificates, and then pointing AdGuard Home to the SSL certfiles is the easiest method.

In other cases, such as running an Apt-Mirror, you may find yourself needing to run Nginx in front of the application as either a webserver and/or reverse proxy for the single application.

The easiest method of setting up and running Certbot that I've found is as follows:

  1. Install the necessary packages: apt install -y certbot python3-certbot-dns-cloudflare
  2. Setup a Cloudflare API credentials directory: sudo mkdir -p ~/.secrets/certbot
  3. Generate a Cloudflare API token with Zone > Zone > Read and Zone > DNS > Edit permissions.
  4. Add the token to a file: echo 'dns_cloudflare_api_token = [yoursupersecretapitoken]' > ~/.secrets/certbot/cloudflare.ini
  5. Update file permissions: sudo chmod 600 ~/.secrets/certbot/cloudflare.ini
  6. Execute Certbot to request a SSL cert: sudo certbot certonly --dns-cloudflare --dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini -d service.example.com

In the case if you're using Nginx, then do the following instead:

  1. Ensure nginx is already installed: sudo apt install -y nginx
  2. Ensure you also install Certbot's Nginx plugin: sudo apt install -y python3-certbot-nginx
  3. To have Certbot update the Nginx configuration when it obtains the certificate: sudo certbot run -i nginx -a dns-cloudflare --dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini -d service.example.com

If you are using Plex, as an example, then it is possible to use Certbot to generate a certificate and then run a script to generate the PFX cert file.

  1. Generate a password for the cert file: openssl rand -hex 16
  2. Add the script below to: /etc/letsencrypt/renewal-hooks/post/create_pfx_file.sh
  3. Ensure the script is executable: sudo chmod +x /etc/letsencrypt/renewal-hooks/post/create_pfs_file.sh
  4. If running for the first time, force Certbot to execute the script: sudo certbot renew --force-renewal

#!/bin/sh # /etc/letsencrypt/renewal-hooks/post/create_pfs_file.sh openssl pkcs12 -export \ -inkey /etc/letsencrypt/live/service.example.com/privkey.pem \ -in /etc/letsencrypt/live/service.example.com/cert.pem \ -out /var/lib/service/service_certificate.pfx \ -passout pass:PASSWORD chmod 755 /var/lib/service/service_certificate.pfx 

Note: The output file: /var/lib/service/service_certificate.pfx will need to be renamed to the respective service, i.e. /var/lib/radarr/radarr_certificate.pfx

Then, you can reference the file and password in the application.

For personal-use, this implementation is fine; however, a dedicated reverse proxy is recommended and preferable.

As mentioned before, Nginx Proxy Manager is another viable option, particularly for those interested in using something with a GUI to help manage their services. It's usage is very self explanatory, as you simply use the GUI to enter in the details of whatever service you wish to forward traffic towards and includes a simple menu system for setting up requesting SSL certificates.

The key thing to recall is that some applications, such as Proxmox, TrueNAS, Portainer, etc, may have their own built-in SSL certificate management. In the case of Proxmox, as an example, it's possible to use its built-in SSL management to request a certificate and then install and configure Nginx to forward the default management port from 8006 to 443:

# /etc/nginx/conf.d/proxmox.conf upstream proxmox { server "pve.example.com"; } server { listen 80 default_server; listen [::]:80 default_server; rewrite ^(.*) https://$host$1 permanent; } server { listen 443 ssl; listen [::]:443 ssl; server_name _; ssl_certificate /etc/pve/local/pveproxy-ssl.pem; ssl_certificate_key /etc/pve/local/pveproxy-ssl.key; proxy_redirect off; location / { proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_pass https://localhost:8006; proxy_buffering off; client_max_body_size 0; proxy_connect_timeout 3600s; proxy_read_timeout 3600s; proxy_send_timeout 3600s; send_timeout 3600s; } } 

Once all is said and done, the last step will always be pointing your DNS to your services.

If you're using a single reverse proxy, then use a wildcard entry, i.e. *.example.com, to point to your reverse proxy's IP address, which will then forward traffic to the respective service.

Example: Nginx Proxy Manager > 192.168.1.2 and Pihole > 192.168.1.10

Point DNS entry for pihole.example.com to 192.168.1.2 and configure Nginx Proxy Manager to forward to 192.168.1.10 .

If you're not using a reverse proxy in front of the service, then simply point the service's domain name to the server's IP address, i.e. pihole.example.com > 192.168.1.10 .

tl;dr - If you're self-hosting and want to secure your services with SSL, so that you may use HTTPS and port 443, then you'll want a domain that you can use for requesting a trusted Let's Encrypt certificate. This opens up options for whether the service itself has SSL management options built-in, such as Proxmox or you want to setup a single point of entry that forwards traffic to the respective service.

There are several different reverse proxy solutions available that have SSL management features, such as Nginx Proxy Manager and Traefik. Depending on your implementation, i.e. using Docker, Kubernetes, etc, there's a variety of ways to implement TLS encryption for your services, especially when considering limited use-cases, such as personal homelabs.

If you need to publicly expose your homelab services, then I would highly recommend considering using something like Cloudflare Tunnels. Depending on use case, you might also want to just simply use Tailscale or Wireguard instead.

This is by no means a comprehensive or production-level/best-practices guide, but hopefully it provides some ideas on several ways to help implement to your homelab.

submitted by /u/Pravobzen
[link] [comments]
❌
❌