VPS / Server Deployment

Deploy Vultrino on a VPS or dedicated server for team access and production use.

Prerequisites

  • Linux server (Ubuntu 22.04+ recommended)
  • Domain name (optional but recommended)
  • TLS certificate (Let's Encrypt)

Installation

# Download latest release
curl -L https://github.com/FeirAI/vultrino/releases/latest/download/vultrino-x86_64-unknown-linux-gnu.tar.gz | tar xz
sudo mv vultrino /usr/local/bin/

# Create vultrino user
sudo useradd -r -s /bin/false vultrino

# Create directories
sudo mkdir -p /etc/vultrino /var/lib/vultrino
sudo chown vultrino:vultrino /var/lib/vultrino

Configuration

Create /etc/vultrino/config.toml:

[server]
# `mode = "server"` enables the stricter server posture. `vultrino web` binds
# 127.0.0.1:7879 by default (the systemd unit below sets it explicitly with --bind).
mode = "server"

[storage]
backend = "file"

[storage.file]
path = "/var/lib/vultrino/credentials.enc"

[logging]
level = "info"   # parsed but not used (use RUST_LOG); there is no audit log file

[mcp]
enabled = true
transport = "stdio"

Systemd Services

Web UI Service

Create /etc/systemd/system/vultrino-web.service:

[Unit]
Description=Vultrino Web UI
After=network.target

[Service]
Type=simple
User=vultrino
Group=vultrino
Environment="VULTRINO_PASSWORD=your-secure-password"
Environment="VULTRINO_POLICY_HASH_SECRET=a-stable-random-secret"
Environment="VULTRINO_ADMIN_USERNAME=admin"
Environment="VULTRINO_ADMIN_PASSWORD_FILE=/etc/vultrino/admin-password"
ExecStart=/usr/local/bin/vultrino --config /etc/vultrino/config.toml web --bind 127.0.0.1:7879
Restart=always
RestartSec=5

# Security hardening
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/lib/vultrino
PrivateTmp=yes

[Install]
WantedBy=multi-user.target

The single vultrino web process serves the HTTP JSON API (/api/v1/…), the connector routes (/mcp, /llm), and the admin UI — there is no separate proxy service. (vultrino serve no longer starts an API server.)

Enable and start:

sudo systemctl daemon-reload
sudo systemctl enable vultrino-web
sudo systemctl start vultrino-web

Reverse Proxy Setup

Nginx

Install nginx and certbot:

sudo apt install nginx certbot python3-certbot-nginx

Create /etc/nginx/sites-available/vultrino:

server {
    listen 80;
    server_name vultrino.yourdomain.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name vultrino.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/vultrino.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/vultrino.yourdomain.com/privkey.pem;

    # Web UI + JSON API (both served by vultrino web on 7879)
    location / {
        proxy_pass http://127.0.0.1:7879;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Enable and get certificate:

sudo ln -s /etc/nginx/sites-available/vultrino /etc/nginx/sites-enabled/
sudo certbot --nginx -d vultrino.yourdomain.com
sudo systemctl reload nginx

Caddy (Alternative)

Create /etc/caddy/Caddyfile:

vultrino.yourdomain.com {
    reverse_proxy 127.0.0.1:7879
}

Firewall Configuration

# Allow only HTTPS
sudo ufw allow 443/tcp
sudo ufw allow 22/tcp  # SSH
sudo ufw enable

Initialize Credentials

# Set password
export VULTRINO_PASSWORD="your-secure-password"

# Add credentials (pass --config so the vault in /var/lib/vultrino is used)
sudo -u vultrino VULTRINO_PASSWORD="$VULTRINO_PASSWORD" vultrino --config /etc/vultrino/config.toml add --alias github-api --key ghp_xxx

There is no VULTRINO_CONFIG variable: every command needs --config /etc/vultrino/config.toml, or it uses the vultrino user's default config and vault paths instead. vultrino init always writes config.toml and admin.json to the invoking user's own config directory and ignores --config, so on this layout set the web UI login with VULTRINO_ADMIN_USERNAME and VULTRINO_ADMIN_PASSWORD_FILE in the unit, as above.

Security Checklist

  • Strong storage password (32+ characters)
  • Strong admin password
  • TLS enabled (HTTPS only)
  • Firewall configured
  • Event outbox retained outside Vultrino ([outbox] url push, or polling GET /api/v1/events); there is no audit log file
  • Regular backups of /var/lib/vultrino/
  • API keys have expiration dates
  • Roles use principle of least privilege

Monitoring

Check service status

sudo systemctl status vultrino-web

View logs

sudo journalctl -u vultrino-web -f

Health check

curl -s http://127.0.0.1:7879/login | head -1

Backup & Restore

The vault is a snapshot plus its write-ahead log (.enc and .wal in the same directory); both go into the backup together, and the services must be stopped while the backup is taken (a copy of a running vault can pair a snapshot with a log from a different moment). Restore both files from the same backup.

Backup with vultrino vault backup

With the service stopped (or at least no process holding the vault), copy the whole vault set consistently and have the copy checked. Pass --config so the commands use the vault in /var/lib/vultrino, and create the backup parent first so the vultrino user can write to it (the destination itself must not exist or must be empty):

sudo install -d -o vultrino -g vultrino -m 700 /var/backups/vultrino
sudo -u vultrino VULTRINO_PASSWORD="$VULTRINO_PASSWORD" vultrino --config /etc/vultrino/config.toml vault backup /var/backups/vultrino/$(date +%Y%m%d)

# Restore: stop vultrino-web first. `vault restore` does not detect a running service.
sudo systemctl stop vultrino-web
sudo -u vultrino VULTRINO_PASSWORD="$VULTRINO_PASSWORD" vultrino --config /etc/vultrino/config.toml vault restore /var/backups/vultrino/YYYYMMDD --force

backup takes the exclusive vault lock and writes a manifest with a SHA-256 per file; restore verifies every checksum and opens the copy before it touches the vault, refuses a backup that lacks the .wal, and moves the old files aside (*.pre-restore-*) when --force replaces them. Keep config.toml and the password with the backup; the vault is useless without them.

Restoring an older backup silently undoes every kill, revocation and approval made after it, and the tool cannot detect that. Before starting the service again, re-apply the kills and revocations made after the backup time and check Govder's kill state. backup refuses while <vault>.restore-pending exists (an earlier restore did not finish): re-run the restore from a known-good backup first.

Backup by hand

sudo systemctl stop vultrino-web
sudo tar -czf vultrino-backup-$(date +%Y%m%d).tar.gz \
    /etc/vultrino \
    /var/lib/vultrino
sudo systemctl start vultrino-web

Restore

sudo systemctl stop vultrino-web
sudo tar -xzf vultrino-backup-YYYYMMDD.tar.gz -C /
sudo systemctl restart vultrino-web