This guide takes you from zero to a running application in a GoShip VM.
GoShip requires a Linux host with hardware virtualization support. Install the following:
# Ubuntu/Debian
sudo apt install -y \
libvirt-dev libvirt-daemon-system \
qemu-system-x86 qemu-utils \
genisoimage \
libguestfs-tools
# Verify KVM is available (recommended but not required)
ls /dev/kvm
# Add your user to the libvirt group
sudo usermod -aG libvirt $USER
# Log out and back in for the group change to take effect
# Start libvirtd
sudo systemctl enable --now libvirtdNote: GoShip works without KVM using QEMU TCG (software emulation), but performance will be significantly degraded. See Troubleshooting — QEMU TCG Fallback for details.
You also need:
- Go 1.26+ — to build GoShip from source
- Docker (optional) — only needed inside VMs for container mode; GoShip installs it automatically during VM provisioning
Clone and build:
git clone https://github.com/guilhermebr/goship.git
cd goship
make buildThis produces two binaries in ./bin/:
goship— CLI tool (runs on your host)goship-init— VM agent (injected into VMs automatically)
Verify the build:
./bin/goship versionYou should see version info along with your libvirt and QEMU versions.
Download the Alpine Linux base image that GoShip uses for VMs:
./bin/goship image pullThis downloads an Alpine NoCloud QCOW2 image to ~/.goship/images/goship-vm.qcow2. The image is shared read-only — each VM gets its own copy-on-write overlay.
A project is an isolated VM where your apps will run:
./bin/goship project create myapp --cpu 1 --memory 512This command:
- Creates a CoW disk overlay from the base image
- Provisions
goship-initinto the overlay usingvirt-customize - Installs Docker inside the VM image
- Generates a cloud-init ISO with the VM's identity
- Builds libvirt domain XML and starts the VM
- Waits for GoShip Init to become ready
You'll see boot progress as the VM starts up. Once complete, the project is running.
Check it:
./bin/goship project list
./bin/goship project info myappAssign domains to your project so the reverse proxy can route HTTP traffic to your apps:
./bin/goship domain set myapp myapp.local
./bin/goship domain list myappAfter deploying apps, they'll be accessible at {appname}.{domain}:{proxy_port} (e.g., web.myapp.local:8081).
Create an app definition and deploy it:
# Define the app
./bin/goship app create myapp web --mode container --image nginx:alpine --port 8080:80
# Deploy it to the VM
./bin/goship app deploy myapp webThe deploy command sends the app spec to GoShip Init inside the VM, which pulls the image and starts the container.
# List all apps in the project
./bin/goship app list myapp
# Get detailed info for a specific app
./bin/goship app info myapp web# App logs
./bin/goship app logs myapp web
# Follow mode (polls every 2s)
./bin/goship app logs myapp web -f
# VM-level logs (GoShip Init)
./bin/goship project logs myapp
# Cloud-init logs (provisioning)
./bin/goship project logs myapp cloud-initGoShip can also run plain binaries directly inside VMs, without Docker. Build a static binary and deploy it:
# Create the app definition pointing to your local binary
./bin/goship app create myapp api \
--mode process \
--binary ./my-server \
--port 3000:3000 \
--restart-policy always
# Deploy — automatically uploads the binary to the VM
./bin/goship app deploy myapp apiThe binary is uploaded over virtio-serial with SHA256 verification, then started as a supervised process inside the VM.
# Stop and remove the app
./bin/goship app stop myapp web
./bin/goship app delete myapp web
# Delete the project and its VM
./bin/goship project delete myappInstead of calling libvirt directly, you can run the goship server REST API server and point the CLI at it:
# Start the API server (runs on :8080 by default)
goship server &
# Point the CLI at the API server
export GOSHIP_API_URL=http://localhost:8080
# All project/app commands now go through HTTP
./bin/goship project list
./bin/goship project create myapp --cpu 1 --memory 512
./bin/goship app create myapp web --image nginx:alpine --port 8080:80
./bin/goship app deploy myapp webThis enables remote management — the CLI no longer requires libvirt on the client machine. Some commands that require direct VM access (console, project logs, push-image) are not available in API mode.
- Concepts — Understand how GoShip works under the hood
- CLI Reference — Every command, flag, and example
- Troubleshooting — Common issues and fixes