Bun
A Conn3x circuit that puts one exact Bun release on all your hosts. Distribution repositories mostly don’t carry Bun, so the usual route is curl | bash, which gives you whatever was newest the day each machine was set up. This circuit takes the official zip from Bun’s GitHub release instead, checks it against the release’s SHA-256, and gives you the same Bun on every distribution: 1.4.4 by default.
module "bun" { source = "github.com/conn3xorg/circuit-bun?ref=v0.1.0"
hosts = { app1 = "203.0.113.10", app2 = "203.0.113.11" } ssh_private_key_file = "~/.ssh/id_ed25519"}Then run conn3x init and conn3x apply. A second conn3x plan says No changes.
For hosts created in the same plan, pass host objects with the host key you generated, so Conn3x checks it without a known_hosts entry:
hosts = { for name, d in digitalocean_droplet.app : name => { address = d.ipv4_address host_key = tls_private_key.host[name].public_key_openssh }}To try it on a throwaway container first, see examples/local.
Changing the release
Section titled “Changing the release”bun_version and checksums move together. Take both zips’ lines from the release’s SHASUMS256.txt, such as https://github.com/oven-sh/bun/releases/download/bun-v1.4.3/SHASUMS256.txt:
bun_version = "1.4.3"checksums = { x64 = "<SHA-256 of bun-linux-x64.zip>" aarch64 = "<SHA-256 of bun-linux-aarch64.zip>"}A zip that doesn’t match its checksum fails the apply, and bun stays on the release it had. To check the checksums themselves, the release signs them in SHASUMS256.txt.asc, with the key F3DCC08A8572C0749B3E18888EAB4D40A7B22B59. The defaults here were checked against that signature.
Each release gets its own directory, so the new one unpacks beside the old, and bun and bunx move over to it. Leave bun upgrade alone on these hosts: it would swap the binary inside that directory without Conn3x noticing.
What it does
Section titled “What it does”On each host, in order:
- Installs
curlandunzip. - Downloads
bun-linux-ARCH.zipto/opt/bun/VERSION, keeping it only if its SHA-256 matches. - Unpacks it to
/opt/bun/VERSION/bun-linux-ARCH. - Links
bunandbunxinto/usr/local/bin.bunxis Bun under a second name, which is how upstream’s installer does it too. - Runs
bun --versionand fails the apply unless it prints the release you asked for.
Before the circuit runs, the conn3x_host data source reads each host’s architecture over SSH, which picks the zip.
Where it won’t run
Section titled “Where it won’t run”- x64 CPUs without SSE4.2. Bun’s docs put the floor at Nehalem. Newer instructions are picked at run time, so there’s only the one x64 build to install. On an older CPU, step 5 is what fails the apply. No such CPU was tried here.
- Alpine, Void and other musl distributions. This circuit installs the glibc builds. Bun publishes separate musl zips, which it doesn’t use.
- Architectures other than x86_64 and aarch64. The plan stops and names the host.
What it doesn’t do
Section titled “What it doesn’t do”- It doesn’t install your project’s dependencies, run your application or manage a service. A systemd unit should name
/usr/local/bin/buninExecStart=. - It doesn’t install global packages.
- It doesn’t uninstall anything. An old release’s directory, and the whole install when you delete the module, stay on the host.
Inputs
Section titled “Inputs”| Name | Type | Default | Description |
|---|---|---|---|
hosts |
any | Required | Hosts to configure, by name. Each value is an address, such as "203.0.113.10", or a host object such as { address = "203.0.113.10", host_key = "ssh-ed25519 AAAA..." }. A host object can also set user, port, private_key_file and jump_hosts. The two forms can be mixed. |
ssh_user |
string | "root" |
User to log in as. |
ssh_port |
number | 22 |
SSH port. |
ssh_private_key_file |
string | null |
Path to a private key. When null, Conn3x uses the SSH agent. |
ssh_known_hosts_file |
string | null |
known_hosts file to check host keys against. When null, ~/.ssh/known_hosts. Not used for a host object with host_key. |
ssh_become |
bool | false |
Run commands as root through sudo. Set it when ssh_user isn’t root. |
bun_version |
string | "1.4.4" |
Bun release to install. Change checksums with it. |
checksums |
map(string) | The zips of 1.4.4 | SHA-256 of the x64 and aarch64 zips, from the release’s SHASUMS256.txt. |
Outputs
Section titled “Outputs”| Name | Description |
|---|---|
bun_home |
Directory of the installed release on each host, by host name, such as { app1 = "/opt/bun/1.4.4/bun-linux-x64" }. |
Requirements
Section titled “Requirements”Requires Conn3x v0.6.10 or later, and hosts with outbound HTTPS to github.com. amd64 and arm64.
Tested on
Section titled “Tested on”Rocky Linux 10, Fedora 45, Ubuntu 24.04 and Debian 13. examples/local was applied to each on arm64, and the second plan had no changes. In a login shell, bun and bunx both reported 1.4.4, bun add --exact semver@7.8.5 pinned that version in package.json, and a TypeScript script importing it ran and gave the right answers. CI runs the same checks on amd64.
On an Ubuntu 24.04 droplet and a Rocky Linux 10 droplet with SELinux enforcing, both s-1vcpu-1gb, amd64: the same checks passed. A wrong checksum failed the apply and left bun on 1.4.4, with an empty /opt/bun/1.4.3 behind it. Moving to 1.4.3 repointed bun and bunx, and moving back was clean. After a reboot the plan had no changes and bun still ran.
ssh_become wasn’t exercised: every test logged in as root.
License
Section titled “License”MPL-2.0. See LICENSE. Bun is under the MIT license, with the bundled components listed in its own license file.
Source
Section titled “Source”- Repository: conn3xorg/circuit-bun. This page covers v0.1.0; the repository’s tags list every release.
- Examples: examples/local.
- Related circuits: Java, PHP-FPM, Jenkins, GitHub Actions runner, GitLab Runner, Cinc Client, Node.js, Perl, Selenium Grid, OpenVox, Rust, Go, Python, Ruby, Kotlin, .NET, C toolchain.