Skip to content
Sistemo
GitHub Docs Install

Port Expose

Forward host ports to machines so services inside a machine are accessible from the host or your network.

Expose at deploy time

# host:80 → machine:80
sistemo machine deploy debian --name web --expose 80
# or: sistemo vm deploy debian --name web --expose 80

# host:8080 → machine:3000
sistemo machine deploy myapp --expose 8080:3000

# Multiple ports
sistemo machine deploy myapp --expose 80 --expose 443 --expose 8080:3000

Expose on a running machine

sistemo machine expose myvm --port 80
sistemo machine expose myvm --port 8080:80

Remove

sistemo machine unexpose myvm --port 8080

Check exposed ports

sistemo machine status myvm

Output:

ID:       af066de1-ff9d-4632-880d-a05afb4ed582
Name:     myvm
Status:   running
IP:       10.200.0.2
Ports:
  host:80 → machine:80 (tcp)
  host:8080 → machine:3000 (tcp)

Example: nginx

# Deploy with port 80 exposed
sistemo machine deploy debian --name web --expose 80

# Install and start nginx
sistemo machine exec web "DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y nginx"
sistemo machine exec web "rm -f /usr/sbin/policy-rc.d && systemctl start nginx"

# Access from your host
curl http://localhost:80

Tip

Some machine images have a policy-rc.d that prevents services from auto-starting during apt-get install. Remove it with rm -f /usr/sbin/policy-rc.d then start the service manually.

Example: Node.js app

sistemo machine deploy debian --name api --expose 3000

sistemo machine exec api "apt-get update && apt-get install -y nodejs"
sistemo machine exec api "node -e 'require(\"http\").createServer((q,s)=>{s.end(\"hello\\n\")}).listen(3000)' &"

curl http://localhost:3000
# hello

Direct machine access

Every machine has a unique IP on the bridge. You can also access services directly without port expose:

sistemo machine status web   # shows IP: 10.200.0.2
curl http://10.200.0.2:80

How it works

Port expose adds 3 nftables rules:

Rule Purpose
PREROUTING DNAT External traffic from other machines on your network
OUTPUT DNAT Localhost traffic (curl localhost:80)
FORWARD ACCEPT Allow traffic through (needed when Docker sets FORWARD policy to DROP)

Port rules are stored in SQLite and survive daemon restarts. On machine stop, nftables rules are removed but DB rows are kept so they can be restored on start. On machine delete, everything is cleaned up.

Limitations

  • TCP only (UDP not yet supported)
  • One machine per host port — first to claim wins
  • Privileged ports (< 1024) require the daemon to run as root (which it does by default)