Skip to content

Instantly share code, notes, and snippets.

Last active Jul 25, 2020
What would you like to do?
HTTPS for Pi-hole using Nginx reverse proxy

This Nginx Configuration sets up Pi-hole behind HTTPS using an Nginx reverse proxy for secure credential transmission when accessing the UI.

Using the NXDOMAIN blocking mode makes sure that Pi-hole is not serving empty HTML pages for every ad.

Since I use ufw on my Raspberry Pi, the following rules are needed for the setup to work (SSH is optional):

sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere
80/tcp                     ALLOW       Anywhere
53/tcp                     ALLOW       Anywhere
53/udp                     ALLOW       Anywhere
443/tcp                    ALLOW       Anywhere

From Anywhere is fine because I'm behind a NAT and no incoming connections are allowed from the internet.

We also need to set server.port = 3000 in /etc/lighttpd/lighttpd.conf to enable Pi-hole to run on a port different than 80. The only problem, however, is that lighttpd.conf gets overwritten whenever Pi-hole is updated.

# /etc/nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/;
include /etc/nginx/modules-enabled/*.conf;
pcre_jit on;
events {
worker_connections 768;
multi_accept on;
http {
# Basic Settings
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
add_header X-Content-Type-Options nosniff;
server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# SSL Settings
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:5m;
ssl_session_timeout 5m;
# Logging Settings
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
# Gzip Settings
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_min_length 1000;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
# Virtual Host Configs
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
# serve static content form /usr/share/nginx/html
server {
server_name $hostname;
listen 80 default_server;
listen [::]:80 default_server;
root /usr/share/nginx/html;
# redirect http to https for pi.hole
server {
add_header Strict-Transport-Security max-age=31536000;
server_name pi.hole;
listen 80;
listen [::]:80;
return 301 https://$http_host$request_uri;
# only map to pi-hole when HTTP host header is `pi.hole`
server {
server_name pi.hole;
listen 443 ssl;
listen [::]:443 ssl;
ssl_certificate /etc/ssl/pi.hole.crt;
ssl_certificate_key /etc/ssl/pi.hole.key;
add_header Strict-Transport-Security max-age=31536000;
location ~ .* {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment