# Deployment ## Node Agent Run this on every Incus host: ```bash cd /opt/incus-backup-ui/backend cp .env.example .env npm install sudo npm start ``` Important `.env` values: ```env HOST="0.0.0.0" PORT=3000 API_TOKEN="long-random-token-at-least-32-characters" HTTPS_ENABLED=true TLS_CERT_FILE="/etc/incus-backup-agent/tls.crt" TLS_KEY_FILE="/etc/incus-backup-agent/tls.key" ALLOWED_MANAGEMENT_IPS="management-server-ip" ``` `API_TOKEN` is required and must be at least 32 characters long. If `ALLOWED_MANAGEMENT_IPS` is set, the agent only accepts requests from those comma-separated IP addresses. For private networks such as NetBird, the agent can serve HTTPS directly with an internal CA. Create one CA and sign one certificate per agent. The certificate must contain the NetBird IP or internal DNS name as a SAN: ```bash sudo install -d -m 700 /etc/incus-backup-agent openssl genrsa -out agent-ca.key 4096 openssl req -x509 -new -nodes -key agent-ca.key -sha256 -days 3650 -out agent-ca.crt -subj "/CN=Incus Backup Agent CA" openssl genrsa -out tls.key 4096 openssl req -new -key tls.key -out tls.csr -subj "/CN=incus-node-1" printf "subjectAltName=IP:100.127.0.10,DNS:incus-node-1.netbird\n" > tls.ext openssl x509 -req -in tls.csr -CA agent-ca.crt -CAkey agent-ca.key -CAcreateserial -out tls.crt -days 825 -sha256 -extfile tls.ext sudo install -m 600 tls.key /etc/incus-backup-agent/tls.key sudo install -m 644 tls.crt /etc/incus-backup-agent/tls.crt ``` Copy `agent-ca.crt` to the management server and set `AGENT_CA_FILE` there. Install systemd service: ```bash sudo cp deploy/systemd/incus-backup-agent.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable --now incus-backup-agent sudo journalctl -u incus-backup-agent -f ``` ## Management API Run this on the management server: ```bash cd /opt/incus-backup-ui/management cp .env.example .env npm install npm start ``` Important `.env` values: ```env PORT=3100 SESSION_SECRET="long-random-secret" AUTH_USERNAME="admin" AUTH_PASSWORD="initial-password" DATABASE_PATH="./management.sqlite" CORS_ORIGINS="https://backup.example.com" SESSION_COOKIE_SECURE=true ALLOW_INSECURE_AGENT_HTTP=false AGENT_CA_FILE="/etc/incus-backup-management/agent-ca.crt" ``` `AUTH_PASSWORD` is required for the first start when the user database is empty. `CORS_ORIGINS` must list the frontend origins that are allowed to use cookie-authenticated API calls. Agent URLs must use `https://`; only set `ALLOW_INSECURE_AGENT_HTTP=true` for local development. `AGENT_CA_FILE` should point to the CA certificate that signed the internal agent certificates. Reset an existing password: ```bash npm run reset-password -- admin "new-password" ``` Install systemd service: ```bash sudo useradd --system --home /opt/incus-backup-ui --shell /usr/sbin/nologin incus-backup sudo chown -R incus-backup:incus-backup /opt/incus-backup-ui/management sudo cp deploy/systemd/incus-backup-management.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable --now incus-backup-management sudo journalctl -u incus-backup-management -f ``` ## Frontend Point the frontend at the management API: ```bash cd /opt/incus-backup-ui/frontend npm install VITE_API_URL=http://management-server:3100/api npm run build npm run preview -- --host 0.0.0.0 ``` For production, put the frontend and management API behind HTTPS.