Hey folks. I work in infrastructure and infosec, and today I want to share the story behind an internal project we recently open-sourced: nkt (NetKnownsThat).
TL;DR: It’s an all-in-one control plane for Linux hosts. It parses nginx/haproxy configs, manages certs, controls firewalls, handles Docker/Podman/LXD/K8s, and gives you a web terminal and centralized vulnerability scanning.
But the tech stack isn't the interesting part. The evolution is.
Originally, nkt was a monstrous Python project. We eventually rewrote it entirely in Go. And for once, the "never rewrite from scratch" rule didn't apply. Rewriting was the only way to survive and build something we weren't embarrassed to run in production.
The Python Era: Dependency Hell and 200MB Binaries
nkt started as a few audit scripts. Over time, it morphed into a massive Swiss Army knife. But deploying Python to dozens of heterogeneous VPS instances (from beefy bare-metal to low-end ARM routers) is a nightmare.
Dependency Hell: Every server needed a venv. System Python varied between Ubuntu versions, pip occasionally nuked system packages, and the cryptography lib demanded Rust compilers on machines that didn't have them.
Deployment: Try packing a complex Python project into a single static binary for ARM. PyInstaller spat out 200MB binaries that crashed with obscure glibc errors. Dragging an interpreter and all dependencies to every host was madness.
Performance: Parsing hundreds of configs and analyzing iptables trees via psutil ate RAM and crawled.
After debugging yet another expired cert incident on prod, I snapped: "Enough. We're rewriting this in Go." We kept the React/Ant Design frontend but moved the backend and TUI to Go.
The Go Rewrite: One Binary to Rule Them All
Moving to Go gave us the holy grail: go build and a single static binary (~30MB) that runs anywhere. We just shoved the frontend inside using go:embed. No Python, no Node, no separate files on the host.
Here is what nkt actually does now, and why we built it this way.
1. Deep Audits and "Findings"
Most tools just list open ports. nkt parses your actual configs (nginx, haproxy, caddy, docker-compose, ufw, firewalld) and cross-checks them against the live host state (ss output, live containers, real TLS sockets).
If your nginx config says port 80 is open, but the firewall blocks it, or the container isn't running, it flags it as a Finding. It tells you the exact file, line number, and how to fix it.
2. Configs That Won't Brick Your Prod
Editing configs via a web UI is terrifying. What if you miss a semicolon and drop the network?
We implemented Optimistic Rollbacks. When you save an nginx or haproxy config, the backend runs nginx -t or haproxy -c before applying. If it fails, the file automatically rolls back to the previous version. You literally cannot break prod with a typo. Plus, it checks if you're about to lock yourself out of SSH.
3. Resource Topology
Instead of staring at raw data, we built a resource map. It visualizes the chain: External Network → Service → Listener → Pool → Backend → Container/VM. If a backend goes down, you see exactly where the chain broke.
The Hub: Managing 50+ Servers
When you have 2 servers, SSH is fine. When you have 50, you need a Hub (nkt hub).
The Hub is a central VPS that connects to your fleet over SSH. When you add a new host, the Hub checks the architecture (uname), cross-compiles the nkt binary on the fly (GOOS=linux GOARCH=arm64), uploads it via SFTP, and sets up a systemd unit.
Centralized Security & Fail2ban
Managing fail2ban across 50 nodes manually is a joke. With the Hub, if an IP attacks one server, you can ban it across your entire fleet from the Hub dashboard in one click.
The Hub automatically injects its own IP into the ignoreip list of all nodes so it never accidentally locks itself out.
We also added heuristic malware scanning. We don't just rely on ClamAV. We check for crypto-miners: processes running from /tmp, weird ld.so.preload entries, or cron jobs piping curl to sh.
The Fallback Channel:
Imagine you (or a junior dev) accidentally block port 22 via ufw, or sshd crashes. A normal tool would lose the server forever. The Hub opens a separate reverse TLS tunnel (fallback channel). If SSH is dead, the dashboard, web terminal, and binary updates keep working through this tunnel.
Launching as a Hub
Prebuilt binaries for linux/amd64, linux/arm64 and linux/arm are in Releases together with SHA256SUMS:
# substitute your architecture; V is the latest version
V=$(curl -fsSL https://api.github.com/repos/piqab/nkt/releases/latest | sed -n 's/.*"tag_name": *"\(.*\)".*/\1/p')
curl -fsSLO https://github.com/piqab/nkt/releases/download/$V/nkt-linux-amd64
curl -fsSLO https://github.com/piqab/nkt/releases/download/$V/SHA256SUMS
sha256sum -c SHA256SUMS --ignore-missing
chmod +x nkt-linux-amd64
sudo mv nkt-linux-amd64 /usr/local/bin/nkt
From source you only need make: it decides whether to build in Docker or on the bare host (then, if Go or Node is missing, it offers to install them into ~/.local without sudo):
git clone https://github.com/piqab/nkt.git && cd nkt
make build # dist/nkt
sudo make install # binary, unit and nkt.env (an existing nkt.env is kept)
Running the Hub is incredibly straightforward. You just need Docker:
curl -fsSLO https://raw.githubusercontent.com/piqab/nkt/main/deploy/docker-compose.hub.release.yml
docker compose -f docker-compose.hub.release.yml up -d
docker compose -f docker-compose.hub.release.yml logs hub # grab the initial admin password
Once it's up, you just paste your target servers' SSH credentials (or keys), and the Hub takes over.
GitOps & Deployments (Even Behind NAT) Beta
We needed a way to deploy Compose stacks and K8s manifests straight from Git. You can set up pipelines triggered by Git webhooks, registry tag polling, or manual buttons.
Deploying Docker Compose stacks straight from Git.
The NAT Problem: What if your management Hub is behind a corporate NAT and can't receive GitHub webhooks?
We built nkt-edge. It’s a tiny 8MB binary you put on a public VPS. It catches the webhook and tunnels it back to your Hub over a pinned TLS connection. Your Hub stays completely hidden from the internet, but still gets CI/CD triggers.
Kubernetes on Steroids Beta
Managing K8s via kubectl over SSH tunnels gets old fast. You can provision multi-node clusters across different VPS providers. nkt spins up the VMs via libvirt, installs k3s/kubeadm, and sets up a WireGuard mesh between the nodes.
Need to debug a pod? You can open the pod's application directly in your browser via kubectl port-forward proxied through the Hub. No Ingress or NodePort required.
Try It Without Breaking Anything
I know installing random infra tools from the internet is sketchy. That’s why we built a fixtures mode. It runs a synthetic snapshot of a real production server with intentionally planted problems (open Redis, port conflicts, expired TLS certs, rogue containers).
You can click around the UI, test the config rollbacks, and view the resource map without touching your actual machine.
git clone https://github.com/piqab/nkt.git && cd nkt
make build-dev && NKT_MODE=fixtures ./nkt
# Opens at http://127.0.0.1:8077
If you want to run it on a real host locally, it’s just a curl away:
V=$(curl -fsSL https://api.github.com/repos/piqab/nkt/releases/latest | sed -n 's/.*"tag_name": *"\(.*\)".*/\1/p')
curl -fsSL -o nkt https://github.com/piqab/nkt/releases/download/$V/nkt-linux-amd64 && sudo install -m 0755 nkt /usr/local/bin/nkt
sudo nkt scan # or tui
Wrapping Up
Rewriting from Python to Go took time, but it eliminated dependency hell, gave us instant cross-compilation, and dropped memory usage to basically zero. nkt is now a ~25MB binary that acts as a local agent, a centralized Hub, and a TUI tool.
Check out the repo, drop a star if it looks useful, and feel free to open issues or PRs. We’re actively using it in production and adding features based on what we actually need.
👉 GitHub: github.com/piqab/nkt
📚 Docs: piqab.github.io/nkt
What’s your go-to tool for auditing Linux hosts? Let me know in the comments!








Top comments (0)