One Linux server.
Many real IP addresses.
Zero config files.

Splitter lets one Linux server host many services — each with its own real IP address — and manage them all from a browser. Point a domain at your backends — static addresses, or Docker containers picked from a live list — and Splitter creates the network interface, balances the traffic as raw TCP/UDP or a full HTTP reverse proxy, routes paths and methods to different pools, issues TLS via Let's Encrypt, rotates and searches the logs, and firewalls it for you. No config files. No SSH. You watch every command it runs.

  • No database
  • Single image
  • One command
splitter · apply
$ splitter apply site4.example.com

→ resolving bind target
  ip link add link eth0.50 name mv-web-0 type macvlan
  ip addr add 192.168.50.20/24 dev mv-web-0
✓ sub-interface up — 52:54:00:fa:bb:04

→ writing /etc/nginx/stream.d/site4.conf
  upstream pool → 192.168.50.10:443, .11:443
  least_conn · tls · acl: office

→ nginx -t
✓ configuration file test is successful
✓ reloaded — listening on 192.168.50.20:443
Backend health
healthy10.0.0.10:8443
healthy10.0.0.11:8443
SFW-IN-eth0
accepttcp/443
dropdefault
2
Proxy modes — Stream & Reverse
Bind IPs per host
5
LB algorithms
6
Snippet kinds, picked per mapping
What is Splitter?

Run many services from one server — each on its own address, all from one screen

Normally, exposing several sites or services from a single server means hand-editing nginx, juggling IP addresses and VLANs over SSH, and praying a typo doesn't take everything offline. Splitter does all of that for you — from one dashboard — and shows you exactly what it changed.

Real addresses, not tricks

Every service gets a genuine IP on a real network interface — one your router and the rest of your network can see. It isn't hidden away inside a container or a namespace.

Point, click, done

Add a domain, choose its backends, and Splitter writes the config, brings the interface up and reloads the proxy — safely, in seconds. No editing files, no restarting anything by hand.

Safe on a live server

Every risky step has a guard rail: the config is tested before each reload, the firewall can't lock you out, and a single click rolls everything back to a known-good state.

How it works

From a domain name to a live proxy in three moves

Splitter runs directly on the host — no network namespaces, no overlay. The interfaces and IPs it creates are real, routable and visible in ip link show.

01

Resolve the bind IP

Bind straight to an interface's existing IP, or give the mapping its own dedicated address on a real macvlan device — unique MAC, optional VLAN tag, static IP.

# its own MAC, inside VLAN 50
ip link add link eth0.50 name mv-web-0 \
   address 52:54:00:fa:bb:04 type macvlan
02

Generate the stream config

An upstream {} pool is rendered for your backends with the load-balancing method you picked, plus TLS, access lists and whatever snippets you selected — rate limit, timeouts, log format. Reverse Proxy adds per-path pools and method routing.

upstream pool_924cb {
    server 192.168.50.10:443;
    server 192.168.50.11:443;
    least_conn;
}
03

Validate & hot-reload

nginx -t runs before every reload, so a bad block is rolled back and the live proxy is never reloaded against a broken config. Each step is streamed back to the UI.

nginx -t   # config OK
nginx -s reload
✓ 192.168.50.20:443 → pool_924cb
Picking Reverse Proxy instead of Stream runs the exact same pipeline, plus one thing: nginx terminates TLS, filters the request through ModSecurity/CRS if the WAF is on, then proxies it at Layer 7 — WebSocket, HTTP/2, custom error pages and per-path location rows that can send /api POSTs to a different pool than GETs. Stream and Reverse Proxy are two clean panels in the dashboard; a field that only applies to one of them simply isn't shown for the other.
Live mapping

Watch every route on your host, in real time

Each domain binds its own address, flows through the proxy host, and fans out to its backend pool. Downed backends light up red the moment a health probe fails.

Live healthy degraded backend down 6 mappings · 8 backends
example1.com 192.168.11.82:449 TCP ↳ ens33 · direct example2.com 192.168.11.83:53 UDP ↳ mv-sub-0 · static example3.com 192.168.11.83:443 TCP ↳ mv-sub-0 · static example4.com 192.168.11.87:443 TCP ↳ mv-sub-2 · static example5.com 192.168.11.84:443 TCP ↳ mv-sub-1 · static example6.com 192.168.11.88:443 TCP ↳ mv-sub-6 · static splitter proxy host example1.com 2 backends · round-robin ! example2.com 2 backends · round-robin example3.com 1 backend · round-robin example4.com 1 backend · round-robin example5.com 1 backend · round-robin example6.com 1 backend · round-robin
Release 0.2.0

What's new in 0.2.0

Splitter grows from a Stream / Reverse Proxy manager into a full control plane for nginx. Everything below ships in the current image — docker compose up -d --build is the whole upgrade.

New

Snippets

Rate limits, timeouts, log formats (incl. JSON), error pages, raw config blocks and log-rotation policies as named, reusable items. One picker on the mapping form, another on every custom location. Edit a snippet and every mapping using it is re-applied under nginx -t protection.

New

Path & method routing

Give /api its own backend pool, send POST/PUT to a write node and DELETE to a third while GET stays on the main pool — several rows per path, or split the whole site by method with a / row. Rendered as dedicated upstreams and a map $request_method.

New

Logs with history

Per-mapping logs rotated daily by logrotate — dated, gzip, retention per mapping — and a time-range search that reads the live file and every archive. "What hit this mapping two days ago at 15:40?" is one query.

New

nginx metrics & port scanner

Live stub_status counters — active, reading, writing, waiting, requests per second — on Monitoring and the live map, from a loopback-only endpoint Splitter provisions itself. Plus an nmap port scanner on the Tools page and a read-only viewer role.

Capabilities

Everything the edge of your network needs

Built with Python + Flask and a single-page dashboard. Mappings, users and settings persist to plain JSON — there is nothing else to run.

Docker & Swarm-backed backends

Pick a running container — or, on a Swarm manager, a service — straight from a live list instead of typing an IP. A background reconciler and a real-time events watcher keep the pool in step the instant a container starts, stops or is recreated. Traefik-style, nginx stays the data plane.

Reverse Proxy (L7)

A dedicated HTTP mode alongside Stream: WebSocket upgrade, HTTP/2, per-path location rows with their own pools and method routing, custom error pages served by nginx, raw config passthrough — and ModSecurity/CRS filtering in one click.

Load balancing & failover

Round-robin, least_conn, hash (+consistent), random, or random-two — with weights, health probes and active-passive priority failover, for Stream and Reverse Proxy alike.

Real macvlan sub-interfaces

Dedicated IP per mapping with its own MAC — optionally inside an 802.1Q VLAN. Not a namespace trick: the device shows up in ip link and answers ARP.

Per-interface firewall

Security-group style iptables rules — every interface gets its own ordered rule set and default policy. Off by default, with lockout protection and a one-click panic switch.

Automated SSL & Let's Encrypt

Upload a cert, generate a SAN self-signed pair, or request one from Let's Encrypt (HTTP-01 via certbot) with background auto-renewal. Keys land at 0600, shared certs are refcounted.

Access lists

Named IP/CIDR allow lists rendered to nginx snippets. Auto-refreshing from a source URL — the built-in tas-ix feed replaces a cron job entirely.

ModSecurity WAF

Install the OWASP Core Rule Set from the dashboard — every Reverse Proxy mapping binds to it automatically. Switch Off → Detection → Enforce once you've tuned the false positives.

Forward proxy

Standalone outbound HTTP forward proxies, each bound to its own IP:port with an allow-all or domain-pattern allowlist — a separate resource from reverse-proxy mappings.

Monitoring, live map & tools

Host CPU/RAM/disk, per-interface throughput, nginx stub_status counters, backend health, an n8n-style canvas of every route — and a Tools page: ping, port test, nmap scanner, DNS, traceroute, tcpdump, WHOIS, SSL check.

Snapshots & rollback

One-click backup of everything — mappings, users, certs, sub-interfaces, snippets, audit log — on a schedule, in-process. Restore or roll back to any point.

Roles & audit log

Admin, creator and read-only viewer roles behind a login, PBKDF2-hashed passwords, a persistent audit trail of every privileged action — and an ⓘ tooltip on every option of the mapping form.

Safe by construction

Powerful enough to break things — designed not to

Splitter runs privileged commands on a production host. Every destructive path has a guard rail, and every one of them is on by default.

  • No shell injection. Every command runs as an argv list — never a shell string — through a single audited choke point.
  • Firewall can't lock you out. Every managed chain accepts established connections and the dashboard's own port first — and Panic tears it all down.
  • Fail-safe reloads. nginx -t gates every reload, so the live proxy never restarts against a broken config.
  • Simulation mode. Run the whole tool off-host: it prints the exact commands it would execute and touches nothing.
  • Least privilege, optionally. Runs as root by default, or as an unprivileged user with a scoped sudoers file granting only what it needs.
SFW-IN-eth0 · rendered
# established + the dashboard, always first
iptables -A SFW-IN-eth0 -m conntrack \
    --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A SFW-IN-eth0 -p tcp --dport 8088 -j ACCEPT

# your rules, by priority
iptables -A SFW-IN-eth0 -p tcp --dport 22 \
    -s 203.0.113.0/24 -j ACCEPT
iptables -A SFW-IN-eth0 -p tcp --dport 443 -j ACCEPT

# fallback = interface default policy
iptables -A SFW-IN-eth0 -j DROP
iptables -I INPUT 1 -i eth0 -j SFW-IN-eth0
Get started

One command. One host. Done.

Ships as a single self-contained image — nginx, the WAF, certbot for Let's Encrypt, logrotate, the diagnostic tools and the app. It runs in the host network namespace, so the IPs it creates are real, and auto-detects your uplink NIC.

$ git clone https://github.com/splitter-uz/splitter.git && cd splitter
$ docker compose up -d --build

Then open http://<server-ip>:8088 and create your admin account. Runs on any Linux host with Docker — named volumes keep your data, and docker compose up -d --build is safe to re-run.

Ready to give your backends real addresses?

Self-hosted and ready to deploy in minutes.

Launch the dashboard