Network List Sync resolves hostnames to IPs and keeps provider-managed target lists in sync.
It supports multiple endpoint providers in one deployment, currently:
- UniFi
- Nginx Proxy Manager (NPM)
- Web UI for endpoint, DNS server, and sync job management
- Multi-target jobs (one job can update multiple endpoint/list pairs)
- Provider-aware endpoint model (UniFi and NPM side by side)
- Built-in local authentication with persistent server-side sessions
- First-start admin bootstrap (interactive in UI or via Docker environment)
- Cron scheduling with manual run support
- DNS preview before saving a job
- Hostname plus literal IPv4 and IPv4 CIDR inputs
- External URL list inputs (HTTP/HTTPS), for example Cloudflare IP ranges
- Run history and per-run details
- Single binary with embedded UI and SQLite persistence
Use this when upstream systems publish hostnames or changing IP ranges and you need list-based access control to stay current automatically.
Common examples:
- Probe/monitoring provider IPs that rotate over time
- Third-party integrations with DNS-based endpoints
- Mixed static and dynamic allow-lists
- Add one or more endpoints in the UI.
- Create a sync job with hostnames/IP inputs.
- Assign a primary target list and optional additional targets.
- Run manually or on schedule.
- The service resolves DNS, computes diffs, updates provider lists, and stores run history.
- Reachable endpoint URLs for each provider.
- Credentials/secrets with permission to update target lists.
- Provider-specific identity value if required:
- UniFi: site (usually default)
- NPM: identity/account value used by your environment
- Existing target list IDs in each provider.
- Persistent storage for the data directory.
This application is protected by login.
- First startup with no users: visiting
/loginshows an admin account creation form. - After setup:
/loginshows a standard sign-in form. - Sessions are server-side and stored in SQLite.
To create the first admin account automatically on container startup, set both env vars:
NLS_INITIAL_ADMIN_USERNAMENLS_INITIAL_ADMIN_PASSWORD
If users already exist, these values are ignored.
Run latest build from main:
docker run --rm -p 8080:8080 \
-v network-list-sync-data:/data \
ghcr.io/mstrhakr/network-list-sync:mainRun a stable release:
docker run --rm -p 8080:8080 \
-v network-list-sync-data:/data \
ghcr.io/mstrhakr/network-list-sync:v0.1.0Open http://localhost:8080.
Published platforms: linux/amd64 and linux/arm64.
See docs/docker-compose.unraid.yml.
services:
network-list-sync:
image: ghcr.io/mstrhakr/network-list-sync:main
container_name: network-list-sync
restart: unless-stopped
ports:
- "8080:8080"
environment:
PUID: "99"
PGID: "100"
UMASK: "022"
NLS_INITIAL_ADMIN_USERNAME: "admin"
NLS_INITIAL_ADMIN_PASSWORD: "change-this-immediately"
volumes:
- /mnt/user/appdata/network-list-sync:/datago run . -addr :8080go build -o network-list-sync .
./network-list-sync| Flag | Default | Description |
|---|---|---|
| -addr | :8080 | HTTP listen address |
| -db | sync.db | SQLite database path |
| -debug | false | Enable debug logs |
| -verbose | false | Enable verbose logs |
| -log-file | sync.log | Log file path (empty disables file logging) |
| -version | false | Print build version metadata and exit |
Environment variables:
| Variable | Description |
|---|---|
NLS_INITIAL_ADMIN_USERNAME |
Optional first-run admin username (must be paired with password) |
NLS_INITIAL_ADMIN_PASSWORD |
Optional first-run admin password (must be paired with username) |
Example:
./network-list-sync -addr :9090 -db /var/lib/sync/data.db -log-file ./sync.log- Open the app and go to Endpoints.
- Add at least one endpoint with provider, URL, identity/site, and secret.
- Test connection and save.
- Create a new sync job.
- Choose primary endpoint and primary target list.
- Add hostnames, IPv4, CIDR, or external URL list entries (one per line).
- Optionally add additional endpoint/list targets.
- Save and run the job.
- Review logs and target list state.
Example input:
# Grafana synthetic probes
synthetics.grafana.net
# Static office egress
203.0.113.10
203.0.113.0/24
# External source list
https://www.cloudflare.com/ips-v4
- Validate jobs with manual runs before enabling schedule.
- Keep data persisted under /data across container upgrades.
- Use exact release tags in production.
- Keep endpoint credentials scoped to minimum required permissions.
All /api/* endpoints require an authenticated session.
| Method | Path | Description |
|---|---|---|
| GET | /api/instances | List endpoints |
| POST | /api/instances | Create endpoint |
| GET | /api/instances/{id} | Get endpoint |
| PUT | /api/instances/{id} | Update endpoint |
| DELETE | /api/instances/{id} | Delete endpoint |
| GET | /api/instances/{id}/target-lists | List provider target lists |
| POST | /api/instances/test | Test endpoint connection |
| Method | Path | Description |
|---|---|---|
| GET | /api/jobs | List jobs |
| POST | /api/jobs | Create job |
| GET | /api/jobs/{id} | Get job |
| PUT | /api/jobs/{id} | Update job |
| DELETE | /api/jobs/{id} | Delete job and history |
| GET | /api/jobs/{id}/target-list | Get primary or selected target list state |
| POST | /api/jobs/{id}/run | Trigger immediate run |
| GET | /api/jobs/{id}/logs | Get job run history |
| Method | Path | Description |
|---|---|---|
| POST | /api/resolve | Preview DNS resolution |
| GET | /api/health | Health check |
| GET | /api/dns-servers | List DNS servers |
| POST | /api/dns-servers | Create DNS server |
| GET | /api/dns-servers/{id} | Get DNS server |
| PUT | /api/dns-servers/{id} | Update DNS server |
| DELETE | /api/dns-servers/{id} | Delete DNS server |
| Expression | Meaning |
|---|---|
| */30 * * * * | Every 30 minutes |
| 0 */6 * * * | Every 6 hours |
| 0 0 * * * | Daily at midnight |
| 0 0 * * 1 | Every Monday |
- Maintainer guide: docs/development.md
- Migration notes: docs/generic-migration-plan.md
- UniFi schema reference: docs/reference/unifi-network-10.1.85.json
The auth layer includes provider abstractions for both password and OIDC flows.
- Current provider: local password (
local) - Planned: OIDC providers can be registered without replacing the existing session model
MIT
