Skip to content

Steph-ux/bind9-web-ui

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

139 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

BIND9 Web UI

Self-hosted DNS control panel for BIND9.

BIND9 Web UI helps DNS operators manage BIND9 without hand-editing every zone and configuration file. It supports local management and remote management over SSH, with a dashboard for zones, records, ACLs, TSIG keys, RPZ, replication, backups, user access, and operational visibility.

Copyright (c) 2025 Stephane ASSOGBA

TypeScript Express React SQLite PostgreSQL MySQL License: MIT

Quick Links

One-Command Install

On Debian or Ubuntu:

git clone https://github.com/Steph-ux/bind9-web-ui.git && cd bind9-web-ui && sudo bash install.sh

The installer can deploy behind nginx, Apache, or no reverse proxy, and can run on the same host as BIND9 or on a separate management server.

Why This Exists

BIND9 is one of the most capable DNS servers available, but it still lacks an official management interface. In practice that means:

  • manual edits in multiple configuration files
  • easy-to-miss syntax mistakes
  • weak visibility across zones, access control, and runtime state
  • awkward remote administration when BIND runs on another host

This project fills that gap with a full web UI focused on operational safety and day-to-day administration.

Who It Is For

  • DNS administrators who run BIND9 in production or labs
  • Teams that want a self-hosted DNS management interface
  • Operators managing several BIND9 servers from one UI
  • Environments that need local control instead of a SaaS DNS platform

Core Features

DNS management

  • Create, edit, and delete DNS zones
  • Manage records for A, AAAA, CNAME, MX, TXT, NS, SOA, PTR, SRV, and more
  • Generate and parse BIND zone files automatically
  • Create reverse DNS and PTR records automatically when appropriate
  • Import existing zones and managed includes from an existing BIND installation

Access control and key management

  • Manage ACLs through dedicated BIND include files
  • Manage TSIG keys through dedicated include files
  • Configure zone transfer authorization more safely

RPZ / DNS firewall

  • Manage Response Policy Zone entries from the UI
  • Import RPZ data from text, zone-file style content, or remote URLs
  • Handle large blocklists with pagination and batch processing
  • Keep RPZ data synchronized with BIND-managed files

Remote server management

  • Add multiple BIND servers over SSH
  • Detect platform details and common BIND paths automatically
  • Switch the active target between local mode and remote mode
  • Run configuration reads, writes, validation, and rndc operations against the active target

Replication and operations

  • Register secondary or replication targets
  • Maintain zone-to-server bindings
  • Run sync operations and conflict detection
  • Send BIND notify actions where applicable

Monitoring and maintenance

  • Dashboard with server, DNS, and operational summaries
  • Status view for service health and runtime information
  • Real-time logs
  • Backups and restore flows
  • Configuration snapshots
  • User management and API tokens

Security controls

  • Session-based authentication
  • Role-based access control for admin, operator, and viewer roles
  • Forced password rotation for bootstrap users
  • Validation and sanitization across BIND-facing inputs
  • CSRF-aware authenticated mutations
  • SSRF protections for remote fetch and notification features

Management Model

The application supports two operating modes.

Local mode

The web UI runs on the same host as BIND9 and interacts with:

  • BIND configuration files
  • zone files
  • rndc
  • validation binaries such as named-checkconf and named-checkzone

Remote SSH mode

The web UI runs on a separate host and connects to a BIND server over SSH. The application executes commands and manages files remotely through the active SSH connection.

This is the mode used when the UI is deployed on a central management server and your BIND servers live elsewhere.

Important BIND Integration Notes

This project does not try to rewrite arbitrary BIND layouts blindly. A few conventions matter if you want the UI to manage everything cleanly.

Managed include files

ACLs and TSIG keys are managed through dedicated include files:

  • named.conf.acls
  • named.conf.keys

Your main BIND configuration should include them, for example:

include "/etc/bind/named.conf.acls";
include "/etc/bind/named.conf.keys";

If an ACL exists only inside named.conf.options, BIND will use it, but the ACL page in the UI will not import it as a managed ACL until it is moved to named.conf.acls.

Existing manual changes

The UI can import and reflect existing BIND configuration, but if you modify files manually outside the UI, the safest workflow is:

  1. make the manual BIND change
  2. validate it on the server
  3. use the relevant sync or refresh flow in the UI

Structural zone edits

Record-level edits are first-class in the UI. Some deeper structural zone changes are still safer to perform directly in BIND and then sync back into the application.

Tech Stack

Layer Technologies
Frontend React 19, Vite 7, TypeScript, Tailwind CSS 4, shadcn/ui, Wouter
Backend Node.js, Express 5, TypeScript
Data SQLite by default, with PostgreSQL and MySQL support via Drizzle ORM
Realtime WebSocket (ws)
Remote access ssh2
Validation Zod, drizzle-zod

Project Structure

Bind-Config/
├── client/              # React frontend
├── server/              # Express backend and BIND services
├── shared/              # Shared schemas and types
├── data/                # SQLite database and local data
├── script/              # Build scripts
├── DESIGN.md            # Active design system direction
└── README.md

Requirements

Development

  • Node.js 20+ recommended
  • npm
  • build tools required by native dependencies such as better-sqlite3

On Debian or Ubuntu:

sudo apt update
sudo apt install -y build-essential python3

BIND target

For local mode:

  • a host with BIND9 installed
  • access to BIND config and zone directories
  • rndc, named-checkconf, and named-checkzone

For remote mode:

  • SSH access to the target server
  • a user with sufficient file and command permissions
  • passwordless sudo for required BIND operations if the user is not already privileged

Quick Start

Production install

On Debian or Ubuntu:

git clone https://github.com/Steph-ux/bind9-web-ui.git
cd bind9-web-ui
sudo bash install.sh

As a single shell line:

git clone https://github.com/Steph-ux/bind9-web-ui.git && cd bind9-web-ui && sudo bash install.sh

Default install:

  • app installed in /opt/bind9-web-ui
  • env file in /etc/bind9-web-ui.env
  • systemd service bind9-web-ui
  • nginx reverse proxy on https://<server-ip>:8443
  • Node.js listens locally on 127.0.0.1:3001
  • generated admin password stored in /root/bind9-web-ui-bootstrap-admin.txt

Install options

Set the initial admin password:

sudo env DEFAULT_ADMIN_PASSWORD='change-me-now' bash install.sh

Use Apache instead of nginx:

sudo env WEB_SERVER=apache bash install.sh

Use nginx on ports 80/443:

sudo env WEB_SERVER=nginx WEB_HTTP_PORT=80 WEB_HTTPS_PORT=443 SERVER_NAME=dns.example.com bash install.sh

Use Apache on ports 80/443:

sudo env WEB_SERVER=apache WEB_HTTP_PORT=80 WEB_HTTPS_PORT=443 SERVER_NAME=dns.example.com bash install.sh

Install without nginx/apache:

sudo env WEB_SERVER=none bash install.sh

WEB_SERVER can be nginx, apache, or none. If WEB_SERVER=none, put your own TLS reverse proxy in front of the Node.js service.

To replace the default web site on the server:

sudo env DISABLE_DEFAULT_SITE=1 WEB_HTTP_PORT=80 WEB_HTTPS_PORT=443 SERVER_NAME=dns.example.com bash install.sh

Install on the BIND server

If the Web UI runs on the same host as BIND9:

sudo env LOCAL_BIND_ACCESS=1 bash install.sh

This lets systemd write to the configured BIND directories and adds the service user to the BIND group when it exists. If BIND files are root-only, local writes may still fail; use an SSH connection to localhost with sudo, or adjust permissions deliberately.

Manual development start

1. Clone the repository

git clone https://github.com/Steph-ux/bind9-web-ui.git
cd bind9-web-ui

2. Install dependencies

npm install

3. Initialize the database

npm run db:push

4. Start development mode

On Windows:

npm run dev

Then open:

http://localhost:3001

5. First login

On first startup, a bootstrap admin account is created automatically.

  • Username: admin
  • Password: the value of DEFAULT_ADMIN_PASSWORD, if set
  • Otherwise: a generated bootstrap password is created

In production, the bootstrap password is not written to logs. Set DEFAULT_ADMIN_PASSWORD before first startup if you want a known initial password.

Production Build

Build the application:

npm run build

Start the compiled server:

node dist/index.cjs

Set NODE_ENV=production in your environment or service manager.

Note:

  • npm start is currently written for Windows-style environment variable syntax
  • for Linux services, prefer setting NODE_ENV=production in systemd, Docker, or your shell and launching node dist/index.cjs

Environment Variables

The repository already includes an .env.example.

Variable Default Description
HOST 0.0.0.0 Bind address for the Node.js server
PORT 3001 HTTP port for the application
NODE_ENV development Runtime mode
SESSION_SECRET random in development Mandatory in production
DB_TYPE sqlite sqlite, postgresql, or mysql
DATABASE_URL data/bind9admin.db SQLite path or database connection URL
BACKUP_DIR data/backups Runtime backup directory
BIND9_CONF_DIR /etc/bind Local-mode BIND config directory
BIND9_ZONE_DIR /var/cache/bind Local-mode zone directory
RNDC_BIN rndc Path to the rndc binary
NAMED_CHECKCONF named-checkconf Path to the config validation binary
DEFAULT_ADMIN_PASSWORD unset Optional initial bootstrap admin password

Database Backends

SQLite is the default and easiest option. PostgreSQL and MySQL are also supported.

SQLite

No extra setup is required beyond:

npm run db:push

PostgreSQL

Set:

DB_TYPE=postgresql
DATABASE_URL=postgresql://user:password@host:5432/dbname

Then push the schema.

On Windows:

npm run db:push:pg

On Linux:

DB_TYPE=postgresql npx drizzle-kit push --config=drizzle.config.pg.ts

MySQL

Set:

DB_TYPE=mysql
DATABASE_URL=mysql://user:password@host:3306/dbname

Then push the schema.

On Windows:

npm run db:push:mysql

On Linux:

DB_TYPE=mysql npx drizzle-kit push --config=drizzle.config.mysql.ts

Development Scripts

Script Purpose
npm run dev Start the server in development mode
npm run dev:client Start only the Vite client
npm run build Build the client and server for production
npm start Windows-oriented production start shortcut
npm run check Run TypeScript checks
npm run db:push Push the SQLite schema
npm run db:push:pg Push the PostgreSQL schema
npm run db:push:mysql Push the MySQL schema

Remote BIND Permissions

For remote SSH management, the SSH user may need passwordless sudo for BIND commands and safe file operations. A typical example looks like this:

<user> ALL=(ALL) NOPASSWD: /usr/sbin/rndc, /usr/bin/named-checkconf, /usr/bin/named-checkzone, /bin/cp, /usr/bin/cp

Adjust this to your platform and operational policy.

If you also use firewall management through the UI, you may need additional sudo permissions for tools such as:

  • ufw
  • nft
  • iptables
  • firewall-cmd
  • systemctl

BIND Reload After Web UI Changes

When a record is created or updated from the Web UI, the zone file must be valid and BIND must reload the affected zone before clients can resolve the new data.

If the zone file contains the new record but DNS queries still return NXDOMAIN or an older SOA serial, BIND is still serving the previous in-memory zone. Validate the zone and reload it:

sudo named-checkconf
sudo named-checkzone intra.isoceltelecom.com /var/cache/bind/zones/forward/intra.isoceltelecom.com
sudo rndc reload intra.isoceltelecom.com

For deployments where the Web UI writes BIND zone files directly, use an automatic reload guard so changes are applied only after validation succeeds:

# /etc/systemd/system/bind-zones-auto-reload.service
[Unit]
Description=Validate and reload BIND zones after Web UI changes
After=named.service

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/bind-zones-reload-if-valid.sh
# /etc/systemd/system/bind-zones-auto-reload.path
[Unit]
Description=Watch BIND zone files for Web UI changes

[Path]
PathChanged=/var/cache/bind/zones/forward/intra.isoceltelecom.com
PathChanged=/var/cache/bind/zones/reverse/intra.isoceltelecom.com
Unit=bind-zones-auto-reload.service

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now bind-zones-auto-reload.path

The reload script should run named-checkconf, validate every managed zone with named-checkzone, and then call rndc reload <zone>. This prevents the UI from reporting a saved record while BIND continues serving stale data.

Security Highlights

  • Passwords are hashed using Node.js crypto primitives
  • Sessions are hardened with strict cookie settings in production
  • Login throttling and IP ban logic are built in
  • Mutating routes require authenticated, same-site-safe flows
  • API tokens support scoped access
  • BIND-facing input is validated and sanitized
  • Remote fetch and notification targets are checked to reduce SSRF risk
  • Sensitive fields are masked in API responses where appropriate

Operational Notes

  • The UI applies supported changes automatically to the active BIND target
  • Configuration writes are validated before reload or reconfigure actions are considered successful
  • If an operation fails, the UI is expected to surface the error instead of reporting a false success
  • Backups are stored under the application data directory
  • Real-time logs and status views are available even when some local-only BIND metrics are not

Recommended Production Setup

  • run the web UI behind HTTPS
  • set a strong SESSION_SECRET
  • set DEFAULT_ADMIN_PASSWORD only for initial bootstrap, then rotate it
  • prefer SSH key authentication over password authentication
  • restrict SSH access tightly
  • keep remote sudo permissions minimal
  • use PostgreSQL or MySQL if you need a database backend beyond local SQLite
  • monitor the host and back up the application data directory

Contributing

Contributions are welcome. Start with CONTRIBUTING.md, run npm run check before opening a pull request, and include enough context for DNS/BIND-related changes to be reviewed safely.

Security

Do not post secrets, real zone exports, private keys, or production screenshots in public issues. See SECURITY.md for reporting guidance.

License

MIT License. See LICENSE.

About

BIND9 Web UI is a self-hosted DNS control panel that replaces manual config file editing with a full-featured dashboard. Manage zones, DNS records, ACLs, TSIG keys, and firewall rules across local and remote BIND9 servers via SSH. Supports UFW, firewalld, nftables and iptables with auto-detection.

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages