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 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:

  1. CI builds the application — a binary, a container image, static assets, whatever the pipeline produces
  2. CI triggers a job over a connection, optionally attaching files
  3. orosu-server authenticates the request using Ed25519 signatures — no passwords, no shared secrets in transit
  4. orosu-server runs a predefined script — one of a fixed set configured on the server, never arbitrary CI-supplied commands
  5. 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 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 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 permissionsorosu-keygen writes private key files with 0600 permissions 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.

Ad-hoc SSH/SCP deployment steps in CI pipelines — private keys in secrets, copy-pasted rsync scripts, and directly reachable production servers. CI triggers an authenticated WebSocket job instead of opening an SSH session.
Each CI client has an Ed25519 key pair. The public key is registered in the server's config; the private key is stored as a CI secret and used to sign job requests. The server only runs scripts it has explicitly configured for that client.
No. orosu-server only executes predefined scripts configured in orosu-server.toml ahead of time. A CI job selects a script by name and passes arguments and attachments — it cannot supply arbitrary commands.
WSS/TLS covers the connection by default, typically terminated at a reverse proxy in front of orosu-server. An optional end-to-end encryption layer (X25519 + ChaCha20-Poly1305) can be enabled so script arguments, files, and output stay confidential even from that proxy.
Via an apt repository (packages.nerdy.pro) for Debian/Ubuntu, or as prebuilt binaries attached to GitHub Releases for orosu-server and the orosu-keygen CLI.
Ed25519-signed requests, a closed set of server-defined scripts CI can trigger, path-traversal and size limits on attachment extraction, low-order-point protection on the optional end-to-end encryption handshake, and secure-by-default file permissions for generated keys.