Complete reference for goship, the GoShip command-line tool.
These flags apply to all commands:
| Flag | Default | Description |
|---|---|---|
--data-dir |
~/.goship |
Data directory for GoShip state, images, and VM files |
-v, --verbose |
true |
Enable verbose output |
--goship-init |
./bin/goship-init |
Path to the goship-init binary used during VM provisioning |
--skip-guest-provision |
false |
Skip guest disk provisioning (goship-init injection) |
--install-docker |
true |
Install Docker during guest provisioning |
--api-url |
(empty) | GoShip API server URL (env: GOSHIP_API_URL). When set, CLI uses HTTP instead of direct libvirt |
goship server is configured via environment variables (using ardanlabs/conf):
| Variable | Default | Description |
|---|---|---|
GOSHIP_ADDR |
:8080 |
API server listen address |
GOSHIP_PROXY_ADDR |
:8081 |
Reverse proxy listen address |
GOSHIP_DATA_DIR |
~/.goship |
Data directory |
GOSHIP_INIT_BINARY_PATH |
./bin/goship-init |
Path to goship-init binary |
GOSHIP_LIBVIRT_URI |
qemu:///system |
Libvirt connection URI |
When --api-url (or GOSHIP_API_URL) is set, goship talks to a running goship server server over HTTP instead of calling libvirt directly. This enables remote management without requiring libvirt on the client machine.
# Start the API server
goship server &
# Use CLI in API mode
export GOSHIP_API_URL=http://localhost:8080
goship project list
goship project create myapp --cpu 1 --memory 512Some commands are not available in API mode and return an error:
project console,project logs,project edit,project update-initapp edit,app push-imageenv set,env list,env delete
Prints version, commit hash, build time, and libvirt/QEMU version info.
goship versionExample output:
goship dev
commit: 827853a
built: 2025-01-15T10:30:00Z
Libvirt version: 10.0.0
QEMU version: 8.2.2
Discovers and displays host virtualization capabilities: hypervisor type, KVM status, CPU topology, memory, hugepages, and confidential computing support.
goship capabilitiesExample output:
Host Capabilities
=================
Hypervisor: QEMU
Architecture: x86_64
KVM: yes
CPU Model: Skylake-Client
CPU Vendor: Intel
Topology: 1 socket(s), 8 core(s), 2 thread(s) [16 vCPUs]
Memory: 32768 MB (32.0 GB)
Hugepages: yes (2048kB)
Confidential: none detected
Libvirt: 10.0.0
QEMU: 8.2.2
Generates a libvirt domain XML document from flags. Does not require a libvirt connection. Useful for experimenting with VM configurations.
goship generate-xml [flags]Flags:
| Flag | Default | Description |
|---|---|---|
--name |
goship-vm |
VM name |
--uuid |
(auto-generated) | VM UUID |
--memory |
512 |
Memory in MB |
--cpus |
1 |
Number of CPU cores |
--enable-kvm |
true |
Enable KVM acceleration |
--disk-path |
/var/lib/goship/disk.qcow2 |
Disk image path |
--disk-format |
qcow2 |
Disk format |
--network-type |
network |
Network type (network, bridge, user) |
--network-source |
default |
Network source name |
Example:
goship generate-xml --name test-vm --memory 1024 --cpus 2Manage VM base images.
Downloads the Alpine Linux NoCloud QCOW2 image used as the GoShip base image.
goship image pull [flags]Flags:
| Flag | Default | Description |
|---|---|---|
--output |
~/.goship/images/goship-vm.qcow2 |
Output path for the downloaded image |
--force |
false |
Overwrite existing image |
Example:
goship image pull
goship image pull --force # re-downloadBuilds a plain base image locally by downloading the Alpine source and resizing it. Does not install goship-init (that happens per-VM during project create).
goship image build [flags]Flags:
| Flag | Default | Description |
|---|---|---|
--output |
~/.goship/images/goship-vm.qcow2 |
Output path for the built image |
--force |
false |
Overwrite existing image |
--image-size |
2G |
Resize image to this virtual size |
Example:
goship image build --image-size 4GManage projects. Each project runs in its own isolated VM.
Creates a new project with its own VM. Provisions the VM with cloud-init, injects goship-init, and optionally installs Docker.
goship project create <name> [flags]Flags:
| Flag | Default | Description |
|---|---|---|
--cpu |
1 |
Number of CPU cores |
--memory |
512 |
Memory in MB |
--disk |
4096 |
Disk size in MB |
--network-type |
Network type (network, bridge, user) |
|
--network-source |
Network source name |
Example:
goship project create webapp --cpu 2 --memory 1024 --disk 8192
goship project create minimal # uses defaults: 1 CPU, 512MB RAM, 4GB diskLists all projects with state, runtime, resources, and creation time.
goship project listAlias: goship project ls
Shows detailed project information including VM instance details and apps.
goship project info myappExample output:
Project: myapp
ID: a1b2c3d4
State: running
Runtime: qemu
CPU: 2 cores
Memory: 1024 MB
Disk: 4096 MB
Created: 2025-01-15T10:30:00Z
VM Instance:
ID: e5f6g7h8
State: running
IP: 192.168.122.45
Domain: goship-myapp
Apps:
- web (image: nginx:alpine)
- api (binary: /opt/goship/binaries/api/myapi)
Destroys the project's VM and removes the project from the state store.
goship project delete myappAlias: goship project rm myapp
Opens an interactive serial console to the project VM via virsh console. Use Ctrl+] to exit.
goship project console myappShows logs from the project VM.
goship project logs <name> [source] [flags]Log sources (positional argument):
| Source | Path in VM |
|---|---|
goship-init (default) |
/var/log/goship-init.log |
cloud-init |
/var/log/cloud-init-output.log |
Flags:
| Flag | Default | Description |
|---|---|---|
-n, --lines |
100 |
Number of log lines to show |
-f, --follow |
false |
Follow log output (poll every 2s) |
--file |
Arbitrary log file path inside the VM (must be under /var/log/) |
Examples:
goship project logs myapp # GoShip Init logs (default)
goship project logs myapp cloud-init # Cloud-init provisioning logs
goship project logs myapp -f # Follow GoShip Init logs
goship project logs myapp --file /var/log/messages # Arbitrary log fileGracefully stops the project VM by sending an ACPI shutdown signal.
goship project stop myappStarts a previously stopped project VM.
goship project start myappRestarts a project VM (stop, wait for shutdown, then start).
goship project restart myappPushes a new goship-init binary into a running VM over virtio-serial using a chunked transfer protocol (512KB chunks with SHA256 verification).
goship project update-init <name> [flags]Flags:
| Flag | Default | Description |
|---|---|---|
--binary |
(uses global --goship-init value) |
Path to the goship-init binary |
--restart |
false |
Restart the VM after successful update |
Example:
make build-goship-init
goship project update-init myapp --restartManage applications inside project VMs.
Creates an application definition in the project. Does not start anything — use app deploy to push it to the VM.
goship app create <project> <appname> [flags]Flags:
| Flag | Default | Description |
|---|---|---|
-m, --mode |
container |
Execution mode: container or process |
-i, --image |
Container image (required for container mode) | |
-b, --binary |
Path to binary (required for process mode) | |
-p, --port |
Port mapping host:container (repeatable) |
|
-e, --env |
Environment variable KEY=VALUE (repeatable) |
|
--cpu |
0 |
CPU limit in cores |
--memory |
0 |
Memory limit in MB |
-r, --replicas |
1 |
Number of replicas |
-d, --description |
App description | |
-g, --tag |
Tags (repeatable) | |
--restart-policy |
never |
Restart policy: never, always, or on-failure |
--hostname |
(app name) | Hostname for reverse proxy routing (default: app name) |
--available |
true |
Whether the app is routable via the reverse proxy |
Examples:
# Container app
goship app create myapp web \
--image nginx:alpine \
--port 8080:80 \
--env "ENV=production"
# Process app with auto-restart
goship app create myapp api \
--mode process \
--binary ./bin/myapi \
--port 3000:3000 \
--restart-policy always \
--env "DATABASE_URL=postgres://..."Deploys an application to the project VM. For container mode, GoShip Init pulls the image and starts the container. For process mode with a local binary, the binary is automatically uploaded to the VM (with SHA256 verification) before starting.
goship app deploy myapp webLists all applications in a project with live status from the VM.
goship app list myappAlias: goship app ls myapp
Example output:
NAME MODE IMAGE/BINARY STATUS PORTS
web container nginx:alpine running 8080:80
api process /opt/goship/binaries/api/myapi running 3000:3000
Shows detailed application information including configuration and live status.
goship app info myapp webStops a running application inside the project VM.
goship app stop myapp webRemoves the application from the VM (best-effort) and deletes it from the state store.
goship app delete myapp webAlias: goship app rm myapp web
Shows application logs. For container apps, reads Docker logs. For process apps, reads from /var/log/goship-<appname>.log inside the VM.
goship app logs <project> <appname> [flags]Flags:
| Flag | Default | Description |
|---|---|---|
-n, --lines |
100 |
Number of log lines to show |
-f, --follow |
false |
Follow log output (poll every 2s) |
Examples:
goship app logs myapp web
goship app logs myapp api -n 50
goship app logs myapp web -fExports a local Docker image, compresses it with gzip, and transfers it into the project VM over virtio-serial. No registry needed.
goship app push-image myapp myimage:latestModifies an application's configuration without deploying. Changes take effect on next app deploy.
goship app edit <project> <appname> [flags]Flags:
| Flag | Default | Description |
|---|---|---|
-i, --image |
Container image | |
-b, --binary |
Binary path (process mode) | |
-p, --port |
Port mapping (repeatable, replaces all) | |
-e, --env |
Set env var KEY=VALUE (repeatable) |
|
--env-file |
Load env vars from a file | |
-d, --description |
App description | |
-g, --tag |
Tags (repeatable, replaces all) | |
--restart-policy |
Restart policy: never, always, on-failure |
|
--cpu |
CPU limit in cores | |
--memory |
Memory limit (e.g., 512M, 2G) |
Example:
goship app edit myapp web --port 9090:80 --env "LOG_LEVEL=debug"
goship app deploy myapp web # apply changesLow-level VM lifecycle commands. These are experimental commands for learning and debugging — use project commands for normal workflows.
Creates a CoW disk overlay, provisions goship-init, generates domain XML, and starts a VM.
goship vm create <name> [flags]Flags:
| Flag | Default | Description |
|---|---|---|
--base-image |
~/.goship/images/goship-vm.qcow2 |
Base qcow2 image path |
--memory |
512 |
Memory in MB |
--cpus |
1 |
Number of CPU cores |
--enable-kvm |
true |
Enable KVM acceleration |
--network-type |
network |
Network type (network, bridge, user) |
--network-source |
default |
Network source name |
--data-dir |
~/.goship |
Data directory |
--hostname |
(VM name) | VM hostname |
--ssh-key |
Path to SSH public key file | |
--goship-init |
./bin/goship-init |
Path to goship-init binary |
--skip-guest-provision |
false |
Skip guest provisioning |
--install-docker |
true |
Install Docker during provisioning |
Stops and undefines a VM, optionally removing its disk.
goship vm destroy <name> [flags]Flags:
| Flag | Default | Description |
|---|---|---|
--data-dir |
~/.goship |
Data directory |
--keep-disk |
false |
Keep disk image after destroying |
Lists all GoShip-managed VMs (domains with the goship- prefix) and their state.
goship vm listSends a ping command to the GoShip Init agent inside a VM via virtio-serial.
goship vm ping myvmFlags:
| Flag | Default | Description |
|---|---|---|
--data-dir |
~/.goship |
Data directory |
Manage project domains for reverse proxy routing.
Sets the domains assigned to a project (replaces all existing domains). The first domain becomes the default unless overridden with --default.
goship domain set <project> <domain> [domain...] [flags]Flags:
| Flag | Default | Description |
|---|---|---|
--default |
(first domain) | Override which domain is the default |
Examples:
goship domain set myapp myapp.local
goship domain set myapp myapp.local myapp.dev --default myapp.devLists all domains assigned to a project with the default domain marked.
goship domain list myappAlias: goship domain ls myapp
Example output:
DOMAIN DEFAULT
myapp.local *
myapp.dev
Removes specific domains from a project. If the default domain is removed, the first remaining domain becomes the new default.
goship domain remove myapp myapp.devAlias: goship domain rm myapp myapp.dev
Manage cluster nodes. Nodes represent compute hosts in the GoShip cluster.
Registers a new node in the cluster.
goship node register <hostname> [flags]Flags:
| Flag | Default | Description |
|---|---|---|
--endpoint |
(empty) | Node agent endpoint (ip:port) |
--label |
Labels as key=value (repeatable) |
Examples:
goship node register worker-1 --endpoint 10.0.0.5:9090
goship node register worker-2 --endpoint 10.0.0.6:9090 --label region=us-east --label tier=computeExample output:
Node 'worker-1' registered successfully
ID: a1b2c3d4
Endpoint: 10.0.0.5:9090
Status: online
Lists all registered nodes.
goship node listAlias: goship node ls
Example output:
HOSTNAME ID STATUS ENDPOINT LAST HEARTBEAT
worker-1 a1b2c3d4 online 10.0.0.5:9090 2026-03-10 14:30
worker-2 e5f6g7h8 draining 10.0.0.6:9090 2026-03-10 14:28
Shows detailed information about a node.
goship node info worker-1Example output:
Hostname: worker-1
ID: a1b2c3d4-e5f6-7890-abcd-ef1234567890
Status: online
Endpoint: 10.0.0.5:9090
Labels:
region=us-east
tier=compute
Last Heartbeat: 2026-03-10T14:30:00Z
Created: 2026-03-10T10:00:00Z
Updated: 2026-03-10T14:30:00Z
Removes a node from the cluster.
goship node remove worker-1Alias: goship node rm worker-1
Marks a node as draining. A draining node will not receive new workloads.
goship node drain worker-1Example output:
Node 'worker-1' is now draining
When running goship server, the following additional endpoints are available for reverse proxy management:
PUT /api/v1/projects/{id}/domains — Update domains assigned to a project.
curl -X PUT http://localhost:8080/api/v1/projects/myapp/domains \
-d '{"domains":["myapp.local","myapp.dev"],"default_domain":"myapp.local"}'GET /api/v1/proxy/routes — List all active proxy routes.
curl http://localhost:8080/api/v1/proxy/routesExample response:
[
{"domain": "web.myapp.local", "backend": "192.168.122.10:8080"},
{"domain": "api.myapp.local", "backend": "192.168.122.10:3000"}
]POST /api/v1/nodes — Register a new node.
curl -X POST http://localhost:8080/api/v1/nodes \
-d '{"hostname":"worker-1","endpoint":"10.0.0.5:9090","labels":{"region":"us-east"}}'GET /api/v1/nodes — List all nodes.
curl http://localhost:8080/api/v1/nodesGET /api/v1/nodes/{id} — Get a node by ID or hostname.
curl http://localhost:8080/api/v1/nodes/worker-1DELETE /api/v1/nodes/{id} — Remove a node.
curl -X DELETE http://localhost:8080/api/v1/nodes/worker-1POST /api/v1/nodes/{id}/drain — Drain a node (mark as draining).
curl -X POST http://localhost:8080/api/v1/nodes/worker-1/drainPATCH /api/v1/projects/{id}/apps/{name} — Update app fields including hostname and available.
curl -X PATCH http://localhost:8080/api/v1/projects/myapp/apps/web \
-d '{"hostname":"www","available":true}'