← back to blog

Setup guide: How to set up a fresh Linux VM per sybil wallet

Setup guide: How to set up a fresh Linux VM per sybil wallet

Running multiple wallets on the same machine is one of the fastest ways to get flagged and slashed on any protocol that runs sybil detection. Shared IP, shared MAC address, shared browser fingerprint, same disk-level artifacts, same timezone and locale. Projects like Hop Protocol, LayerZero, and Optimism have all done retroactive sybil sweeps, and the common thread is always the same: wallets that share infrastructure get treated as one entity regardless of how many seed phrases you generated.

The cleanest solution i’ve found, after running this operation since 2022, is one Linux VM per wallet. Not one browser profile, not one antidetect tab, one full virtual machine with its own network interface, its own hostname, its own machine ID, and its own proxy exit node. it costs more in compute and takes longer to set up correctly, but the isolation is categorically stronger than anything a browser-level tool can provide.

this guide is for operators who are already comfortable with the Linux command line and want a repeatable, auditable setup. by the end you’ll have a working template VM you can clone for each new wallet, with a clear checklist for what to randomize on each clone. i run this on a dedicated bare-metal server in a Singapore datacenter but the approach works on any hypervisor-capable machine.


what you need

hardware / hosting - a bare-metal server or VPS with KVM virtualization support, at minimum 4 cores and 16 GB RAM (supports roughly 8-10 lightweight VMs comfortably) - recommended: Hetzner AX41 dedicated (about €40/month as of May 2026) or equivalent OVH bare metal - Ubuntu Server 22.04 LTS on the host

software - Proxmox VE 8.x as the hypervisor, free community edition is fine - cloud-init for VM templating - qemu-guest-agent for clean snapshots - a proxy provider with per-IP residential or mobile proxies, one IP per VM

accounts / credentials - one wallet seed phrase per VM, generated offline or on an air-gapped device - one proxy credential per VM (i use Oxylabs residential, roughly $3-5 per dedicated residential IP/month)

costs (rough) - bare metal server: $40-80/month - proxies: $3-5/IP/month, so $30-50/month for 10 wallets - time: about 45 minutes to build the template, then ~5 minutes per clone


step by step

step 1: install Proxmox on the host

if you’re starting from a fresh Hetzner or OVH bare metal, download the Proxmox VE ISO and install it via the provider’s KVM-over-IP console. follow the installer, point it at your primary disk, set a static IP on the management interface.

after install, access the web UI at https://your-server-ip:8006. log in as root.

if it breaks: if you get a “no valid subscription” nag on login, it’s cosmetic. for the community apt repository run:

sed -i 's|enterprise.proxmox.com|download.proxmox.com/debian|g' /etc/apt/sources.list.d/pve-enterprise.list

step 2: download and prepare the Ubuntu cloud image

Ubuntu publishes minimal cloud images that boot in under 10 seconds and are designed to be cloned with cloud-init. on the Proxmox host shell:

wget https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img
qm create 9000 --name ubuntu-template --memory 1024 --cores 1 --net0 virtio,bridge=vmbr0
qm importdisk 9000 jammy-server-cloudimg-amd64.img local-lvm
qm set 9000 --scsihw virtio-scsi-pci --scsi0 local-lvm:vm-9000-disk-0
qm set 9000 --boot c --bootdisk scsi0
qm set 9000 --ide2 local-lvm:cloudinit
qm set 9000 --serial0 socket --vga serial0
qm set 9000 --agent enabled=1

if it breaks: if importdisk complains about disk format, append --format qcow2 to the import command.

step 3: configure the base template

before converting to a template, harden the base image. start the VM temporarily, log in via the Proxmox console, then run:

# disable cloud-init after first boot (we'll re-enable per clone)
sudo systemctl disable cloud-init

# remove machine-id so it regenerates on clone
sudo truncate -s 0 /etc/machine-id
sudo rm -f /var/lib/dbus/machine-id

# clear bash history
history -c && sudo truncate -s 0 /root/.bash_history

# install essentials
sudo apt update && sudo apt install -y qemu-guest-agent curl jq
sudo systemctl enable qemu-guest-agent

shut down the VM. now convert it to a template:

qm template 9000

if it breaks: if the template conversion says the VM is running, do qm stop 9000 first.

step 4: clone and individualize each wallet VM

for each new wallet, clone from the template and then immediately randomize the identifiers that sybil detectors look for. replace 101 with your VM ID and wallet01 with your naming scheme:

qm clone 9000 101 --name wallet01 --full true

now boot VM 101 and run the individualization script:

#!/bin/bash
# run this INSIDE the cloned VM on first boot

NEW_HOSTNAME="vm-$(cat /dev/urandom | tr -dc 'a-z0-9' | head -c 8)"
hostnamectl set-hostname "$NEW_HOSTNAME"

# regenerate machine-id
systemd-machine-id-setup

# randomize MAC at the OS level (Proxmox sets the virtual MAC; change the reported one if needed)
NEW_MAC=$(printf '%02x:%02x:%02x:%02x:%02x:%02x' \
  $((RANDOM % 256)) $((RANDOM % 256)) $((RANDOM % 256)) \
  $((RANDOM % 256)) $((RANDOM % 256)) $((RANDOM % 256)))
echo "new hostname: $NEW_HOSTNAME"
echo "new MAC: $NEW_MAC"

also set a unique MAC address at the Proxmox level before first boot:

qm set 101 --net0 virtio,bridge=vmbr0,macaddr=AA:BB:CC:DD:EE:FF

replace AA:BB:CC:DD:EE:FF with a randomly generated value. you can use python3 -c "import uuid; print(':'.join(['%02x'%b for b in uuid.uuid4().bytes[:6]]))".

if it breaks: if systemd-machine-id-setup says the machine-id already exists, delete /etc/machine-id and /var/lib/dbus/machine-id first, then re-run.

step 5: assign a dedicated proxy to each VM

each VM should route all traffic through a unique residential or mobile proxy IP. i configure this at the VM’s network level using redsocks to transparently proxy all TCP traffic, so even CLI tools and scripts don’t need individual proxy settings.

sudo apt install -y redsocks

edit /etc/redsocks.conf:

base {
    log_debug = off;
    log_info = on;
    log = "syslog:daemon";
    daemon = on;
    redirector = iptables;
}

redsocks {
    local_ip = 127.0.0.1;
    local_port = 12345;
    ip = YOUR_PROXY_IP;
    port = YOUR_PROXY_PORT;
    type = socks5;
    login = "YOUR_USER";
    password = "YOUR_PASS";
}

then add iptables rules to redirect outbound traffic:

sudo iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-ports 12345
sudo iptables -t nat -A OUTPUT -p tcp --dport 443 -j REDIRECT --to-ports 12345
sudo iptables-save > /etc/iptables/rules.v4

verify with curl https://api.ipify.org , it should return your proxy IP, not your server IP.

if it breaks: if iptables rules aren’t persisting across reboots, install iptables-persistent with sudo apt install iptables-persistent.

step 6: install your wallet tooling

for EVM chains i install the wallet CLI directly rather than a browser where possible. for protocols that require a browser, i install a minimal Chromium instance inside the VM and control it headlessly via Playwright or Puppeteer. the multiaccountops.com/blog/ has good writeups on browser automation inside VMs if you need that layer.

for a CLI-first EVM setup:

# install foundry (cast, anvil, forge)
curl -L https://foundry.paradigm.xyz | bash
source ~/.bashrc && foundryup

verify:

cast wallet address --private-key YOUR_PRIVATE_KEY

if it breaks: if foundryup fails with a TLS error, your proxy config may be blocking the install CDN. temporarily disable the iptables redirect rules, install, then re-enable.

step 7: snapshot the clean state

once the VM is individualized, proxied, and tooling is installed, take a snapshot before doing any on-chain activity. this is your recovery point if you need to rebuild.

qm snapshot 101 clean-state --description "fresh wallet, proxy configured, no txns"

you can roll back to this snapshot at any time with qm rollback 101 clean-state.


common pitfalls

reusing the template’s machine-id. this is the most common mistake. if you clone without clearing /etc/machine-id, every clone has the same ID. some protocols and infrastructure tools fingerprint on this. always truncate before templating.

same exit IP on multiple VMs. assigning proxies at the application layer (like in MetaMask’s settings) doesn’t catch all traffic. configure the proxy at the OS level so every outbound connection, including DNS, goes through the right exit node. check with curl https://api.ipify.org from inside each VM before doing anything on-chain.

forgetting to randomize the Proxmox-level MAC. Proxmox auto-assigns MACs from a predictable range. if you clone 20 VMs without changing the MAC, they’ll have sequential MACs which is a weak signal but still detectable. set a random MAC before first boot as described in step 4.

doing airdrop activity across VMs from the same timing pattern. even with perfect isolation, if all your wallets transact at identical times (because you run a script at 9am every day), that’s a behavioral cluster. stagger activity windows. this is covered in more depth at /blog/wallet-activity-timing-guide/.

not testing proxy leaks. use a DNS leak test (curl https://dnsleak.com/api/) and WebRTC leak checks if you’re running a browser inside the VM. a proxy that passes HTTP traffic but leaks DNS is nearly as bad as no proxy. see /blog/proxy-leak-testing-for-airdrop-wallets/ for a dedicated checklist.


scaling this

10 wallets. manual clone, individualize, and snapshot each one. takes about an hour total. manage with a simple spreadsheet: VM ID, wallet address, proxy IP, last activity date.

100 wallets. manual is no longer viable. write a bash script that loops through a CSV of proxy credentials and wallet configs and calls qm clone, qm set (for MAC), and your individualization script via qm guest exec. Proxmox’s cloud-init support can inject per-VM userdata automatically, so you can bake the hostname randomization and redsocks config into a cloud-init template. provisioning 100 VMs this way takes about 20 minutes unattended.

1000 wallets. you’ve outgrown a single bare-metal machine. at this scale you need a cluster. Proxmox supports multi-node clustering natively. pair it with Terraform’s Proxmox provider for infrastructure-as-code, and Ansible for post-clone configuration. your proxy bill alone at $3-5/IP will be $3,000-5,000/month, so the ROI math needs to work before you go there. for antidetect browser approaches at this scale (which some operators prefer over VMs), antidetectreview.org/blog/ has comparisons of tools that offer API-level account management.


where to go next


Written by Xavier Fok

disclosure: this article may contain affiliate links. if you buy through them we may earn a commission at no extra cost to you. verdicts are independent of payouts. last reviewed by Xavier Fok on 2026-05-19.

need infra for this today?