Skip to main content
Deploy Python Agents to DigitalOcean

Deploy Python Agents to DigitalOcean

Deploy Python Agents to DigitalOcean
Chudi Nnorukam Mar 17, 2026 10 min read

Run a Python agent on a $6 Droplet for months. Full setup, gotchas, and why serverless doesn't work for async bots.

Why this matters

I ran my Polymarket trading bot on a DigitalOcean Droplet ($6/month) for 4 months before migrating to a specialized VPS for sub-10ms latency. For most Python agents: Droplets give you 24/7 uptime, full root access, and predictable costs. Here's the complete setup.

Disclosure: This post contains affiliate links to DigitalOcean. If you sign up through these links, I earn a commission at no extra cost to you, and you get $200 in free credits for 60 days. I ran my trading bot on a DigitalOcean Droplet before migrating to a specialized VPS for lower latency. I recommend DO for Python agents because I used it and it worked.


My Python trading bot worked perfectly on my laptop. Asyncio event loop, WebSocket connections to Binance, real-time order placement on Polymarket. Clean code. Passed review. Ran great locally.

Then I tried to deploy it.

The first attempt was AWS Lambda. Cold starts added 400ms to every signal. The 15-minute timeout killed my long-running WebSocket connections. I spent two days fighting CloudWatch logs before I realized: Lambda was built for HTTP request handlers, not for a process that needs to stay alive.

Here’s what I wish someone had told me: deploying a Python agent that runs 24/7 costs $6/month and takes 30 minutes. Not $50. Not $80. Six dollars.

I ran my Polymarket trading bot on a $6 DigitalOcean Droplet for months. It processed live Binance price feeds, placed orders on the CLOB, and managed exits autonomously. 69.6% win rate across 23 clean trades. The infrastructure never failed me. The server was not the bottleneck. It never was.

This is the setup guide that would have saved me those two days on Lambda.

What does a Python agent actually need?

Most developers pick their deployment platform based on what they already know. If you’ve used AWS before, you reach for EC2 or Lambda. If you’re a Heroku person, you spin up a dyno. Nobody stops to ask: what are the actual infrastructure requirements?

A long-running Python agent requires:

  • A process that stays alive (not a function that runs and dies)
  • Persistent connections (WebSocket feeds, database connections)
  • Predictable cost (not pay-per-invocation that spikes when your bot gets active)
  • Full control over the runtime (Python version, system packages, cron)

Here’s what it does not need:

  • Auto-scaling (your bot is one process)
  • Load balancers (it’s not serving HTTP traffic)
  • Managed runtimes (you want control, not guardrails)
  • A $50/month bill for resources you’ll never use

That last point stings. If you’re running a single Python agent on Heroku ($7-25/mo), Railway ($5 + metered usage), or an EC2 instance you forgot to right-size ($15-80/mo depending on how lost you got in the AWS console), you’re paying for infrastructure designed for problems you don’t have.

How do DigitalOcean costs compare to AWS, Heroku, and Railway?

I evaluated four providers before my first deploy. Here’s the honest comparison:

ProviderMonthly CostBest ForThe Catch
AWS EC2$8-80/moYou already live in AWSConsole is a maze. Surprise bills are real. A t3.micro costs $8, but you’ll add EBS, bandwidth, and by month 3 you’re at $35 wondering what happened.
Heroku$7-25/moQuick web app deploysDynos sleep on the free tier. Paid tier starts at $7 but a worker dyno for a bot is $25. No SSH access. Limited debugging.
Railway$5 + usageGit-push simplicityUsage-based pricing sounds cheap until your bot runs 24/7. A busy month can cost $20-40.
DigitalOcean$6/mo flatBots, agents, anything that runs 24/7Fewer regions than AWS. You manage your own server. That’s it.

I picked DigitalOcean. $6/month flat. No metered surprises. Full root access. The documentation read like it was written by someone who actually uses the product. I went from zero to running bot in 28 minutes.

Here’s what that $6 gets you: 1 vCPU, 1GB RAM, 25GB SSD, 1TB transfer. My trading bot (asyncio event loop, multiple WebSocket connections, real-time order placement) used about 200MB of that RAM. The CPU barely touched 5% between trading signals.

Most of you are overpaying. Let me show you the setup.

What do you need before starting?

You need three things: Python 3.10 or higher on your local machine, an SSH key pair (generate one with ssh-keygen -t ed25519 if you don’t have one), and 30 minutes of uninterrupted time.

That’s literally all the prerequisites.

Step 1: Create a Droplet (2 Minutes)

Log into DigitalOcean and create a new Droplet:

  • Region: Pick the closest to your data source. For my trading bot, I chose Amsterdam (5-12ms to Polymarket’s CLOB in London). For a general agent, pick the region nearest whatever API you call most.
  • Image: Ubuntu 24.04 LTS
  • Size: Basic, Regular, $6/month (1 vCPU, 1GB RAM, 25GB SSD)
  • Authentication: SSH Key (paste your public key from ~/.ssh/id_ed25519.pub)

The Droplet spins up in about 60 seconds. Grab the IP address from the dashboard. Test your connection:

ssh root@YOUR_DROPLET_IP

That root prompt means you have a server. Running. Waiting for your code. For $6/month, you now own a machine that will run 24/7 whether or not you’re watching.

Step 2: Lock It Down (10 Minutes)

I skipped this step the first time. A week later, I checked the auth log and found 3,000 brute-force SSH attempts from IPs I’d never seen. Nothing was compromised (SSH keys are strong), but it was a wake-up call.

Ten minutes of security setup prevents real problems:

# Create a deploy user (never run your bot as root)
adduser --disabled-password agent
usermod -aG sudo agent

# Copy your SSH key to the new user
mkdir -p /home/agent/.ssh
cp /root/.ssh/authorized_keys /home/agent/.ssh/
chown -R agent:agent /home/agent/.ssh
chmod 700 /home/agent/.ssh
chmod 600 /home/agent/.ssh/authorized_keys

# Disable root login and password auth
sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
systemctl restart sshd

# Enable the firewall
ufw allow OpenSSH
ufw --force enable

Log out. Reconnect as the agent user:

ssh agent@YOUR_DROPLET_IP

You now have a locked-down server. Root login disabled, password auth disabled, firewall active. This is what separates a production server from a tutorial project.

Step 3: Set Up Python (3 Minutes)

Ubuntu 24.04 ships with Python 3.12. Set up a virtual environment:

sudo apt update && sudo apt install -y python3-venv python3-pip

mkdir -p ~/my-agent
cd ~/my-agent

python3 -m venv venv
source venv/bin/activate

pip install aiohttp websockets python-dotenv

Step 4: Deploy Your Agent (5 Minutes)

Here’s a production-ready async agent skeleton. This is the same pattern my trading bot used. Replace the inner logic with whatever your agent does:

# ~/my-agent/agent.py
import asyncio
import signal
import logging
from datetime import datetime

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s",
    handlers=[
        logging.FileHandler("agent.log"),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)

shutdown_event = asyncio.Event()

def handle_signal(sig, frame):
    logger.info(f"Received signal {sig}, shutting down gracefully...")
    shutdown_event.set()

async def process_tick(data: dict):
    """Your agent logic goes here."""
    logger.info(f"Processing: {data}")

async def run_agent():
    """Main agent loop. Replace with your real logic."""
    logger.info("Agent started")

    cycle = 0
    while not shutdown_event.is_set():
        try:
            await process_tick({"cycle": cycle, "ts": datetime.utcnow().isoformat()})
            cycle += 1
            await asyncio.sleep(10)

        except Exception as e:
            logger.error(f"Agent error: {e}")
            await asyncio.sleep(5)

    logger.info("Agent stopped cleanly")

def main():
    signal.signal(signal.SIGTERM, handle_signal)
    signal.signal(signal.SIGINT, handle_signal)
    asyncio.run(run_agent())

if __name__ == "__main__":
    main()

Create a .env file for configuration:

# ~/my-agent/.env
API_KEY=your_api_key_here
POLL_INTERVAL=10
LOG_LEVEL=INFO

Test it on the Droplet:

cd ~/my-agent
source venv/bin/activate
python3 agent.py

You should see log output. Press Ctrl+C to stop. If it runs for 30 seconds clean, you’re ready for the part most tutorials skip.

How do you keep a Python agent running 24/7 on a Droplet?

Use systemd. This is the critical step separating “I deployed my bot” from “my bot runs in production.”

Running your agent in screen or tmux kills it when SSH disconnects, server reboots, or when your code crashes at 3am with nobody watching. I lost 6 hours of trading signals before learning about systemd.

systemd handles three essential tasks:

  1. Automatically restarts your agent if it crashes
  2. Starts it on server reboot without manual intervention
  3. Manages logs for debugging and audit trails

Create a service file:

sudo tee /etc/systemd/system/my-agent.service << 'EOF'
[Unit]
Description=My Python Agent
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=agent
WorkingDirectory=/home/agent/my-agent
Environment=PATH=/home/agent/my-agent/venv/bin:/usr/bin
EnvironmentFile=/home/agent/my-agent/.env
ExecStart=/home/agent/my-agent/venv/bin/python3 agent.py
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
EOF

Enable and start:

sudo systemctl daemon-reload
sudo systemctl enable my-agent
sudo systemctl start my-agent

Check it:

sudo systemctl status my-agent

active (running). Your agent now survives reboots, crashes, and SSH disconnects. Close your laptop. Go to sleep. It keeps running.

Step 6: What are the common mistakes after deployment?

I hit all of these. You’ll hit at least two.

1. “ModuleNotFoundError” after deploy

systemd runs its own environment. If ExecStart points to python3 instead of /home/agent/my-agent/venv/bin/python3, it uses the system Python which doesn’t have your packages. Exact path. Every time.

2. Agent dies silently after 6 hours

An unhandled exception in the main loop. Without the try/except wrapper, the agent crashes, systemd restarts it, it crashes again on the same data, and you hit the restart rate limit. The backoff sleep is not optional.

3. Disk fills up from logs

journalctl handles systemd logs, but your agent.log file grows without bounds. I discovered this after a 2GB log file ate my 25GB disk. Add log rotation:

sudo tee /etc/logrotate.d/my-agent << 'EOF'
/home/agent/my-agent/agent.log {
    daily
    rotate 7
    compress
    missingok
    notifempty
}
EOF

4. SSH disconnect kills the agent

Only happens if you started with python3 agent.py & in a shell session. systemd doesn’t have this problem. If you’re still running bots in tmux: stop. Use systemd.

How do you deploy code changes to your running agent?

When you update your agent code:

# From your local machine
scp agent.py agent@YOUR_DROPLET_IP:~/my-agent/

# Restart the service
ssh agent@YOUR_DROPLET_IP "sudo systemctl restart my-agent"

# Verify clean start
ssh agent@YOUR_DROPLET_IP "sudo journalctl -u my-agent -n 10 --no-pager"

Three commands. Under 10 seconds. I started with scp and switched to git-based deploys after the third time I forgot to push a dependency file. For a single agent, scp is fine.

What should you verify before going live?

Before you trust your agent with real work or money:

  • SSH key auth only (password auth disabled)
  • Firewall active (ufw status shows SSH allowed, everything else denied)
  • Non-root user running the agent
  • systemd service with Restart=always
  • Error handling in the main loop (catch, log, backoff, continue)
  • Signal handlers for SIGTERM/SIGINT
  • Log rotation configured
  • Monitoring (check logs daily until stable)

If your agent handles money, also add: position limits, stop-losses, health check endpoints, and alert notifications. I documented the full trading bot architecture, risk management, and signal detection patterns in my Polymarket trading bot guide.

When do you outgrow a $6 Droplet?

I migrated away from DigitalOcean when my trading strategy demanded sub-10ms round-trip latency to Polymarket’s CLOB. The Amsterdam region provided 5-12ms, which worked for my initial strategy. When I needed 3-5ms consistency, I switched to a specialized VPS provider colocated near the exchange.

That migration took 4 months. It only mattered because I was doing latency arbitrage where 100ms cost me money.

For most Python agents, you will not outgrow a $6 Droplet for years.

You’ll know it’s time to upgrade when:

  • Milliseconds matter: Your agent’s profitability depends on execution speed
  • Multiple agents: You’re running 4+ processes and hitting CPU/RAM limits
  • GPU inference: Your agent runs ML models that need a GPU
  • Compliance: You need certifications or regions DO doesn’t offer

Until then, every month you spend more than $6 on infrastructure for a single Python agent is money you didn’t need to spend.

Start Here

If you’ve been running your bot on Lambda hitting execution timeouts, paying $25/month for a Heroku worker dyno, or avoiding deployment because AWS console complexity paralyzes you:

  1. Sign up for DigitalOcean (claim $200 in free credits for 60 days, enough to test this entire setup cost-free)
  2. Follow the 6-step process above (30 minutes total, no dependencies)
  3. Replace the example agent skeleton with your actual logic
  4. Run through the production checklist and monitor for 48 hours

Result: $6/month. 30 minutes setup time. Your agent running 24/7 on infrastructure you control completely.

For trading bot builders: Start with my guide on building a Polymarket trading bot to understand signal detection, order placement, risk management, and profitability metrics. Then return here for the deployment infrastructure. My bot achieved 69.6% win rate on this exact setup before migrating for latency reasons.

For general AI agents: This Droplet setup works equally well for data crawlers, scheduled scrapers, webhook processors, LLM orchestration systems, and autonomous agents. The pattern applies to any Python process that needs 24/7 uptime without paying cloud premium prices.

What are you deploying? I’m curious what agents people are running on VPS these days.

Chudi Nnorukam

Written by Chudi Nnorukam

I build chudi.dev as a live public experiment in AI-visible web architecture: a website designed for human readers, LLM retrieval, and agent interoperability. My work spans WebMCP interfaces, machine-readable identity, technical writing, and the systems that make public knowledge legible to search and AI.

FAQ

What does a $6 DigitalOcean Droplet run?

1 vCPU, 1GB RAM, 25GB SSD storage. My trading bot used ~200MB RAM with active WebSocket connections. Enough for most Python agents until you need multiple concurrent processes or GPU inference.

Why not use App Platform or Heroku instead?

App Platform is managed PaaS for HTTP web apps. Agents that maintain persistent WebSocket connections, run event loops, or need custom process control require a Droplet where you control the full lifecycle. Heroku worker dynos cost $25/month for the same capability.

What latency does DigitalOcean Amsterdam region provide?

5-12ms round-trip to London (Polymarket CLOB location). US East gives 130-150ms. That 120ms difference is critical for latency-sensitive strategies like arbitrage.

Can I run a trading bot on DigitalOcean?

Yes. I placed real trades with 69.6% win rate on a Droplet. Works for strategies where sub-50ms latency is acceptable. I migrated to a specialized VPS only when my strategy required sub-10ms execution consistency.

Why does Lambda fail for Python agents?

Lambda cold starts add 100-500ms latency, enforce 15-minute execution limits, and disconnect WebSocket connections at function timeout. Agents need persistent connections that stay open. Lambda doesn't support that model.

Sources & Further Reading

Sources

Further Reading

Discussion

Comments powered by GitHub Discussions coming soon.