Deploy Velociraptor on a RamNode VPS
A production-grade open-source DFIR and endpoint visibility server in under an hour — Go-based frontend, Let's Encrypt-fronted GUI, signed client packages, and a defensible baseline.
At a Glance
| Project | Velociraptor 0.76.5 |
| License | AGPL v3 |
| Recommended Plan | RamNode Cloud VPS 4 GB / 80 GB NVMe |
| OS | Ubuntu 24.04 LTS |
| Frontend Port | 443 (clients + GUI) |
| Estimated Setup Time | 45–60 minutes |
Sizing Cheat Sheet
- Lab / IR scratch: ~25 endpoints — 2 GB RAM, 50 GB NVMe
- SMB / MSP client: 25–150 — 4 GB, 80–160 GB NVMe
- Mid-fleet continuous monitoring: 150–750 — 8 GB, 320 GB+ NVMe
- Heavy hunting / long retention: 750+ — 16 GB+, 500 GB+ NVMe
Double storage if continuous client event monitoring is enabled — process-creation streams can consume 50 GB/month for a few hundred Windows endpoints.
Patch & Baseline Hardening
apt update && apt full-upgrade -y
apt install -y unattended-upgrades chrony fail2ban ufw curl wget gnupg
dpkg-reconfigure -plow unattended-upgradesConfirm chrony is syncing time — clock skew between server and clients produces baffling enrollment failures.
adduser veloadmin
usermod -aG sudo veloadmin
mkdir -p /home/veloadmin/.ssh
# paste public key into authorized_keys
chmod 700 /home/veloadmin/.ssh
chmod 600 /home/veloadmin/.ssh/authorized_keys
chown -R veloadmin:veloadmin /home/veloadmin/.sshIn /etc/ssh/sshd_config: PermitRootLogin no, PasswordAuthentication no, PubkeyAuthentication yes. Restart sshd and verify the veloadmin login from a second terminal before closing root.
Firewall & Swap
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw enableLock SSH to your static IP if you have one; otherwise lean on fail2ban. Add a swapfile on 2–4 GB plans so the OOM killer doesn't wake during heavy hunts:
fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab
sysctl -w vm.swappiness=10
echo 'vm.swappiness=10' >> /etc/sysctl.d/99-velociraptor.confDownload & Verify the Binary
Always check the downloads page for the latest patched build. 0.76.5 fixed CVE-2026-5329, 6290, 6863, and 6948.
cd ~
wget https://github.com/Velocidex/velociraptor/releases/download/v0.76/velociraptor-v0.76.5-linux-amd64
wget https://github.com/Velocidex/velociraptor/releases/download/v0.76/velociraptor-v0.76.5-linux-amd64.siggpg --keyserver keys.openpgp.org --recv-keys 0572F28B4EF19A043F4CBBE0B22A7FB19CB6CFA1
gpg --verify velociraptor-v0.76.5-linux-amd64.sig velociraptor-v0.76.5-linux-amd64
chmod +x velociraptor-v0.76.5-linux-amd64Generate the Server Configuration
./velociraptor-v0.76.5-linux-amd64 config generate -i- Datastore path: default
/opt/velociraptor(or a mounted block volume — moving later is painful) - Frontend FQDN: a real DNS record like
velo.yourdomain.com— clients verify cert hostname - Frontend port: 443 — punches through restrictive client networks
- GUI port: 8889 (bind to localhost & SSH-tunnel) or front via path routing on 443
- SSL: choose Let's Encrypt with a real email — autocert handles renewals
- PKI expiration: 10 years is sensible (rotation reissues every client cert)
Critical: back up server.config.yaml offline immediately. Lose it and every enrolled client is orphaned.
chmod 600 server.config.yaml client.config.yamlBuild & Install the Server .deb
./velociraptor-v0.76.5-linux-amd64 --config server.config.yaml debian server \
--binary velociraptor-v0.76.5-linux-amd64
sudo dpkg -i velociraptor_server_0.76.5_amd64.debThe package creates a velociraptor system user, installs the systemd unit, and starts velociraptor_server.service. Tail journalctl -u velociraptor_server.service -f while the autocert handler completes the Let's Encrypt challenge on port 80.
Create the First Admin User
sudo -u velociraptor velociraptor --config /etc/velociraptor/server.config.yaml \
user add yourname --role=administratorFor SOC analysts who shouldn't modify artifacts, use analyst or investigator roles. Visit https://velo.yourdomain.com; or for a localhost-bound GUI, tunnel with ssh -L 8889:127.0.0.1:8889 veloadmin@vps and browse to https://127.0.0.1:8889.
Build Client Packages
client.config.yaml contains the frontend URL, CA cert, and a unique nonce — anyone with it can enroll a client.
./velociraptor-v0.76.5-linux-amd64 --config client.config.yaml \
config repack --msi velociraptor-v0.76.5-windows-amd64.msi \
velociraptor_client.msi./velociraptor-v0.76.5-linux-amd64 --config client.config.yaml debian client \
--binary velociraptor-v0.76.5-linux-amd64./velociraptor-v0.76.5-linux-amd64 --config client.config.yaml rpm client \
--binary velociraptor-v0.76.5-linux-amd64Clients connect outbound on 443, register a unique client ID, and appear under the GUI's Clients tab.
Production Hardening
Lock down the GUI: restrict 443 by source IP at the firewall, or front it with nginx/Caddy + SSO (Authelia, Authentik). For more than two operators, configure SAML or OIDC in the authenticator block of server.config.yaml.
# /etc/systemd/system/velociraptor_server.service.d/override.conf
[Service]
MemoryMax=3G
LimitNOFILE=65536
TasksMax=4096sudo systemctl daemon-reload
sudo systemctl restart velociraptor_server.servicePatch promptly: subscribe to the GitHub release feed; treat Velociraptor patches like any other internet-facing security tool.
Backup Strategy
#!/bin/bash
set -euo pipefail
BACKUP_DIR=/var/backups/velociraptor
TS=$(date +%Y%m%d-%H%M%S)
mkdir -p "$BACKUP_DIR"
systemctl stop velociraptor_server.service
tar -C / -czf "$BACKUP_DIR/datastore-$TS.tar.gz" opt/velociraptor etc/velociraptor
systemctl start velociraptor_server.service
restic -r sftp:backupuser@backup.example.com:/backups/velo backup "$BACKUP_DIR/datastore-$TS.tar.gz"
find "$BACKUP_DIR" -name 'datastore-*.tar.gz' -mtime +7 -deleteserver.config.yaml rarely changes — back up once, store offline. The datastore changes constantly; nightly is enough for most deployments. Use LVM/ZFS snapshots if you can't afford the brief stop/start.
A First Hunt to Confirm Everything Works
- In the GUI, open Hunt Manager → New Hunt
- Pick a benign artifact:
Windows.System.Pslist,Linux.Sys.Pslist, orMacOS.System.Pslist - Schedule against "All Clients" or a label subset
- Launch and watch results stream in
If clients show connected but the hunt stalls, check server logs for permission errors against the datastore directory — that's almost always the cause.
Common Issues
- Clients flap: clock skew or stale CA in the client package — re-NTP and rebuild from current config
- Let's Encrypt fails: port 80 must be reachable for HTTP-01, even though traffic serves on 443
- Login: "user not found": users live in the configured authenticator — recreate after switching methods
- Disk fills fast: tune
Server.Monitoring.LogReduceror limit event monitoring artifacts
