Project · Infrastructure as Code
Conn3x: One Plan for the Server and Everything You Put On It
Building a server and setting it up are one job, so why does it take Terraform, Ansible and a pile of glue to do it? Conn3x is one Go binary, built on OpenTofu, that plans the machine and its configuration together and keeps them in one state.
Overview
Ask anyone who runs servers how a new one gets built. Terraform or OpenTofu creates the machine. Ansible sets it up. And in between sits a layer nobody planned: a local-exec that waits for SSH, an inventory script that copies IP addresses from one tool’s state into the other’s, a sleep 60 that nobody dares remove.
That’s two tools, two states and two previews for what is really one job. Conn3x does the whole job from one binary, with one plan and one state. It’s written in Go and built on OpenTofu, so the providers, modules and state you already have keep working unchanged. Why I started it is a post of its own.
The problem
The handoff is where it hurts. The cloud says the server exists, but it’s still booting, so the configuration run races it. You scale a pool down and the inventory still lists the box you deleted. You want to see what a change will do, and you get two previews from two tools that have never heard of each other.
And when someone edits a file by hand on host 14? Terraform has no idea. Ansible only finds out if you remember to run it in check mode.
What I built
Conn3x adds one block to HCL: the circuit. A circuit is a playbook that lives beside the rest of your infrastructure. It has hosts, an ssh block, a list of steps and some handlers. Each step is one module (a package, a template, a service) and each one reads the server, shows you a diff, then applies it. Change the nginx config and a handler reloads nginx, the way you’d expect.
What makes it worth building is where hosts can point. Point it at a resource, and conn3x plan shows the droplet about to be created right next to the exact package, file and service changes headed for it. The IP address gets from the cloud into the host config through an expression, not an inventory plugin. The repo’s DigitalOcean example goes one further: it generates each server’s SSH host key in the same config, so the very first connection is verified too.
The modules cover the everyday work: files and templates, packages and repositories, services, users and SSH keys, cron jobs and timers, sysctl, mounts, hostname and time zone, firewalld and ufw, SELinux, downloads, archives, git checkouts, reboots, host facts and locale. Secrets you mark write-only stay out of the plan and the state.
Nothing gets installed on your servers. No agent, no Python. Conn3x connects over SSH, checks the host key every time, and runs plain shell commands as root or through sudo. Jump hosts and your ~/.ssh/config work as they do anywhere else.
Drift, and the playbooks you already have
conn3x drift checks both layers, the cloud and the hosts, and exits with code 2 when it finds a difference. Put it on a schedule and you get an alert the morning after someone hand-edits a file, not three months later.
Nobody starts from nothing, so conn3x convert ansible -i inventory site.yml turns an existing playbook into circuits. Anything it can’t translate it marks TODO(convert) and leaves for you, instead of guessing.
Where it is now
It’s early, and I’d rather say so. The repo is only days old, and v0.5.0 is already out. Conn3x configures Rocky Linux, RHEL, AlmaLinux, Fedora, Debian and Ubuntu today. Network devices come next, then Windows; neither is there yet.
Every change runs end-to-end tests against Rocky Linux 10, Ubuntu 24.04, Debian 13 and Fedora 45 hosts in Podman, and a scheduled job builds a real Rocky Linux 10 droplet on DigitalOcean and configures it in one plan. Releases are signed with cosign and ship with SBOMs and build provenance, for Linux and macOS on amd64 and arm64.
It’s licensed MPL-2.0, the same as OpenTofu, which it builds on. Contributions need a DCO sign-off and there’s no CLA, and there never will be. Longer term, I want it to go where OpenTofu went. Once Conn3x has maintainers from more than one organization, the plan is to hand the project, its trademark and its domains to a neutral foundation, with a CNCF Sandbox application as the route. That’s a goal, not something that’s happened: nothing has been applied for.
Try it
On macOS:
brew install conn3xorg/tap/conn3x
On Linux, grab the tarball for your architecture from the releases page. Then write a circuit and run:
conn3x init && conn3x plan && conn3x apply
No server handy? The try-it-locally example configures a throwaway Rocky Linux 10 container in about five minutes. Get started on the docs site takes about fifteen. Ideas and feedback are most useful right now, in Discussions, and the code is all on GitHub. There’s more at conn3x.org.
// Let's talk
You have ideas.
I have IT solutions.
Fifteen minutes on Zoom is usually enough to tell whether I'm the right person for what you're building.
Denver, CO · Available for architecture, infrastructure, and DevOps engagements