From Japanese 降ろす (órosu) — "to unload" or "offload."
The Problem
CI systems are good at building software and bad at delivering it. Getting a build artifact from a pipeline onto a production machine usually means one of a few well-worn but fragile patterns:
- SSH private keys copied into CI secrets and spread across every pipeline and repository that needs to deploy
- SFTP/rsync scripts copy-pasted from one project to the next, each with its own slightly different bugs
- Hardcoded paths and permissions that break the moment a server's layout changes
- Production machines directly reachable from CI runners, widening the attack surface every pipeline adds to
- Secret sprawl that turns rotating a single compromised key into an audit of every repository that might reference it
None of this is specific to any one CI/CD platform — it's the default shape of "run a script on a remote machine from a pipeline," and it accumulates risk with every project that adopts it.
How Orosu Solves It
Orosu installs once on the target machine as orosu-server and turns deployment into a bounded, authenticated request instead of an open SSH session:
- CI builds the application — a binary, a container image, static assets, whatever the pipeline produces
- CI triggers a job over a WebSocket connection, optionally attaching files
orosu-serverauthenticates the request using Ed25519 signatures — no passwords, no shared secrets in transitorosu-serverruns a predefined script — one of a fixed set configured on the server, never arbitrary CI-supplied commands- The script deploys, using whatever files and arguments the job attached
No direct SSH, no per-pipeline credential juggling, and no server-side surface beyond the specific scripts an operator has explicitly configured.
Installation
orosu-server and its companion orosu-keygen CLI ship as Debian/Ubuntu packages from an apt repository:
curl -fsSL https://packages.nerdy.pro/NerdyPro.gpg | sudo gpg --dearmor -o /usr/share/keyrings/nerdy-pro.gpg
echo "deb [signed-by=/usr/share/keyrings/nerdy-pro.gpg] https://packages.nerdy.pro/ stable main" | sudo tee /etc/apt/sources.list.d/nerdy-pro.list
sudo apt update
sudo apt install orosu
GitHub Releases also publish prebuilt orosu-server and orosu-keygen binaries directly, for machines that can't add an apt source.
Getting Started
Generate a client key pair with orosu-keygen, from /etc/orosu:
orosu-keygen --name my-ci-client --private-key-output my-ci-client.key --public-key-output my-ci-client.pub
The public key goes into the server config; the private key becomes a CI secret.
Configure the server in /etc/orosu/orosu-server.toml — a listen address and the client's public key:
listen:
tcp: "127.0.0.1:8081"
clients:
- name: my-ci-client
secret_file: /etc/orosu/my-ci-client.pub
A server bound to localhost is typically fronted by a reverse proxy that terminates TLS and forwards WebSocket upgrades — the README documents an nginx configuration for this.
Define a script the client is allowed to trigger:
#!/bin/bash
echo "Hello, $1!"
clients:
- name: my-ci-client
secret_file: /etc/orosu/my-ci-client.pub
scripts:
- name: test-script
command:
- "bash"
- "/etc/orosu/scripts/test.sh"
Trigger it from CI with the companion GitHub Action, passing the server address and the client's private key as secrets:
- name: Remotely execute a script
uses: orosu-ci/orosu@v0
with:
address: ${{ secrets.OROSU_SERVER_URL }}
script: test-script
key: ${{ secrets.OROSU_CLIENT_KEY }}
arguments: "from CI pipeline"
End-to-End Encryption
WSS/:termTLS covers the connection, but when TLS is terminated at a reverse proxy in front of orosu-server — the standard setup above — script arguments, uploaded files, and streamed output are plaintext at that proxy. An optional end-to-end encryption handshake (X25519 + HKDF-SHA256 + ChaCha20-Poly1305) closes that gap:
orosu-keygen --kind server --private-key-output server.key --public-key-output server.pub
The server's public key is added to its config and handed to CI as the Action's server_key input. The upgrade is opt-in and additive on both ends independently — a server with encryption configured still serves clients that omit server_key exactly as before, and no coordinated rollout is required.
Security
Security is a first-class design constraint, not an afterthought:
- Cryptographic authentication — every job is signed with the client's Ed25519 key; there's no password or shared secret on the wire for an attacker to intercept.
- A closed set of actions — CI can only trigger scripts an operator has explicitly predefined on the server. There's no path from a CI job to an arbitrary shell command.
- Hardened attachment handling — zip entry names are validated against path traversal, and entry count and decompressed size are both capped, so a crafted or oversized attachment can't escape its extraction directory or exhaust disk.
- Defense-in-depth encryption — the optional end-to-end handshake checks for low-order-point attacks on its X25519 exchange, on top of the confidentiality it already provides.
- Secure-by-default file permissions —
orosu-keygenwrites private key files with0600permissions regardless of the umask in effect.
These protections landed in the 0.7.0 release as a drop-in upgrade — no config, CLI, or protocol changes required. See CHANGELOG.md for the full release history.
License
Orosu is licensed under Apache-2.0.