Back to Agents

Self-Hosting Autonomous Agents on Ubuntu: Headless Browser Pools, Xvfb, and VPS Isolation

Self-Hosting Autonomous Agents on Ubuntu: Headless Browser Pools, Xvfb, and VPS Isolation
Image credit: labs.zeroshot.studio

Contents

Why self-host autonomous agents on a dedicated VPS?

Running autonomous agents on local development laptops causes frequent interruptions when your machine sleeps, changes Wi-Fi networks, or runs out of RAM.

Deploying agents to a dedicated Ubuntu VPS (such as a 4-core, 8GB RAM Hetzner or DigitalOcean instance) provides:

  1. Continuous Execution: Cron jobs and scheduled signal collectors run 24/7 without downtime.
  2. Fixed Static IP: Reliable access for webhooks, SSH tunnels, and API endpoints.
  3. Environment Isolation: Agent shell commands run inside a dedicated sandbox rather than on your primary workstation.
Flowchart
6 linescompact
flowchart TD
    A[System Cron / Webhook Trigger] --> B[systemd Supervisor Service]
    B --> C[Agent Core Runtime]
    C --> D[Xvfb Virtual Display :99]
    D --> E[Headless Chromium CDP Instance]
    C --> F[(Local SQLite / Postgres Store)]
Rendered from Mermaid source with the native ZeroLabs diagram container.

How do you configure Xvfb and headless Chromium on Ubuntu?

Many web scraping and browser navigation tools fail on headless Linux servers because no graphical display is available. Xvfb (X Virtual Framebuffer) emulates a monitor entirely in system memory.

Install required dependencies on Ubuntu 24.04:

Terminalbash
sudo apt-get update && sudo apt-get install -y \    xvfb \    chromium-browser \    libnss3 \    libxss1 \    libasound2t64 \    fonts-liberation

Start the virtual display buffer and verify Chromium can render pages:

Terminalbash
# Launch Xvfb on display :99 with standard 1920x1080 resolutionXvfb :99 -screen 0 1920x1080x24 -ac &export DISPLAY=:99# Test headless browser navigationchromium-browser --no-sandbox --disable-dev-shm-usage --dump-dom https://example.com

How do you supervise agent processes with systemd?

To ensure your agent recovers automatically from crashes or server reboots, create a dedicated systemd service:

text
# /etc/systemd/system/agent-worker.service[Unit]Description=ZeroLabs Autonomous Agent WorkerAfter=network.target[Service]Type=simpleUser=zeroshotWorkingDirectory=/home/zeroshot/.openclaw/workspaceEnvironment=DISPLAY=:99Environment=NODE_ENV=productionExecStart=/usr/bin/python3 /home/zeroshot/.openclaw/workspace/scripts/zerostate-content-team/auto_publisher.py --scheduledRestart=on-failureRestartSec=10StandardOutput=append:/home/zeroshot/zero-signals/auto-publisher.logStandardError=append:/home/zeroshot/zero-signals/auto-publisher.log[Install]WantedBy=multi-user.target

Enable and start the service:

Terminalbash
sudo systemctl daemon-reloadsudo systemctl enable agent-worker.servicesudo systemctl start agent-worker.service

How do you prevent memory leaks and zombie browser processes?

Headless browser automation frequently leaves orphaned Chrome subprocesses that consume system RAM over time.

Implement an automated cleanup script and schedule it in crontab every 15 minutes:

python
#!/usr/bin/env python3# scripts/browser/close_chrome_if_idle.pyimport subprocessimport psutilimport timedef cleanup_orphaned_browsers():    for proc in psutil.process_iter(['pid', 'name', 'create_time']):        try:            if 'chrome' in proc.info['name'].lower() or 'chromium' in proc.info['name'].lower():                # Terminate browser processes running longer than 15 minutes                if time.time() - proc.info['create_time'] > 900:                    print(f'Terminating stale browser PID: {proc.info["pid"]}')                    proc.terminate()        except (psutil.NoSuchProcess, psutil.AccessDenied):            passif __name__ == '__main__':    cleanup_orphaned_browsers()

Add the cleanup check to crontab:

text
*/15 * * * * /usr/bin/python3 /home/zeroshot/.openclaw/workspace/scripts/browser/close_chrome_if_idle.py >/dev/null 2>&1

FAQ

How much RAM is needed to self-host browser-based agents?

A minimum of 4GB RAM is recommended for single-agent workloads. For running multiple concurrent headless Chrome sessions, provision at least 8GB RAM with swap enabled.

Why is the --no-sandbox flag required for Chromium on Linux VPS?

When running Chromium under non-root service accounts on minimal Linux distributions, standard Linux namespaces may be restricted. The --no-sandbox flag enables execution within your secured VPS perimeter.

How do I view what the headless browser is doing for debugging?

You can use x11vnc to attach a VNC server to the Xvfb display :99, allowing you to connect with a standard VNC client and watch agent navigation in real time.

Share