Deploying Secure BIND9 DNS Service with NGINX on RHEL/CentOS/Rocky/Fedora

This guide covers deploying BIND9 DNS alongside an already-installed NGINX instance for providing secure DNS services including DoH and DoT. This configuration supports advanced SELinux policies and offloading TLS/HTTPS through NGINX.


1. BIND9 Installation

The default BIND version in RHEL 9 repositories is 9.16 (Extended Support), which does not support DNS-over-TLS (DoT) for forwarders.

To use DoT forwarders (requires BIND 9.19+), consider using the official ISC Fedora COPR repository:

https://copr.fedorainfracloud.org/coprs/isc/bind

For installation instructions, refer to the RHEL documentation:

RHEL 9: Setting up and Configuring BIND


2. SELinux Configuration for BIND9

When installing BIND in a non-standard location (e.g., /opt/isc), SELinux contexts must be explicitly set:

chcon -t named_exec_t /opt/isc/isc-bind/root/usr/sbin/named

Verify Current Allowed Ports:

semanage port -l | grep http_port_t
semanage port -l | grep dns_port_t

Add Custom TCP Ports for Local BIND Listening:

We will use the following ports for local unencrypted access by NGINX:

  • TCP 753: DNS-over-TLS local endpoint
  • TCP 8458: DoH local endpoint
sudo semanage port -a -t dns_port_t -p tcp 753
sudo semanage port -a -t dns_port_t -p tcp 8458

For NGINX to access TLS-based DNS forwarding:

sudo semanage port -a -t http_port_t -p tcp 853

3. BIND Configuration


http local-http-server { endpoints { "/dns-query"; }; };

options {
  listen-on port 753 tls ephemeral { 127.0.0.1; };
  http-port 8458;
  listen-on port 8458 tls ephemeral http local-http-server { 127.0.0.1; };

  allow-query       { 127.0.0.1; };
  allow-query-cache { localhost; };
  allow-recursion   { 127.0.0.1; };
  recursion yes;
};

Optional: Configure DoT Forwarders (Cloudflare Example)


tls cloudflare-tls { remote-hostname "one.one.one.one"; };

options {
  forwarders port 853 {
    1.1.1.1 tls cloudflare-tls;
    1.0.0.1 tls cloudflare-tls;
  };
};

Note: If you are not using DoT, forward on port 53 instead.


4. NGINX Configuration for Reverse Proxying DNS

Install the stream module if not already present:

sudo dnf install nginx-mod-stream

DoH Pass-through (GRPC over HTTP)


http {
  upstream doh-servers {
    zone doh-servers 64k;
    server 127.0.0.1:8458;
    keepalive_timeout 60s;
    keepalive_requests 100;
    keepalive 10;
  }

  server {
    listen 443 ssl http2;
    ssl_certificate /etc/ssl/certs/your_cert.pem;
    ssl_certificate_key /etc/ssl/private/your_key.key;

    location /dns-query {
      proxy_set_header Connection "";
      grpc_pass grpcs://doh-servers;
    }
  }
}

DoT and DNS-over-UDP Pass-through (Stream Block)


stream {
  upstream dns_servers {
    zone dns_servers 64k;
    server 127.0.0.1:753;
  }

  server {
    listen 853 ssl;
    ssl_certificate /etc/ssl/certs/your_cert.pem;
    ssl_certificate_key /etc/ssl/private/your_key.key;
    proxy_pass dns_servers;
  }

  server {
    listen 53 udp;
    listen 53;
    proxy_pass dns_servers;
  }
}

5. Firewall Configuration

Allow required ports through firewalld:


sudo firewall-cmd --zone=public --add-port=853/tcp --permanent
sudo firewall-cmd --zone=public --add-port=53/tcp --permanent
sudo firewall-cmd --zone=public --add-port=53/udp --permanent
sudo firewall-cmd --reload

Note: Port 443 is likely already open for HTTPS/DoH traffic.


6. Testing & Debugging

Test DNS responses using dig and resolvectl. Verify the NGINX reverse proxy is relaying requests properly. Check logs under:

  • /var/log/nginx/access.log
  • /var/log/nginx/error.log
  • /var/named/data/named.run (or similar, depending on your BIND config)

Use setenforce 0 only temporarily for debugging SELinux issues. Always return to setenforce 1 and address issues using audit2allow or direct SELinux rules.


7. Final Notes

This setup results in a high-performance, secure DNS server using modern protocols and strict access controls.

Warning: Do not misuse this infrastructure (e.g., forging DNS responses, inserting root CAs into client devices, etc.). This guide is intended for ethical hosting and self-use scenarios only. Be responsible. Be secure. Be happy.