vibebin: code and host inside Incus containers on your own VPS/server.
106
stars
2
commits
Go
primary language
Aug 10, 2026
updated
An Incus/LXC-based platform for self-hosting persistent AI coding agent sandboxes with Caddy reverse proxy and direct SSH routing to containers (suitable for VS Code remote ssh).
Create and host your vibe-coded apps on a single VPS/server.
Vibebin TUI Manager - Container detail view with quick actions:

AI Tools Admin Web App - Toggle AI coding tools on/off:

AI Tools Admin Web App - One-click update for all tools:

This project is 99.9% vibe-coded on the exe.dev platform using their Shelley Web AI Coding Agent and Claude Opus 4.5. Take that as you will. Note that the above exe.dev URL is a referral link for a free 30 day trial if you register. If you convert to a paid plan, both you and I will receive a one-time $50 in extra Shelley credits.
With that said, I am a huge proponent of the exe.dev platform, and if you can, you should definitely try it out and use their service. The love and care for that project/service is extremely evident... AND it is incredibly awesome (and I think it's in its infancy stages, so should only get better).
This is a very new project. Feel free to test and experiment but it's likely to have bugs and may not be ready for production. Use at your own risk.
This project provides the infrastructure to self-host your own AI coding environment on virtually any Linux server -- a VPS, cloud VM (EC2, GCP, Azure), or dedicated hardware. Because it uses Incus/LXC (container-based virtualization rather than nested VMs), it runs efficiently on KVM, VMware, Xen, Hyper-V, and most other hypervisors.
Each container is a fully persistent Linux sandbox running Ubuntu 24.04 LTS (Noble) or Debian 13 (Trixie), with:
code.yourdomain.com (Basic Auth protected)admin.code.yourdomain.com for managing AI coding toolsyourdomain.com| Component | Purpose |
|---|---|
| Incus (LXC) | Container runtime - lightweight, persistent Linux containers |
| Caddy | Reverse proxy with automatic HTTPS (Let's Encrypt) |
| SSHPiper | SSH routing - access any container via ssh -p 2222 container-name@host |
| SQLite | Local database for container metadata (/var/lib/vibebin/containers.db) |
| Ubuntu/Debian | Native Incus images (user choice during creation) |
| opencode | Open source AI coding agent with terminal and web UI |
| nanocode | NanoGPT-powered AI coding agent (fork of opencode) |
| shelley | AI coding web agent from Bold Software |
| claude-code | Anthropic's CLI coding agent |
This project installs opencode, nanocode, claude-code, and shelley in each container:
OpenCode is a 100% open source AI coding agent that works with multiple LLM providers:
NanoCode is a fork of OpenCode configured to work with NanoGPT as the default provider. It includes:
NanoGPT subscription is $8/month for 60,000 requests across all open models - an excellent value that works great with NanoCode.
Note: The nanocode web UI requires LLM configuration before it will work. SSH into the container and run nanocode (CLI mode) first to configure your LLM provider/API keys.
Disclosure: The NanoGPT link is an affiliate link.
Claude Code is Anthropic's official CLI coding agent:
ANTHROPIC_API_KEY environment variable)claude command in terminalNote: Claude Code is CLI-only and is not managed via the admin.code web UI. Use it directly in the terminal.
Shelley is a powerful AI web agent from Bold Software:
Note: Before starting Shelley, add your API keys to ~/.shelley_env. Custom models can be configured in Shelley's web UI, but doing so switches to "custom model mode" and the env var models will no longer be shown.
All AI Coding tools support terminal/web UI modes with the exception of Shelley (web UI only) and Claude Code (CLI only). OpenCode, NanoCode, and Shelley support configuring LLM providers from within their web UIs.
Through the webUIs on OpenCode/NanoCode, adding NanoGPT as the provider is seamless! With Shelley, you just need to add a custom model and set it up with the same concept as shown here. See the NanoGPT integrations page for setting up NanoGPT with various coding agents.
vibebin - Interactive TUI for container managementvibebin_sync_daemon - Background service for config synchronization (auto-heals Caddy routes on restart)containers.db - SQLite database storing container metadata (at /var/lib/vibebin/containers.db)Any KVM-based VPS will work well with vibebin. Here are some recommended options:
HostBRR - Budget-friendly with excellent performance:
Netcup - German provider with reliable infrastructure:
OVHcloud - Large European provider with competitive pricing:
Oracle Cloud Infrastructure (OCI) - Free tier available:
Disclosure: The HostBRR and Netcup links above are affiliate links.
Complete these security steps before installing vibebin.
Ensure your host SSH is properly secured in /etc/ssh/sshd_config:
PermitRootLogin no
PasswordAuthentication no
Restart SSH after changes: sudo systemctl restart sshd
If you want to use UFW firewall, install and configure it with the required rules:
# Install UFW
sudo apt update && sudo apt install -y ufw
# Allow required ports (SSH must be allowed before enabling!)
sudo ufw allow 22/tcp # Host SSH
sudo ufw allow 80/tcp # HTTP (Caddy)
sudo ufw allow 443/tcp # HTTPS (Caddy)
sudo ufw allow 2222/tcp # SSHPiper (container SSH)
# Enable UFW
sudo ufw enable
sudo systemctl enable ufw
After the first vibebin run (which installs Incus), add the bridge rules for container networking:
# Allow Incus bridge traffic (run after vibebin installs Incus)
sudo ufw allow in on incusbr0
sudo ufw route allow in on incusbr0
sudo ufw route allow out on incusbr0
Note: UFW is enabled at boot automatically after
ufw enable. Verify status withsudo ufw status verbose.
For additional protection against brute-force attacks, you can install fail2ban. By default, fail2ban protects the host SSH daemon (sshd). The docs/fail2ban.md guide extends this with Caddy and SSHPiper protection.
Note: Install fail2ban after the initial vibebin run so that Caddy and SSHPiper are already in place.
All administrative tasks should be performed as a regular user with sudo privileges, not as root directly.
# Install essential tools
sudo apt update && sudo apt install -y wget curl git jq htop tmux
# Ubuntu/Debian - install from official Go downloads
wget https://go.dev/dl/go1.23.5.linux-amd64.tar.gz
sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.23.5.linux-amd64.tar.gz
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
source ~/.bashrc
# Verify installation
go version
Note: For ARM64 systems, use
go1.23.5.linux-arm64.tar.gzinstead. Check https://go.dev/dl/ for the latest version.
Use the install script for a one-liner install or upgrade:
curl -fsSL https://raw.githubusercontent.com/jgbrwn/vibebin/main/install-upgrade.sh | bash
The script automatically:
/usr/local/bin/vibebin-sync service accordinglyIf you prefer to build manually:
# Clone and build
git clone https://github.com/jgbrwn/vibebin.git
cd vibebin
go build -o vibebin vibebin.go
go build -o vibebin_sync_daemon vibebin_sync_daemon.go
# Install binaries
sudo cp vibebin vibebin_sync_daemon /usr/local/bin/
# This auto-installs Incus, Caddy, and SSHPiper
sudo vibebin
See the SSHPiper Manual Setup section below.
sudo vibebin
The creation wizard will guide you through:
The first run automatically installs:
During container creation, the following is automatically installed:
Development Tools:
gh) for GitHub operationsAI Coding Agents:
System Utilities:
Configuration:
~/projects for AI coding tool workspaces)Before creating containers, verify SSHPiper is running:
# Check SSHPiper status (should be active)
sudo systemctl status sshpiperd
# If not running, start it
sudo systemctl enable --now sshpiperd
SSHPiper listens on port 2222 for container SSH access. Host SSH remains on port 22.
sudo vibebin
List View:
n - Create new containerEnter - View container detailsd - Delete containeru - Show untracked containers (import existing)D - Manage DNS API tokens (Cloudflare/deSEC)i - View Incus logsl - View sync daemon logsq - QuitDetail View:
s - Start/Stop containerr - Restart containerp - Change app porta - Change auth credentialsS - Snapshot managementu - Update AI coding tools (opencode/nanocode/claude-code/shelley)Esc - Back to listSnapshot View:
n - Create new snapshotEnter/r - Restore selected snapshotd - Delete selected snapshot↑/↓ or j/k - Navigate snapshotsEsc - Back to container detailshttps://domain.com → Container's app (port 8000, configurable)ssh -p 2222 container-name@host accessAfter creating a container, SSH in and run any of the tools. A project directory is pre-created at ~/projects for your coding workspaces.
# SSH to your container
ssh -p 2222 container-name@host.example.com
# cd to projects directory first
cd ~/projects
# Run opencode
opencode
# Or run nanocode
nanocode
# Or run claude-code
claude
All tools will prompt you to configure your LLM provider and API key on first run. Note that Shelley is web-only (no CLI mode) and Claude Code is CLI-only (no web UI).
To access the AI coding agent via web browser:
# SSH to your container
ssh -p 2222 container-name@host.example.com
opencode (cd to project directory first):
cd ~/projects
screen -S code
opencode serve --port 9999 --hostname 0.0.0.0
nanocode (cd to project directory first):
cd ~/projects
screen -S code
nanocode serve --port 9999 --hostname 0.0.0.0
Note: nanocode web UI requires LLM configuration first. Run
nanocode(CLI) to configure your provider/API keys before starting the web UI.
shelley (web UI only - no CLI mode):
cd ~/projects
screen -S code
start-shelley.sh 2>&1 | tee -a ~/.shelley.log
Note: Before starting Shelley, add your API keys to
~/.shelley_env. Custom models can be configured in Shelley's web UI, but doing so switches to "custom model mode" and the env var models will no longer be shown.
Then access via https://code.yourdomain.com (protected by Basic Auth credentials you set during container creation).
Press Ctrl+A, D to detach from screen. Reattach with screen -x code.
Note: Only one web UI can run on port 9999 at a time. Stop the current one before starting another.
Each container includes an AI Tools Admin web app accessible at https://admin.code.yourdomain.com. This provides:
MANAGE View:
UPDATE View:
The admin app runs as a systemd service (admin-app) and is protected by the same Basic Auth credentials as the Code UI.
Note: For Shelley, ensure your API keys are configured in
~/.shelley_envbefore starting.
From the container detail view in the TUI, press u to update opencode, nanocode, claude-code, and shelley to their latest versions.
ssh -p 2222 container-name@host.example.com
# You'll be logged in as 'ubuntu' (or 'debian') with sudo access
ssh user@host.example.com
For HTTPS to work, DNS must point to the host server:
domain.com → Host IPcode.domain.com → Host IP (for AI coding web UI)admin.code.domain.com → Host IP (for AI tools admin app)Caddy will automatically obtain Let's Encrypt certificates for both domains.
Internet
│
┌────────────┴────────────┐
│ │
▼ ▼
HTTPS (:443) SSH (:2222 via SSHPiper)
│ │
┌───────────────────▼─────────────────────▼─────────────────┐
│ Host System │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Caddy │ │ SSHPiper │ │
│ │ (reverse │ │ (SSH │ │
│ │ proxy) │ │ router) │ │
│ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │
│ │ Routes by domain │ Routes by username │
│ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Incus (LXC) │ │
│ │ │ │
│ │ ┌─────────────────┐ ┌─────────────────┐ │ │
│ │ │ Container │ │ Container │ ... │ │
│ │ │ (Ubuntu/Debian)│ │ (Ubuntu/Debian)│ │ │
│ │ │ │ │ │ │ │
│ │ │ ┌───────────┐ │ │ ┌───────────┐ │ │ │
│ │ │ │ AI Coding │ │ │ │ AI Coding │ │ │ │
│ │ │ │ Tool UI │ │ │ │ Tool UI │ │ │ │
│ │ │ │ (:9999) │ │ │ │ (:9999) │ │ │ │
│ │ │ └───────────┘ │ │ └───────────┘ │ │ │
│ │ │ ┌───────────┐ │ │ ┌───────────┐ │ │ │
│ │ │ │admin.code │ │ │ │admin.code │ │ │ │
│ │ │ │ (:8099) │ │ │ │ (:8099) │ │ │ │
│ │ │ └───────────┘ │ │ └───────────┘ │ │ │
│ │ │ ┌───────────┐ │ │ ┌───────────┐ │ │ │
│ │ │ │ Your App │ │ │ │ Your App │ │ │ │
│ │ │ │ (:8000) │ │ │ │ (:8000) │ │ │ │
│ │ │ └───────────┘ │ │ └───────────┘ │ │ │
│ │ └─────────────────┘ └─────────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────┐ │
│ │ vibebin │ TUI for container management │
│ │ (this tool) │ - Create/delete containers │
│ │ │ - Configure domains & auth │
│ └───────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
myapp.example.com → Caddy → Container's app (port 8000)code.myapp.example.com → Caddy (with Basic Auth) → AI coding web UI (port 9999)myapp-example-com@host → SSHPiper → Container's SSH as ubuntu/debianRoutes are managed via Caddy's Admin API (localhost:2019), not config files:
@id for identification (e.g., container-name-app, container-name-code)vibebin-sync service monitors Caddy routes and automatically restores them if the server restarts, Caddy restarts, or routes are otherwise modified/removedcurl http://localhost:2019/config/apps/http/servers/srv0/routesContainers use Incus's default "last-state" behavior (by not setting boot.autostart):
Incus automatically tracks each container's power state and restores it when the daemon starts.
Snapshots allow you to save and restore the complete state of a container.
From the container detail view, press S to access snapshot management, then n to create.
Note: Snapshots are stored by Incus and consume disk space. Delete old snapshots to free space.
Container won't start:
journalctl -u incus -f
incus info container-name
Caddy certificate errors:
journalctl -u caddy -fcurl -s http://localhost:2019/config/apps/http/servers/srv0/routes | jq .SSH to containers not working:
systemctl status sshpiperdssh -p 2222 container-name@hostcat /var/lib/sshpiper/container-name/sshpiper_upstreamAI coding tools not working:
opencode, nanocode, or claude interactively, or start-shelley.sh for Shelley web UIopencode --version, nanocode --version, claude --version, shelley versionSync daemon issues:
journalctl -u vibebin-sync -f
You can use subdomains for your containers:
app.example.com - works correctlystaging.app.example.com - works correctlymy-app.example.com - works correctlyDomains with two-part TLDs (like .co.uk, .com.au) are not fully supported
for automatic DNS creation. The zone detection assumes a single-part TLD.
For example:
app.example.com → zone: example.com (correct)app.example.co.uk → zone: co.uk (incorrect, should be example.co.uk)Workaround: For two-part TLDs, select "No" for auto DNS creation and configure DNS records manually.
Each container created by vibebin is fully isolated by default:
10.x.x.x)security.nesting=true is enabled to allow Docker-in-container (useful for development). This is standard for development environments but worth noting for security-sensitive deployments.
If you run 3 containers (app1.example.com, app2.example.com, app3.example.com):
It's essentially like having separate lightweight VMs, but with much lower overhead than full virtualization.
Currently, this implementation uses the Incus DIR storage driver for proof of concept. The DIR driver uses basic filesystem-level storage and is:
Planned: During the dependencies/installation phase, users will be able to choose between:
| Driver | Pros | Cons |
|---|---|---|
| DIR | Simple, works everywhere | Slow snapshots, no CoW |
| Btrfs | Fast snapshots, CoW, compression | Requires Btrfs filesystem |
| ZFS | Fast snapshots, CoW, excellent features | Requires significant RAM (1GB+ per TB of storage) |
Btrfs and ZFS provide instant snapshots via copy-on-write, making them much more suitable for production use.
This project is licensed under the MIT License. See LICENSE for details.
2 commits
Hacker News (1)
Go
98.0%
Shell
2.0%
vibebin: code and host inside Incus containers on your own VPS/server.
106
stars
2
commits
Go
primary language
Aug 10, 2026
updated
An Incus/LXC-based platform for self-hosting persistent AI coding agent sandboxes with Caddy reverse proxy and direct SSH routing to containers (suitable for VS Code remote ssh).
Create and host your vibe-coded apps on a single VPS/server.
Vibebin TUI Manager - Container detail view with quick actions:

AI Tools Admin Web App - Toggle AI coding tools on/off:

AI Tools Admin Web App - One-click update for all tools:

This project is 99.9% vibe-coded on the exe.dev platform using their Shelley Web AI Coding Agent and Claude Opus 4.5. Take that as you will. Note that the above exe.dev URL is a referral link for a free 30 day trial if you register. If you convert to a paid plan, both you and I will receive a one-time $50 in extra Shelley credits.
With that said, I am a huge proponent of the exe.dev platform, and if you can, you should definitely try it out and use their service. The love and care for that project/service is extremely evident... AND it is incredibly awesome (and I think it's in its infancy stages, so should only get better).
This is a very new project. Feel free to test and experiment but it's likely to have bugs and may not be ready for production. Use at your own risk.
This project provides the infrastructure to self-host your own AI coding environment on virtually any Linux server -- a VPS, cloud VM (EC2, GCP, Azure), or dedicated hardware. Because it uses Incus/LXC (container-based virtualization rather than nested VMs), it runs efficiently on KVM, VMware, Xen, Hyper-V, and most other hypervisors.
Each container is a fully persistent Linux sandbox running Ubuntu 24.04 LTS (Noble) or Debian 13 (Trixie), with:
code.yourdomain.com (Basic Auth protected)admin.code.yourdomain.com for managing AI coding toolsyourdomain.com| Component | Purpose |
|---|---|
| Incus (LXC) | Container runtime - lightweight, persistent Linux containers |
| Caddy | Reverse proxy with automatic HTTPS (Let's Encrypt) |
| SSHPiper | SSH routing - access any container via ssh -p 2222 container-name@host |
| SQLite | Local database for container metadata (/var/lib/vibebin/containers.db) |
| Ubuntu/Debian | Native Incus images (user choice during creation) |
| opencode | Open source AI coding agent with terminal and web UI |
| nanocode | NanoGPT-powered AI coding agent (fork of opencode) |
| shelley | AI coding web agent from Bold Software |
| claude-code | Anthropic's CLI coding agent |
This project installs opencode, nanocode, claude-code, and shelley in each container:
OpenCode is a 100% open source AI coding agent that works with multiple LLM providers:
NanoCode is a fork of OpenCode configured to work with NanoGPT as the default provider. It includes:
NanoGPT subscription is $8/month for 60,000 requests across all open models - an excellent value that works great with NanoCode.
Note: The nanocode web UI requires LLM configuration before it will work. SSH into the container and run nanocode (CLI mode) first to configure your LLM provider/API keys.
Disclosure: The NanoGPT link is an affiliate link.
Claude Code is Anthropic's official CLI coding agent:
ANTHROPIC_API_KEY environment variable)claude command in terminalNote: Claude Code is CLI-only and is not managed via the admin.code web UI. Use it directly in the terminal.
Shelley is a powerful AI web agent from Bold Software:
Note: Before starting Shelley, add your API keys to ~/.shelley_env. Custom models can be configured in Shelley's web UI, but doing so switches to "custom model mode" and the env var models will no longer be shown.
All AI Coding tools support terminal/web UI modes with the exception of Shelley (web UI only) and Claude Code (CLI only). OpenCode, NanoCode, and Shelley support configuring LLM providers from within their web UIs.
Through the webUIs on OpenCode/NanoCode, adding NanoGPT as the provider is seamless! With Shelley, you just need to add a custom model and set it up with the same concept as shown here. See the NanoGPT integrations page for setting up NanoGPT with various coding agents.
vibebin - Interactive TUI for container managementvibebin_sync_daemon - Background service for config synchronization (auto-heals Caddy routes on restart)containers.db - SQLite database storing container metadata (at /var/lib/vibebin/containers.db)Any KVM-based VPS will work well with vibebin. Here are some recommended options:
HostBRR - Budget-friendly with excellent performance:
Netcup - German provider with reliable infrastructure:
OVHcloud - Large European provider with competitive pricing:
Oracle Cloud Infrastructure (OCI) - Free tier available:
Disclosure: The HostBRR and Netcup links above are affiliate links.
Complete these security steps before installing vibebin.
Ensure your host SSH is properly secured in /etc/ssh/sshd_config:
PermitRootLogin no
PasswordAuthentication no
Restart SSH after changes: sudo systemctl restart sshd
If you want to use UFW firewall, install and configure it with the required rules:
# Install UFW
sudo apt update && sudo apt install -y ufw
# Allow required ports (SSH must be allowed before enabling!)
sudo ufw allow 22/tcp # Host SSH
sudo ufw allow 80/tcp # HTTP (Caddy)
sudo ufw allow 443/tcp # HTTPS (Caddy)
sudo ufw allow 2222/tcp # SSHPiper (container SSH)
# Enable UFW
sudo ufw enable
sudo systemctl enable ufw
After the first vibebin run (which installs Incus), add the bridge rules for container networking:
# Allow Incus bridge traffic (run after vibebin installs Incus)
sudo ufw allow in on incusbr0
sudo ufw route allow in on incusbr0
sudo ufw route allow out on incusbr0
Note: UFW is enabled at boot automatically after
ufw enable. Verify status withsudo ufw status verbose.
For additional protection against brute-force attacks, you can install fail2ban. By default, fail2ban protects the host SSH daemon (sshd). The docs/fail2ban.md guide extends this with Caddy and SSHPiper protection.
Note: Install fail2ban after the initial vibebin run so that Caddy and SSHPiper are already in place.
All administrative tasks should be performed as a regular user with sudo privileges, not as root directly.
# Install essential tools
sudo apt update && sudo apt install -y wget curl git jq htop tmux
# Ubuntu/Debian - install from official Go downloads
wget https://go.dev/dl/go1.23.5.linux-amd64.tar.gz
sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.23.5.linux-amd64.tar.gz
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
source ~/.bashrc
# Verify installation
go version
Note: For ARM64 systems, use
go1.23.5.linux-arm64.tar.gzinstead. Check https://go.dev/dl/ for the latest version.
Use the install script for a one-liner install or upgrade:
curl -fsSL https://raw.githubusercontent.com/jgbrwn/vibebin/main/install-upgrade.sh | bash
The script automatically:
/usr/local/bin/vibebin-sync service accordinglyIf you prefer to build manually:
# Clone and build
git clone https://github.com/jgbrwn/vibebin.git
cd vibebin
go build -o vibebin vibebin.go
go build -o vibebin_sync_daemon vibebin_sync_daemon.go
# Install binaries
sudo cp vibebin vibebin_sync_daemon /usr/local/bin/
# This auto-installs Incus, Caddy, and SSHPiper
sudo vibebin
See the SSHPiper Manual Setup section below.
sudo vibebin
The creation wizard will guide you through:
The first run automatically installs:
During container creation, the following is automatically installed:
Development Tools:
gh) for GitHub operationsAI Coding Agents:
System Utilities:
Configuration:
~/projects for AI coding tool workspaces)Before creating containers, verify SSHPiper is running:
# Check SSHPiper status (should be active)
sudo systemctl status sshpiperd
# If not running, start it
sudo systemctl enable --now sshpiperd
SSHPiper listens on port 2222 for container SSH access. Host SSH remains on port 22.
sudo vibebin
List View:
n - Create new containerEnter - View container detailsd - Delete containeru - Show untracked containers (import existing)D - Manage DNS API tokens (Cloudflare/deSEC)i - View Incus logsl - View sync daemon logsq - QuitDetail View:
s - Start/Stop containerr - Restart containerp - Change app porta - Change auth credentialsS - Snapshot managementu - Update AI coding tools (opencode/nanocode/claude-code/shelley)Esc - Back to listSnapshot View:
n - Create new snapshotEnter/r - Restore selected snapshotd - Delete selected snapshot↑/↓ or j/k - Navigate snapshotsEsc - Back to container detailshttps://domain.com → Container's app (port 8000, configurable)ssh -p 2222 container-name@host accessAfter creating a container, SSH in and run any of the tools. A project directory is pre-created at ~/projects for your coding workspaces.
# SSH to your container
ssh -p 2222 container-name@host.example.com
# cd to projects directory first
cd ~/projects
# Run opencode
opencode
# Or run nanocode
nanocode
# Or run claude-code
claude
All tools will prompt you to configure your LLM provider and API key on first run. Note that Shelley is web-only (no CLI mode) and Claude Code is CLI-only (no web UI).
To access the AI coding agent via web browser:
# SSH to your container
ssh -p 2222 container-name@host.example.com
opencode (cd to project directory first):
cd ~/projects
screen -S code
opencode serve --port 9999 --hostname 0.0.0.0
nanocode (cd to project directory first):
cd ~/projects
screen -S code
nanocode serve --port 9999 --hostname 0.0.0.0
Note: nanocode web UI requires LLM configuration first. Run
nanocode(CLI) to configure your provider/API keys before starting the web UI.
shelley (web UI only - no CLI mode):
cd ~/projects
screen -S code
start-shelley.sh 2>&1 | tee -a ~/.shelley.log
Note: Before starting Shelley, add your API keys to
~/.shelley_env. Custom models can be configured in Shelley's web UI, but doing so switches to "custom model mode" and the env var models will no longer be shown.
Then access via https://code.yourdomain.com (protected by Basic Auth credentials you set during container creation).
Press Ctrl+A, D to detach from screen. Reattach with screen -x code.
Note: Only one web UI can run on port 9999 at a time. Stop the current one before starting another.
Each container includes an AI Tools Admin web app accessible at https://admin.code.yourdomain.com. This provides:
MANAGE View:
UPDATE View:
The admin app runs as a systemd service (admin-app) and is protected by the same Basic Auth credentials as the Code UI.
Note: For Shelley, ensure your API keys are configured in
~/.shelley_envbefore starting.
From the container detail view in the TUI, press u to update opencode, nanocode, claude-code, and shelley to their latest versions.
ssh -p 2222 container-name@host.example.com
# You'll be logged in as 'ubuntu' (or 'debian') with sudo access
ssh user@host.example.com
For HTTPS to work, DNS must point to the host server:
domain.com → Host IPcode.domain.com → Host IP (for AI coding web UI)admin.code.domain.com → Host IP (for AI tools admin app)Caddy will automatically obtain Let's Encrypt certificates for both domains.
Internet
│
┌────────────┴────────────┐
│ │
▼ ▼
HTTPS (:443) SSH (:2222 via SSHPiper)
│ │
┌───────────────────▼─────────────────────▼─────────────────┐
│ Host System │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Caddy │ │ SSHPiper │ │
│ │ (reverse │ │ (SSH │ │
│ │ proxy) │ │ router) │ │
│ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │
│ │ Routes by domain │ Routes by username │
│ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Incus (LXC) │ │
│ │ │ │
│ │ ┌─────────────────┐ ┌─────────────────┐ │ │
│ │ │ Container │ │ Container │ ... │ │
│ │ │ (Ubuntu/Debian)│ │ (Ubuntu/Debian)│ │ │
│ │ │ │ │ │ │ │
│ │ │ ┌───────────┐ │ │ ┌───────────┐ │ │ │
│ │ │ │ AI Coding │ │ │ │ AI Coding │ │ │ │
│ │ │ │ Tool UI │ │ │ │ Tool UI │ │ │ │
│ │ │ │ (:9999) │ │ │ │ (:9999) │ │ │ │
│ │ │ └───────────┘ │ │ └───────────┘ │ │ │
│ │ │ ┌───────────┐ │ │ ┌───────────┐ │ │ │
│ │ │ │admin.code │ │ │ │admin.code │ │ │ │
│ │ │ │ (:8099) │ │ │ │ (:8099) │ │ │ │
│ │ │ └───────────┘ │ │ └───────────┘ │ │ │
│ │ │ ┌───────────┐ │ │ ┌───────────┐ │ │ │
│ │ │ │ Your App │ │ │ │ Your App │ │ │ │
│ │ │ │ (:8000) │ │ │ │ (:8000) │ │ │ │
│ │ │ └───────────┘ │ │ └───────────┘ │ │ │
│ │ └─────────────────┘ └─────────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────┐ │
│ │ vibebin │ TUI for container management │
│ │ (this tool) │ - Create/delete containers │
│ │ │ - Configure domains & auth │
│ └───────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
myapp.example.com → Caddy → Container's app (port 8000)code.myapp.example.com → Caddy (with Basic Auth) → AI coding web UI (port 9999)myapp-example-com@host → SSHPiper → Container's SSH as ubuntu/debianRoutes are managed via Caddy's Admin API (localhost:2019), not config files:
@id for identification (e.g., container-name-app, container-name-code)vibebin-sync service monitors Caddy routes and automatically restores them if the server restarts, Caddy restarts, or routes are otherwise modified/removedcurl http://localhost:2019/config/apps/http/servers/srv0/routesContainers use Incus's default "last-state" behavior (by not setting boot.autostart):
Incus automatically tracks each container's power state and restores it when the daemon starts.
Snapshots allow you to save and restore the complete state of a container.
From the container detail view, press S to access snapshot management, then n to create.
Note: Snapshots are stored by Incus and consume disk space. Delete old snapshots to free space.
Container won't start:
journalctl -u incus -f
incus info container-name
Caddy certificate errors:
journalctl -u caddy -fcurl -s http://localhost:2019/config/apps/http/servers/srv0/routes | jq .SSH to containers not working:
systemctl status sshpiperdssh -p 2222 container-name@hostcat /var/lib/sshpiper/container-name/sshpiper_upstreamAI coding tools not working:
opencode, nanocode, or claude interactively, or start-shelley.sh for Shelley web UIopencode --version, nanocode --version, claude --version, shelley versionSync daemon issues:
journalctl -u vibebin-sync -f
You can use subdomains for your containers:
app.example.com - works correctlystaging.app.example.com - works correctlymy-app.example.com - works correctlyDomains with two-part TLDs (like .co.uk, .com.au) are not fully supported
for automatic DNS creation. The zone detection assumes a single-part TLD.
For example:
app.example.com → zone: example.com (correct)app.example.co.uk → zone: co.uk (incorrect, should be example.co.uk)Workaround: For two-part TLDs, select "No" for auto DNS creation and configure DNS records manually.
Each container created by vibebin is fully isolated by default:
10.x.x.x)security.nesting=true is enabled to allow Docker-in-container (useful for development). This is standard for development environments but worth noting for security-sensitive deployments.
If you run 3 containers (app1.example.com, app2.example.com, app3.example.com):
It's essentially like having separate lightweight VMs, but with much lower overhead than full virtualization.
Currently, this implementation uses the Incus DIR storage driver for proof of concept. The DIR driver uses basic filesystem-level storage and is:
Planned: During the dependencies/installation phase, users will be able to choose between:
| Driver | Pros | Cons |
|---|---|---|
| DIR | Simple, works everywhere | Slow snapshots, no CoW |
| Btrfs | Fast snapshots, CoW, compression | Requires Btrfs filesystem |
| ZFS | Fast snapshots, CoW, excellent features | Requires significant RAM (1GB+ per TB of storage) |
Btrfs and ZFS provide instant snapshots via copy-on-write, making them much more suitable for production use.
This project is licensed under the MIT License. See LICENSE for details.
Hacker News (1)
2 commits
Go
98.0%
Shell
2.0%