
Deploy Python Agents to DigitalOcean

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:
| Provider | Monthly Cost | Best For | The Catch |
|---|---|---|---|
| AWS EC2 | $8-80/mo | You already live in AWS | Console 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/mo | Quick web app deploys | Dynos 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 + usage | Git-push simplicity | Usage-based pricing sounds cheap until your bot runs 24/7. A busy month can cost $20-40. |
| DigitalOcean | $6/mo flat | Bots, agents, anything that runs 24/7 | Fewer 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:
- Automatically restarts your agent if it crashes
- Starts it on server reboot without manual intervention
- 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 statusshows 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:
- Sign up for DigitalOcean (claim $200 in free credits for 60 days, enough to test this entire setup cost-free)
- Follow the 6-step process above (30 minutes total, no dependencies)
- Replace the example agent skeleton with your actual logic
- 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.
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
- DigitalOcean Droplet Documentation Official Droplet setup, regions, and pricing documentation.
- systemd Service Units Complete reference for writing systemd .service files to manage persistent processes.
- Python asyncio Documentation Official docs for Python's async event loop and task management used in the example.
- DigitalOcean SSH Key Setup Best practices for SSH key-based authentication and security hardening.
Further Reading
- How I Built a Self-Tuning Position Sizing System in Python How to build a self-tuning position sizing system that adjusts bet size based on recent performance — without overfitting or over-reacting to variance.
- Binance to Polymarket Signal Pipeline: How I Built It in Real Time How to wire Binance WebSocket price feeds into a Polymarket trading bot — signal detection, filtering, deduplication, and latency-optimized order flow.
- How I Built a Polymarket Trading Bot That Made Money A full technical walkthrough of building a latency arbitrage bot for Polymarket prediction markets — from Binance WebSocket signals to CLOB order placement.
Discussion
Comments powered by GitHub Discussions coming soon.