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.
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.
$ 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
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.
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.
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.
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.
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.
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
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; }
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
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.
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.
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.
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.
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.
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.
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.
Built with Python + Flask and a single-page dashboard. Mappings, users and settings persist to plain JSON — there is nothing else to run.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Splitter runs privileged commands on a production host. Every destructive path has a guard rail, and every one of them is on by default.
nginx -t gates every reload, so the live
proxy never restarts against a broken config.# 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
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.
Self-hosted and ready to deploy in minutes.