rss logo

Setting Up a Web Filtering Server with Unbound and RPZ on Linux

Unbound Logo

I was looking for a way to implement Web Filtering on GNU/Linux. While I knew about using squidguard for that purpose, it proved to be quite complicated to set up and particularly challenging to deploy automatically on every workstation, especially when not managed by an Active Directory domain. That's when I came across the DynFi Open Source firewall, which is capable of Web Filtering and utilizes RPZ to achieve this. Thus, I started studying this solution and found a way to implement Web Filtering with RPZ.

Network diagram

In this architecture, we will have a Debian serving as both a DNS and a web server. When a client request for a site that is forbidden (as per a pre-established blocklist), they will be redirected to the web server, where a blocked web page message will be displayed in their browsers.

  • Prerequisites:
    • Block port 53 (UDP and TCP) on your gateway to prevent workstations from making requests to external DNS servers.
Network diagram illustrating a blocked web request from a workstation to an Unbound DNS server

Debian Server

Debian Logo

As described above, we will have two services running on our Debian server: a web server to display a simple text message informing users that they are attempting to connect to a forbidden website, and a DNS service to provide clients with correct or modified DNS responses. For the web server, I will use micro-httpd, which is a lightweight HTTP server that perfectly suits our needs, and Unbound as the DNS server.


To inform users that the requested page is blocked, we will require a web server that will display a denied web page, informing them that the website they are trying to access is forbidden.


  • Install micro-httpd package:
root@host:~# apt install micro-httpd


  • Edit /etc/initd.conf:
www stream tcp nowait nobody:www-data /usr/sbin/tcpd /usr/sbin/micro-httpd /var/www/html
  • Create an /var/www/html/index.html file and set the appropriate permissions:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Access Forbidden</title> </head> <body> <h1>Access Forbidden</h1> <p>Sorry, but you do not have permission to access this page.</p> </body> </html> root@host:~# chown -R www-data:www-data /var/www/html

Open a web browser and navigate to to verify if you can see the blocked web page.



  • Install unbound package:
root@host:~# apt install unbound


  • Create a /etc/unbound/unbound.conf.d/rpz.conf file:
server: module-config: "respip validator iterator" # Load respip, validator, and iterator modules interface: # Network interface used for DNS queries interface: # Loopback interface used for local DNS queries do-ip4: yes # Enable IPv4 support do-ip6: no # Disable IPv6 support do-udp: yes # Enable UDP support for DNS queries do-tcp: yes # Enable TCP support for DNS queries do-daemonize: yes # Run Unbound as a daemon (in the background) access-control: allow # Allow all IP addresses to make DNS queries local-zone: "std.priv." static # Define a local zone for DNS queries local-data: "denied.std.priv. IN A" # Define a local DNS entry for a specific domain local-data-ptr: " denied.std.priv." # Define a local DNS PTR entry for a specific IP address rpz: name: # RPZ zone name zonefile: /etc/unbound/ # RPZ zone file used for DNS query filtering
  • Create a /etc/unbound/ file where, for testing purposes, we will redirect every request for and to our blocked web page:
* IN A * IN A
  • Restart unbound service:
root@host:~# systemctl restart unbound


  • From the workstation, try to open You should be redirected to the blocking page:
Screenshot of Firefox browser displaying 'Access Forbidden' page
  • When we make a DNS request, we observe that and are being redirected to the address:
Screenshot of Windows Command Prompt (CMD) window with two 'nslookup' commands

The Download and Application of a Block List

Now that we have built our web filtering system, it is time to make it useful. To do so, we will download a block list file and format it to make it work with our architecture. There are many different lists available on the internet (search for RPZ block list). Let's try one of the lists available on

  • Available RPZ lists come in this format: CNAME .
  • However, to be useful in our case, we need to have this format: IN A

So, how can we translate the default format to the one useful in our architecture, as seen above? There are different approaches, but personally, I will use the sed editor. Let's see how to do that!

  • First, download one of the RPZ lists:
root@host:~# wget
  • Then, format it using sed:
root@host:~# sed -i 's/CNAME.*/IN A' multi.txt

Note: To prevent users from bypassing the policy, I recommend adding a DoH/VPN/TOR/Proxy list and blocking DoH IP addresses on your firewall. (Check this list:

Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

Contact :

contact mail address