ilbertt/nibrun/deploy-to-nibrun
Claude Code and agent skill by ilbertt/nibrun
- community
Checking that the SKILL.md file is still in the repository.
Deploy a compiled binary to nibrun and run it as an HTTPS service. Use when asked to deploy, ship, host or run a self-contained server binary (Bun, Go, Rust, Zig, C) or a folder of static assets on nibrun, when working in a repo that targets nibrun, or when deciding whether nibrun fits an app.
Install
npx vskill@latest install ilbertt/nibrun/deploy-to-nibrunSKILL.md
Deploy to nibrun
nibrun takes one compiled binary and gives it a microVM of its own, a persistent filesystem, and an HTTPS URL. No Dockerfile, no YAML, no cluster.
Build for Linux x86_64, deploy through nibrun's MCP server or CLI, then ask the URL for something. What that path does not need is below it: copying an app, the guest contract, naming a runtime value, a second public port, cron jobs, and what nibrun does not do.
For CI deployments, start at GitHub Actions.
1. Sign in
If using a connected nibrun MCP server, use its authenticated account and skip CLI sign-in. Otherwise, check the CLI:
Both halves in one command: command not found means the CLI is not installed, Not signed in. means it is not signed in.
nib login waits on a human approving it in a browser, so an agent that finds itself signed out asks the user to run it rather than trying to drive it.
2. Build the binary
One self-contained linux-x86_64 file — static, or dynamically linked against glibc, which the rootfs carries. It has to be built for that target: a binary compiled on a Mac, or for arm64, is the most common reason a first deploy never boots.
If the repo already builds one, run its build. A project that ships a binary usually wraps more than a compiler invocation — assets embedded, constants substituted at build time, a frontend compiled first — and a hand-rolled command silently skips all of it, producing something that links and then dies on boot. bun-full-stack-starter is one such: bun run build gives backend/dist/app with the frontend and the migrations inside it, defaulting to PORT 3000 and ./data.
A Bun repo with nothing to inherit compiles one itself with bun build --compile, targeting bun-linux-x64. Embedding an asset directory, bytecode, build-time constants — all flags on that same command, and worth reading Bun's single-file executable docs for rather than recalling: a flag invented from memory is how a binary ends up missing the files it expects to carry.
Three things to read off the binary before deploying rather than after:
- The port it listens on, and that it binds
0.0.0.0rather than127.0.0.1. The guest hands
the number back as NIBRUN_HTTP_PORT and PORT, so an app that reads either needs no configuration here.
- Where it writes. Only
/app/datasurvives a redeploy, and an app that keeps its SQLite file
and its uploads under ./data is already there.
- What it needs from the environment, off a
.env.exampleor whatever it loads config from. It
has to be there on the first deploy: a process that exits over a missing variable never starts serving, and the deploy fails with it.
A folder of static assets has no binary to build: nib is one, and nib serve answers for whatever folder it is given, on the port the guest hands it. So the folder goes up as the app's data/, and the CLI's own Linux build as the binary that serves it:
A path naming a directory answers with its index.html, and a miss with the folder's own 404.html where it has one; serve /app/data --single-page answers every miss with the root index.html instead, for a SPA whose routes exist only in the browser. No --port: nib serve binds whichever port the guest assigns. The assets ride in as data, which goes up only as the app is created — a rebuilt site is a new app, at a new URL, and a custom domain (nib apps domains) is what keeps an address across that.
3. Deploy
With MCP
Choose the app: supply a name and optional initial config to create one, or an appId to redeploy an existing app. Initial configuration includes the environment, arguments and HTTP port needed on first boot. Existing apps reuse their saved configuration. Reuse the returned app.id as appId for subsequent deployments; a name creates a new app.
Include chatId in deploy_app when your current chat ID is available; omit it rather than guessing. Without it, nibrun records the client's _meta["openai/session"] when available. This metadata is an anonymized conversation ID and cannot be assumed to resolve to a chat URL.
Choose one binary source:
- Native file binding: attach the compiled executable to
deploy_app'sbinaryinput using
the client's file binding.
- HTTPS download: pass
urltodeploy_appwhen the binary is already reachable over HTTPS
from nibrun. Signed download URLs work. For binary or url, an optional sha256 verifies the downloaded bytes.
- Direct upload: if native file binding is unavailable, use
prepare_deployas described
below. This requires an agent that can read the compiled file and upload bytes over HTTP.
For a direct upload:
- Call
prepare_deploywith the app target, the binary'sfilenameand its actualsizeBytes.
It returns app and upload, creating the app if needed. It does not deploy anything.
- PUT the raw binary as the whole request body to
upload.url, withContent-Lengthequal to
sizeBytes. The signed URL authorizes this request; send no nibrun authorization token. Wait for a successful 2xx response.
- Call
deploy_appwithappId: app.idandartifactId: upload.artifactId. nibrun finalizes and
validates the uploaded binary, then queues the deployment.
Each deploy_app call creates a deployment and replaces the current release. The result contains app, deployment and the public url; a pending deployment is only queued. Use get_app to check the returned deployment and request the public URL before reporting success.
With the CLI
The first deploy creates the app:
--port is the HTTP port the binary listens on inside the guest — read it off the app rather than carrying a number over from an example. It is the number the guest hands back as NIBRUN_HTTP_PORT and PORT, and it defaults to 3000.
An app can be created with its data/ already holding something — a seeded SQLite file, a corpus, fixtures a first run would otherwise have to write:
--data-folder accepts a local folder, a .tar.gz or .zip file, or an HTTPS URL to either archive format. nibrun fetches remote archives directly, so there is no need to download them locally first. The URL must name the archive in its path and be reachable from nibrun; signed query strings work, so quote URLs that contain them:
For every source, the root of the archive becomes the root of `data/`: a folder is packed from the inside, so ./seed/app.db arrives as /app/data/app.db, and bundling the folder rather than its contents puts every file one directory deeper than the app looks. Up to 1 GiB uploaded or fetched and 2 GiB unpacked, and only as the app is created: this and the app writing its own files are the whole of how anything gets onto the volume. A zip made anywhere but unix carries no permissions, so an executable bit does not survive one.
Try seeding first-run setup before going public
Some apps let the first visitor claim the admin account. Their public URL is reachable as soon as they boot, so check whether that setup can be seeded before deploying. This depends on what the app supports and what can run on the local machine:
- Look for a build for the local OS and architecture, or a supported way to run the app from
source. The Linux binary uploaded to nibrun cannot run directly on macOS. Use the same app version and check that its data can move between the local and Linux builds.
- If supported, seed a dedicated data folder using the app's documented initialization command,
or run the local build bound to 127.0.0.1, complete admin setup, and stop it cleanly.
- Deploy the seeded folder with
--data-folder, using the Linux x86_64 binary. Supply any
encryption keys or other environment values the saved data needs on this first deploy.
- Check the public app requires the configured login and no longer offers an initial admin claim.
If seeding succeeds, the app starts with its admin account already claimed. Keep the configured data folder private: it contains the app's account state.
If a compatible local build or initialization method is unavailable, check whether the app can set initial admin credentials through configuration on its first boot. If neither approach is supported, explain that seeding could not be done and that first-visitor setup will be reachable when the public URL goes live.
Redeploying
Every deploy after that must name the app, or a non-interactive shell creates a second one. nib apps list finds the name again when a later session has to redeploy:
For a local binary, the CLI skips uploading when that app already has an artifact with the same bytes and filename. It still creates a new deployment with the configuration you supplied.
Environment variables are an edit, not a replacement — anything a deploy does not name is left alone, so secrets are set once:
Arguments for the binary go inside the quotes, not after them:
The binary may be an https url instead of a path, and nibrun fetches it rather than this machine uploading it:
Changing only how the binary starts is nib apps update, which runs the one the app already has rather than asking for it again. What no flag names is left alone:
nib run waits until the deployment is actually serving and prints the URL. Or drag the binary onto app.nibrun.com — same thing, no CLI.
Every option a deploy takes is listed by nib run anything --help — any word will do in place of the binary, because the help does not read it, and nib run --help on its own answers with the subcommand rather than the options. What is below is what --help does not say.
GitHub Actions
Deploy an existing app without an API key or nib login in CI. Use a CLI release with GitHub OIDC support. After signing in locally, configure which workflow may deploy:
Save this as .github/workflows/deploy.yml. Replace ./build.sh with the repository’s build command, ./my-server with its Linux x86_64 output, and APP_ID with the app ID from the setup command above:
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 90 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/deploy-to-nibrun/SKILL.md
Popularity
- Repository stars
- 115
- Repository forks
- 4
- 7-day trend score
- 0
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/ilbertt/nibrun/deploy-to-nibrun)