Open source · Built on OpenTofu
Provision it. Configure it.
One plan.
Today that's Terraform, Ansible, and a drawer of glue scripts holding them together. Conn3x does both jobs: one binary, one plan, one state, for your cloud and every server it creates.
brew install conn3xorg/tap/conn3x- DigitalOcean
- AWS
- Hetzner Cloud
- Google Cloud
- Azure
- Akamai (Linode)
- Vultr
- Scaleway
- Oracle Cloud
- Proxmox VE
- Rocky Linux
- RHEL
- AlmaLinux
- Fedora
- Debian
- Ubuntu
01 One plan
One plan for the cloud and the servers in it. Point a circuit at a resource and the plan shows the server about to be created next to every package, file and service headed for it.
Reads before it writes
Every step reads the server first, so the plan shows the exact change, not a guess.
Waits for SSH
A new server's steps wait until it answers. No sleep 60.
One state
The droplet and everything on it live in the same state file.
02 Drift
Hear about the 3 a.m. fix at breakfast. conn3x drift checks the cloud and the servers, and fails the job when either has moved.
- conn3x applyServers match the code.
- A hand edit on web1worker_connections, 1024 to 4096.
- Nightly conn3x driftFinds it, exits 2, the job fails.
- conn3x applyPut back. Or keep it, in code.
user nginx; worker_processes auto; events { worker_connections 10244096; }
$ conn3x drift Drift found in 1 resource. Hosts ~ conn3x_file.web__nginx_conf["web1"] changed $ conn3x apply conn3x_file.web__nginx_conf["web1"]: Modifying... conn3x_file.web__nginx_conf["web1"]: Modifications complete after 1s
03 Bring your playbooks
Your playbooks come with you. The converter rewrites each task it can prove, and marks the rest with the reason. Nothing gets guessed.
- name: Install nginx
ansible.builtin.dnf:
name: nginx
state: present- name: Start nginx
ansible.builtin.service:
name: nginx
state: started
enabled: true- name: Install tools
ansible.builtin.package:
name: "{{ item }}"
loop: [git, jq]- name: Open the status port
ansible.posix.firewalld:
port: "{{ status_port }}/tcp"
state: enabled
when: ansible_os_family == "RedHat"step "install_nginx" {
package {
name = "nginx"
}
}step "start_nginx" {
service {
name = "nginx"
state = "started"
enabled = true
}
}step "install_tools" {
for_each = ["git", "jq"]
package {
name = item.value
}
}# TODO(convert): Task "Open the status port"
# uses when, which the converter can't
# translate yet.
# - name: Open the status port
# when: ansible_os_family == "RedHat"Servers still need packages, files and services. What's changing is that one plan can see all of it.
How it fits together
Your configuration and your circuits are one HCL project. Conn3x plans the cloud through OpenTofu's providers and the servers over SSH, and records both in one state file.
How a step runs
1 · Read
What's on web1 now?
/etc/nginx/nginx.conf
worker_connections 4096;2 · Diff
What would change, shown in the plan.
~ conn3x_file.web__nginx_conf["web1"] - worker_connections 4096; + worker_connections 1024;
3 · Apply
Only after you approve the plan.
Modifications complete after 1s notify → handler.reload_nginx
Every step reads the server first, so the plan shows the exact change, not a guess. Nothing on the server changes until you apply, and a step that already matches does nothing.
Built on OpenTofu
Conn3x adds
- Circuits
- 29 host modules
- SSH with host-key checks
- conn3x drift
- conn3x convert ansible
OpenTofu v1.13
- Plan and apply
- State and backends
- Providers
- Modules
- HCL
Conn3x starts from OpenTofu and tracks its releases, so your providers, modules and state come with you. Files from OpenTofu keep their original licence headers.
04 Everyday work
Everything a server needs. Linux first: every change is tested on Rocky Linux 10, Fedora 45, Ubuntu 24.04 and Debian 13.
Keep your providers
Built on OpenTofu, so every Terraform and OpenTofu provider works as it is, and so do your modules and state.
Install nothing on your servers
No Python, no agent. Conn3x connects over SSH, checks the host key every time, and runs plain shell commands.
Repeat a step for every item
for_eachruns a step once per package, user or file. Drop an item and the next plan stops managing just that one.Keep secrets out of state
Write a password with
content_woand it reaches the server, not the plan or the state. State keeps an HMAC.Reach hosts behind a bastion
Chain jump hosts, or point at your SSH config and use its aliases. Each host can log in its own way.
Twenty-nine modules
Packages, files, templates, services, users, cron, sysctl, mounts, firewalld, ufw, SELinux and more.
05 Circuits
Don't write the nginx setup again. Borrow a circuit with one module block, or share your own on the directory.
- v0.1.0auto-updatesTurns on automatic package updates with unattended-upgrades or dnf-automatic, with security-only updates and a reboot window.
conn3xorg/circuit-auto-updates - v0.1.0baselineA sensible start for any server: time zone, chrony, sysctl settings and SSH that only takes keys.
conn3xorg/circuit-baseline - v0.1.0caddyRuns Caddy as a web server or reverse proxy, with the Caddyfile built from a map of sites and checked before it goes live.
conn3xorg/circuit-caddy - v0.1.0dockerInstalls Docker Engine from Docker's repository and runs your Compose stacks from files in your configuration.
conn3xorg/circuit-docker - v0.1.0fail2banBans addresses that keep failing SSH logins, through nftables, with room for jails of your own.
conn3xorg/circuit-fail2ban - v0.1.0firewallA default-deny ufw or firewalld firewall, picked per host, that opens SSH before it turns on.
conn3xorg/circuit-firewall - v0.1.1k3sA k3s Kubernetes cluster from servers and agents, with embedded etcd for HA and Raspberry Pi OS support.
conn3xorg/circuit-k3s - v0.1.0kubeadmAn upstream Kubernetes cluster with kubeadm: containerd, pkgs.k8s.io, HA control planes and a pod network.
conn3xorg/circuit-kubeadm - v0.1.0monitoringPrometheus, Grafana and cAdvisor as one Compose stack, scraping the targets you give it.
conn3xorg/circuit-monitoring - v0.1.0nginxInstalls nginx, writes your site, keeps the service running and opens port 80 in firewalld or ufw.
conn3xorg/circuit-nginx - v0.1.0node-exporterRuns Prometheus node_exporter at a pinned, checksummed version as its own system user.
conn3xorg/circuit-node-exporter - v0.1.0podmanInstalls Podman and runs your containers as systemd services through Quadlet, with secrets kept in a root-only file.
conn3xorg/circuit-podman - v0.1.0postgresInstalls PostgreSQL with your settings, access rules, users and databases, and keeps passwords out of state.
conn3xorg/circuit-postgres - v0.1.0tailscaleInstalls Tailscale from Tailscale's repository and joins your hosts to your tailnet, with subnet routes, exit nodes and Tailscale SSH.
conn3xorg/circuit-tailscale - v0.1.0usersCreates users, groups and their SSH keys from one map, with optional passwordless sudo.
conn3xorg/circuit-users
06 Compare
Two tools, or one. The same job, with one less handoff.
| Aspect | Terraform or OpenTofu, plus Ansible | Conn3x |
|---|---|---|
| To install | Two tools, and Python on the controller and every host | One binary |
| State | Terraform state for the cloud, none for the hosts | One state for both |
| Seeing host changes | A separate --check --diff run | In the same plan as the cloud |
| Cloud addresses in host config | Inventory scripts or plugins | An expression |
| Finding drift on hosts | Run the playbook in check mode | conn3x drift, both layers |
07 Open source
Built with the people who use it. Every fix from outside the project ships with the name of whoever wrote it, right there in the release notes.
MPL-2.0, no CLA, and no feature held back for sponsors. Meet the people building it, or start with the contributing guide.
From the blog.
All posts
Conn3x v0.6.5: circuits that share a host get alongPackage steps from two circuits now wait for each other's locks, ufw rules applied together all stick, and sysctl and file steps work on minimal images. Six fixes, three of them from contributors.
The first five contributorsWithin hours of the first release, people started opening pull requests against Conn3x. Here's who they were, what they fixed, and what you can expect if you're next.
GitHub Universe, and the place Conn3x livesGitHub Universe runs today and tomorrow in San Francisco. A note on why Conn3x is built entirely in the open on GitHub, and an open door for whoever wants to build it with us.
Fifteen minutes to your
first circuit.
All you need is one Linux server you can reach over SSH. No server handy? Try it on a throwaway container, in about five.