Deny all hosts except the one with SSL

I have a setup where I have a pihole running on pi.domain.com and I have gotten a Let's Encrypt certificate for that domain. I then followed Enabling HTTPS for your Pi-hole Web Interface to have the certificates served. Now I wanted to block access via any other host (or IP) other than pi.domain.com. That includes the pi.hole hostname. To that end I modified the external.conf as follows:

$HTTP["host"] == "pi.domain.com" {
  setenv.add-environment = ("fqdn" => "true")

  $SERVER["socket"] == ":443" {
    ssl.engine = "enable"
    ssl.pemfile = "/etc/letsencrypt/live/pi.domain.com/combined.pem"
    ssl.ca-file =  "/etc/letsencrypt/live/pi.domain.com/full.pem"
    ssl.honor-cipher-order = "enable"
    ssl.cipher-list = "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"
    ssl.use-sslv2 = "disable"
    ssl.use-sslv3 = "disable"
  }

  $HTTP["scheme"] == "http" {
    $HTTP["host"] =~ ".*" {
      url.redirect = (".*" => "https://%0$0")
    }
  }
}
else {
  url.deny-access = ("")
}

Few notes:

  • PiHole is running inside a docker container and external.conf along with certificated files is mapped. I have verified that work by getting interacting shell inside the docker and inspecting them. Also accessing the pi via pi.domain.com gives me the right certificate.
  • I don't care about a block page since I want to use NULL blocking.

The relevant part of docker-compose:

services:
  pihole:
    container_name: pihole
    image: pihole/pihole:latest
    depends_on:
      - dnscrypt
      - acme-pihole
    network_mode: host
    environment:
      TZ: "Europe/Berlin"
      WEBPASSWORD: "MyPass"
      DNS1: "192.168.1.254#3553"
      DNS2: "192.168.1.254#3553"
      ServerIP: "192.168.1.254"
      VIRTUAL_HOST: "pi.domain.com"
      IPv6: "false"
    extra_hosts:
      - "dev1.domain.com:192.168.1.1"
      - "dev2.domain.com:192.168.1.2"
    volumes:
      - './pihole/etc-pihole/:/etc/pihole/'
      - './pihole/etc-dnsmasq.d/:/etc/dnsmasq.d/'
      - './pihole/etc-lighttpd/external.conf:/etc/lighttpd/external.conf'
      - './pihole/etc-resolv.conf:/etc/resolv.conf'
      - './pihole/etc-letsencrypt:/etc/letsencrypt'
    dns:
     - '127.0.0.1'
     - '1.1.1.1'
    cap_add:
      - NET_ADMIN
      - NET_BIND_SERVICE
    labels:
      - 'sh.acme.autoload.domain=pi.domain.com'
    restart: unless-stopped

Expected Behaviour:

An access denied when I access the pihole web interface via the IP, pi hostname and pi.hole hostname.

Actual Behaviour:

I can still access the pi via the IP, pi hostname and pi.hole hostname.

Debug Token:

https://tricorder.pi-hole.net/mupofns18t

Have you tried making modifications to /etc/lighttpd/lighttpd.conf at all?

The default path rules in it are what opens things up to all hosts/IPs i believe, so that is at odds with your goal. You may have to move the default /admin rules into your external conf host block to get the behavior you're describing.

After that you could persist your changes with a volume mount (but be aware you may not get any updates to that file new versions contain)

Hi. Following your advice and fine tuning it afterwards I landed with this external.conf file that does the job:

$HTTP["url"] =~ "^/(.*)?" {
  url.access-deny = ("")
}

$HTTP["host"] == "pi.domain.com" {
  # Allow for this host
  $HTTP["url"] =~ "^/(.*)?" {
    url.access-allow  = ("")
  }

  # Ensure the Pi-hole Block Page knows that this is not a blocked domain
  setenv.add-environment = ("fqdn" => "true")

  # Enable the SSL engine with a LE cert, only for this specific host
  $SERVER["socket"] == ":443" {
    ssl.engine = "enable"
    ssl.pemfile = "/etc/letsencrypt/live/pi.domain.com/combined.pem"
    ssl.ca-file =  "/etc/letsencrypt/live/pi.domain.com/full.pem"
    ssl.honor-cipher-order = "enable"
    ssl.cipher-list = "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"
    ssl.use-sslv2 = "disable"
    ssl.use-sslv3 = "disable"
  }

  # Redirect HTTP to HTTPS
  $HTTP["scheme"] == "http" {
    $HTTP["host"] =~ ".*" {
      url.redirect = (".*" => "https://%0$0")
    }
  }
}

It gives a 403 for the IP address, pi, pi.hole and other hostnames via HTTP. It also fails the TLS setup (and rightfully so since it has no certificates) for the pi, pi.hole and other hostnames. It only tries to serve the wrong SSL certificate when using the IP, but I am not sure how to prevent this.

1 Like

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.