{"id":51594188,"url":"https://github.com/mstrhakr/network-list-sync","last_synced_at":"2026-07-11T17:01:17.660Z","repository":{"id":362682507,"uuid":"1259735451","full_name":"mstrhakr/network-list-sync","owner":"mstrhakr","description":"Network List Sync resolves hostnames to IPs and keeps provider-managed target lists in sync.","archived":false,"fork":false,"pushed_at":"2026-06-05T12:05:09.000Z","size":234,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-05T13:21:03.708Z","etag":null,"topics":["access-list","dns","network-list","nginx-proxy-manager","sync","unifi"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mstrhakr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-04T20:03:37.000Z","updated_at":"2026-06-05T12:07:54.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/mstrhakr/network-list-sync","commit_stats":null,"previous_names":["mstrhakr/network-list-sync"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/mstrhakr/network-list-sync","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mstrhakr%2Fnetwork-list-sync","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mstrhakr%2Fnetwork-list-sync/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mstrhakr%2Fnetwork-list-sync/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mstrhakr%2Fnetwork-list-sync/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mstrhakr","download_url":"https://codeload.github.com/mstrhakr/network-list-sync/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mstrhakr%2Fnetwork-list-sync/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35368768,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-11T02:00:05.354Z","response_time":104,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["access-list","dns","network-list","nginx-proxy-manager","sync","unifi"],"created_at":"2026-07-11T17:01:14.494Z","updated_at":"2026-07-11T17:01:17.652Z","avatar_url":"https://github.com/mstrhakr.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Network List Sync\n\n[![CI](https://img.shields.io/github/actions/workflow/status/mstrhakr/network-list-sync/ci.yml?branch=main\u0026label=ci)](https://github.com/mstrhakr/network-list-sync/actions/workflows/ci.yml)\n[![Latest Release](https://img.shields.io/github/v/release/mstrhakr/network-list-sync?display_name=tag)](https://github.com/mstrhakr/network-list-sync/releases/latest)\n[![Go Report Card](https://img.shields.io/badge/go%20report-A%2B-brightgreen?logo=go)](https://goreportcard.com/report/github.com/mstrhakr/network-list-sync)\n[![Go Version](https://img.shields.io/github/go-mod/go-version/mstrhakr/network-list-sync)](https://github.com/mstrhakr/network-list-sync/blob/main/go.mod)\n[![License](https://img.shields.io/github/license/mstrhakr/network-list-sync)](LICENSE)\n\n![Banner](./docs/banner.png)\n\nNetwork List Sync resolves hostnames to IPs and keeps provider-managed target lists in sync.\n\nIt supports multiple endpoint providers in one deployment, currently:\n\n- UniFi\n- Nginx Proxy Manager (NPM)\n\n## Features\n\n- Web UI for endpoint, DNS server, and sync job management\n- Multi-target jobs (one job can update multiple endpoint/list pairs)\n- Provider-aware endpoint model (UniFi and NPM side by side)\n- Built-in local authentication with persistent server-side sessions\n- First-start admin bootstrap (interactive in UI or via Docker environment)\n- Cron scheduling with manual run support\n- DNS preview before saving a job\n- Hostname plus literal IPv4 and IPv4 CIDR inputs\n- External URL list inputs (HTTP/HTTPS), for example Cloudflare IP ranges\n- Run history and per-run details\n- Single binary with embedded UI and SQLite persistence\n\n## Why Use It\n\nUse this when upstream systems publish hostnames or changing IP ranges and you need list-based access control to stay current automatically.\n\nCommon examples:\n\n- Probe/monitoring provider IPs that rotate over time\n- Third-party integrations with DNS-based endpoints\n- Mixed static and dynamic allow-lists\n\n## How It Works\n\n1. Add one or more endpoints in the UI.\n2. Create a sync job with hostnames/IP inputs.\n3. Assign a primary target list and optional additional targets.\n4. Run manually or on schedule.\n5. The service resolves DNS, computes diffs, updates provider lists, and stores run history.\n\n## Before You Start\n\n1. Reachable endpoint URLs for each provider.\n2. Credentials/secrets with permission to update target lists.\n3. Provider-specific identity value if required:\n   - UniFi: site (usually default)\n   - NPM: identity/account value used by your environment\n4. Existing target list IDs in each provider.\n5. Persistent storage for the data directory.\n\n## Authentication\n\nThis application is protected by login.\n\n- First startup with no users: visiting `/login` shows an admin account creation form.\n- After setup: `/login` shows a standard sign-in form.\n- Sessions are server-side and stored in SQLite.\n\n### Docker Initial Admin Bootstrap\n\nTo create the first admin account automatically on container startup, set both env vars:\n\n- `NLS_INITIAL_ADMIN_USERNAME`\n- `NLS_INITIAL_ADMIN_PASSWORD`\n\nIf users already exist, these values are ignored.\n\n## Quick Start\n\n### Docker (Recommended)\n\nRun latest build from main:\n\n```bash\ndocker run --rm -p 8080:8080 \\\n  -v network-list-sync-data:/data \\\n  ghcr.io/mstrhakr/network-list-sync:main\n```\n\nRun a stable release:\n\n```bash\ndocker run --rm -p 8080:8080 \\\n  -v network-list-sync-data:/data \\\n  ghcr.io/mstrhakr/network-list-sync:v0.1.0\n```\n\nOpen http://localhost:8080.\n\nPublished platforms: linux/amd64 and linux/arm64.\n\n### Docker Compose (Example)\n\nSee [docs/docker-compose.unraid.yml](docs/docker-compose.unraid.yml).\n\n```yaml\nservices:\n  network-list-sync:\n    image: ghcr.io/mstrhakr/network-list-sync:main\n    container_name: network-list-sync\n    restart: unless-stopped\n    ports:\n      - \"8080:8080\"\n    environment:\n      PUID: \"99\"\n      PGID: \"100\"\n      UMASK: \"022\"\n      NLS_INITIAL_ADMIN_USERNAME: \"admin\"\n      NLS_INITIAL_ADMIN_PASSWORD: \"change-this-immediately\"\n    volumes:\n      - /mnt/user/appdata/network-list-sync:/data\n```\n\n### Run From Source\n\n```bash\ngo run . -addr :8080\n```\n\n### Build Binary\n\n```bash\ngo build -o network-list-sync .\n./network-list-sync\n```\n\n## Runtime Flags\n\n| Flag | Default | Description |\n|------|---------|-------------|\n| -addr | :8080 | HTTP listen address |\n| -db | sync.db | SQLite database path |\n| -debug | false | Enable debug logs |\n| -verbose | false | Enable verbose logs |\n| -log-file | sync.log | Log file path (empty disables file logging) |\n| -version | false | Print build version metadata and exit |\n\nEnvironment variables:\n\n| Variable | Description |\n|----------|-------------|\n| `NLS_INITIAL_ADMIN_USERNAME` | Optional first-run admin username (must be paired with password) |\n| `NLS_INITIAL_ADMIN_PASSWORD` | Optional first-run admin password (must be paired with username) |\n\nExample:\n\n```bash\n./network-list-sync -addr :9090 -db /var/lib/sync/data.db -log-file ./sync.log\n```\n\n## UI Setup Walkthrough\n\n1. Open the app and go to Endpoints.\n2. Add at least one endpoint with provider, URL, identity/site, and secret.\n3. Test connection and save.\n4. Create a new sync job.\n5. Choose primary endpoint and primary target list.\n6. Add hostnames, IPv4, CIDR, or external URL list entries (one per line).\n7. Optionally add additional endpoint/list targets.\n8. Save and run the job.\n9. Review logs and target list state.\n\nExample input:\n\n```text\n# Grafana synthetic probes\nsynthetics.grafana.net\n\n# Static office egress\n203.0.113.10\n203.0.113.0/24\n\n# External source list\nhttps://www.cloudflare.com/ips-v4\n```\n\n## Operational Tips\n\n1. Validate jobs with manual runs before enabling schedule.\n2. Keep data persisted under /data across container upgrades.\n3. Use exact release tags in production.\n4. Keep endpoint credentials scoped to minimum required permissions.\n\n## API Endpoints\n\nAll `/api/*` endpoints require an authenticated session.\n\n### Endpoints/Instances\n\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /api/instances | List endpoints |\n| POST | /api/instances | Create endpoint |\n| GET | /api/instances/{id} | Get endpoint |\n| PUT | /api/instances/{id} | Update endpoint |\n| DELETE | /api/instances/{id} | Delete endpoint |\n| GET | /api/instances/{id}/target-lists | List provider target lists |\n| POST | /api/instances/test | Test endpoint connection |\n\n### Jobs\n\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /api/jobs | List jobs |\n| POST | /api/jobs | Create job |\n| GET | /api/jobs/{id} | Get job |\n| PUT | /api/jobs/{id} | Update job |\n| DELETE | /api/jobs/{id} | Delete job and history |\n| GET | /api/jobs/{id}/target-list | Get primary or selected target list state |\n| POST | /api/jobs/{id}/run | Trigger immediate run |\n| GET | /api/jobs/{id}/logs | Get job run history |\n\n### DNS And Health\n\n| Method | Path | Description |\n|--------|------|-------------|\n| POST | /api/resolve | Preview DNS resolution |\n| GET | /api/health | Health check |\n| GET | /api/dns-servers | List DNS servers |\n| POST | /api/dns-servers | Create DNS server |\n| GET | /api/dns-servers/{id} | Get DNS server |\n| PUT | /api/dns-servers/{id} | Update DNS server |\n| DELETE | /api/dns-servers/{id} | Delete DNS server |\n\n## Cron Schedule Examples\n\n| Expression | Meaning |\n|------------|---------|\n| */30 * * * * | Every 30 minutes |\n| 0 */6 * * * | Every 6 hours |\n| 0 0 * * * | Daily at midnight |\n| 0 0 * * 1 | Every Monday |\n\n## References\n\n- Maintainer guide: [docs/development.md](docs/development.md)\n- Migration notes: [docs/generic-migration-plan.md](docs/generic-migration-plan.md)\n- UniFi schema reference: [docs/reference/unifi-network-10.1.85.json](docs/reference/unifi-network-10.1.85.json)\n\n## OIDC Roadmap\n\nThe auth layer includes provider abstractions for both password and OIDC flows.\n\n- Current provider: local password (`local`)\n- Planned: OIDC providers can be registered without replacing the existing session model\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmstrhakr%2Fnetwork-list-sync","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmstrhakr%2Fnetwork-list-sync","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmstrhakr%2Fnetwork-list-sync/lists"}