Skip to main content

Automated domain blocking controller for NextDNS with per-domain scheduling

Project description

NextDNS Blocker

PyPI version Python versions CI

Automated system to control domain access with per-domain schedule configuration using the NextDNS API.

Features

  • Per-domain scheduling: Configure unique availability hours for each domain
  • Flexible time ranges: Multiple time windows per day, different schedules per weekday
  • Protected domains: Mark domains as protected to prevent accidental unblocking
  • Pause/Resume: Temporarily disable blocking without changing configuration
  • Automatic synchronization: Runs every 2 minutes via cron with watchdog protection
  • Timezone-aware: Respects configured timezone for schedule evaluation
  • Secure: File permissions, input validation, and audit logging
  • NextDNS API integration: Works via NextDNS denylist
  • Dry-run mode: Preview changes without applying them
  • Smart caching: Reduces API calls with intelligent denylist caching
  • Rate limiting: Built-in protection against API rate limits
  • Exponential backoff: Automatic retries with increasing delays on failures

Requirements

  • Python 3.9+
  • NextDNS account with API key
  • Linux/macOS/Windows

Installation

Option 1: Install from PyPI (Recommended)

pip install nextdns-blocker

Then run the setup wizard:

nextdns-blocker init

Option 2: Install from Source

git clone https://github.com/aristeoibarra/nextdns-blocker.git
cd nextdns-blocker
pip install -e .
nextdns-blocker init

Quick Setup

1. Get NextDNS Credentials

2. Run Setup Wizard

nextdns-blocker init

The wizard will prompt for:

  • API Key
  • Profile ID
  • Timezone
  • Option to create sample domains.json

3. Configure Domains and Schedules

Edit domains.json in your config directory to configure your domains and their availability schedules.

See SCHEDULE_GUIDE.md for detailed schedule configuration examples.

4. Install Watchdog (Optional)

For automatic syncing every 2 minutes with cron:

nextdns-blocker watchdog install

Done! The system will now automatically sync based on your configured schedules.

Docker Setup

Alternatively, run NextDNS Blocker using Docker:

1. Configure Environment

cp .env.example .env
nano .env  # Add your API key, profile ID, and timezone

2. Configure Domains

cp domains.json.example domains.json
nano domains.json  # Configure your domains and schedules

3. Run with Docker Compose

docker compose up -d

Docker Commands

# View logs
docker compose logs -f

# Stop the container
docker compose down

# Rebuild after changes
docker compose up -d --build

# Check status
docker compose ps

# Run a one-time sync
docker compose exec nextdns-blocker python nextdns_blocker.py sync -v

# Check blocking status
docker compose exec nextdns-blocker python nextdns_blocker.py status

Environment Variables for Docker

Variable Required Default Description
NEXTDNS_API_KEY Yes - Your NextDNS API key
NEXTDNS_PROFILE_ID Yes - Your NextDNS profile ID
DOMAINS_URL No - URL to fetch domains.json remotely
TZ No America/Mexico_City Container timezone

Commands

Main Blocker Commands

# Sync based on schedules (runs automatically every 2 min)
nextdns-blocker sync

# Preview what sync would do without making changes
nextdns-blocker sync --dry-run

# Sync with verbose output showing all actions
nextdns-blocker sync --verbose
nextdns-blocker sync -v

# Check current blocking status
nextdns-blocker status

# Manually unblock a domain (won't work on protected domains)
nextdns-blocker unblock example.com

# Pause all blocking for 30 minutes (default)
nextdns-blocker pause

# Pause for custom duration (e.g., 60 minutes)
nextdns-blocker pause 60

# Resume blocking immediately
nextdns-blocker resume

Watchdog Commands

# Check cron status
nextdns-blocker watchdog status

# Disable watchdog for 30 minutes
nextdns-blocker watchdog disable 30

# Disable watchdog permanently
nextdns-blocker watchdog disable

# Re-enable watchdog
nextdns-blocker watchdog enable

# Manually install cron jobs
nextdns-blocker watchdog install

# Remove cron jobs
nextdns-blocker watchdog uninstall

Logs

# View application logs
tail -f ~/.local/share/nextdns-blocker/logs/app.log

# View audit log (all blocking/unblocking actions)
cat ~/.local/share/nextdns-blocker/logs/audit.log

# View cron execution logs
tail -f ~/.local/share/nextdns-blocker/logs/cron.log

# View watchdog logs
tail -f ~/.local/share/nextdns-blocker/logs/wd.log

# View cron jobs
crontab -l

Configuration

Environment Variables (.env)

Variable Required Default Description
NEXTDNS_API_KEY Yes - Your NextDNS API key
NEXTDNS_PROFILE_ID Yes - Your NextDNS profile ID
TIMEZONE No UTC Timezone for schedule evaluation
API_TIMEOUT No 10 API request timeout in seconds
API_RETRIES No 3 Number of retry attempts
DOMAINS_URL No - URL to fetch domains.json from

Domain Schedules

Edit domains.json to configure which domains to manage and their availability schedules:

{
  "domains": [
    {
      "domain": "reddit.com",
      "description": "Social media",
      "protected": false,
      "schedule": {
        "available_hours": [
          {
            "days": ["monday", "tuesday", "wednesday", "thursday", "friday"],
            "time_ranges": [
              {"start": "12:00", "end": "13:00"},
              {"start": "18:00", "end": "22:00"}
            ]
          },
          {
            "days": ["saturday", "sunday"],
            "time_ranges": [
              {"start": "10:00", "end": "22:00"}
            ]
          }
        ]
      }
    },
    {
      "domain": "gambling-site.com",
      "description": "Always blocked",
      "protected": true,
      "schedule": null
    }
  ]
}

Domain Configuration Options

Field Required Description
domain Yes Domain name to manage
description No Human-readable description
protected No If true, domain cannot be manually unblocked
schedule No Availability schedule (null = always blocked)

Changes take effect on next sync (every 2 minutes).

See SCHEDULE_GUIDE.md for complete documentation and examples.

Allowlist (Exceptions)

Use the allowlist to keep specific subdomains accessible even when their parent domain is blocked:

{
  "domains": [
    {
      "domain": "amazon.com",
      "description": "E-commerce - blocked with schedule",
      "schedule": { ... }
    }
  ],
  "allowlist": [
    {
      "domain": "aws.amazon.com",
      "description": "AWS Console - always accessible"
    },
    {
      "domain": "developer.amazon.com",
      "description": "Amazon Developer - always accessible"
    }
  ]
}

Allowlist Behavior

  • Allowlist entries are always active 24/7 (no schedule support)
  • A domain cannot be in both domains (denylist) and allowlist
  • Use for subdomain exceptions: block amazon.com but allow aws.amazon.com
  • Changes sync automatically every 2 minutes

Allowlist Commands

# Add domain to allowlist (always accessible)
nextdns-blocker allow aws.amazon.com

# Remove domain from allowlist
nextdns-blocker disallow aws.amazon.com

# View current status including allowlist
nextdns-blocker status

Timezone

Edit .env to change timezone:

TIMEZONE=America/New_York

See list of timezones.

Troubleshooting

Sync not working?

  • Check cron: crontab -l (should see sync job running every 2 minutes)
  • Check logs: tail -f ~/.local/share/nextdns-blocker/logs/app.log
  • Test manually: nextdns-blocker sync
  • Validate JSON: python3 -m json.tool domains.json

Domains.json errors?

  • Ensure valid JSON syntax (use jsonlint.com)
  • Check time format is HH:MM (24-hour)
  • Check day names are lowercase (monday, tuesday, etc.)
  • Domain names must be valid (no spaces, special characters)
  • See domains.json.example for reference

Wrong timezone?

  • Update TIMEZONE in .env
  • Re-run ./install.sh
  • Check logs to verify timezone is being used

API timeouts?

  • Increase API_TIMEOUT in .env (default: 10 seconds)
  • Increase API_RETRIES in .env (default: 3 attempts)

Cron not running?

# Check cron service status
sudo service cron status || sudo service crond status

# Check watchdog status
nextdns-blocker watchdog status

Uninstall

# Remove cron jobs
nextdns-blocker watchdog uninstall

# Remove files
rm -rf ~/nextdns-blocker

# Remove logs (optional)
rm -rf ~/.local/share/nextdns-blocker

Log Rotation

To prevent log files from growing indefinitely, set up log rotation:

chmod +x setup-logrotate.sh
./setup-logrotate.sh

This configures automatic rotation with:

  • app.log: daily, 7 days retention
  • audit.log: weekly, 12 weeks retention
  • cron.log: daily, 7 days retention
  • wd.log: daily, 7 days retention

Development

Running Tests

pip install -e ".[dev]"
pytest tests/ -v

Test Coverage

pytest tests/ --cov=nextdns_blocker --cov-report=html

Current coverage: 85% with 379 tests.

Code Quality

The codebase follows these practices:

  • Type hints on all functions
  • Docstrings with Args/Returns documentation
  • Custom exceptions for error handling
  • Secure file permissions (0o600)
  • Input validation before API calls

Documentation

Security

  • Never share your .env file (contains API key)
  • .gitignore is configured to ignore sensitive files
  • All API requests use HTTPS
  • Sensitive files created with 0o600 permissions
  • Domain names validated before API calls
  • Audit log tracks all blocking/unblocking actions

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nextdns_blocker-5.0.1.tar.gz (57.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nextdns_blocker-5.0.1-py3-none-any.whl (34.0 kB view details)

Uploaded Python 3

File details

Details for the file nextdns_blocker-5.0.1.tar.gz.

File metadata

  • Download URL: nextdns_blocker-5.0.1.tar.gz
  • Upload date:
  • Size: 57.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for nextdns_blocker-5.0.1.tar.gz
Algorithm Hash digest
SHA256 4b73175d61543f65540c1d2ef9135de25ddf6aa54225bf0a2618238f5ef1f2e8
MD5 9b9a6da1a6dc8cc6a2959eeeccc8a987
BLAKE2b-256 7d70fda1686775d324b6749bc06ef7c6d7a4206d179c81a3cef79aafc157cc7d

See more details on using hashes here.

Provenance

The following attestation bundles were made for nextdns_blocker-5.0.1.tar.gz:

Publisher: publish.yml on aristeoibarra/nextdns-blocker

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file nextdns_blocker-5.0.1-py3-none-any.whl.

File metadata

File hashes

Hashes for nextdns_blocker-5.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 097402f5a99c3152ab541eeab49c1874d6550c438f7ca18d2fb8c7bdae7b11dd
MD5 0ffd26cd4be4d4bf643de6aed7301ef2
BLAKE2b-256 394762293d0dda6d42330a2235e192f604ae778f91fb6cd0f6694bd5a499c084

See more details on using hashes here.

Provenance

The following attestation bundles were made for nextdns_blocker-5.0.1-py3-none-any.whl:

Publisher: publish.yml on aristeoibarra/nextdns-blocker

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page