AI Agents

Deploy your LangChain agent to a VPS

You built an agent. It works on your machine. Now it needs to answer at 3am while you are asleep, keep answering after a reboot, and live at an address you can actually give people. This guide takes you from a folder of Python on your laptop to a service running on your own server, with HTTPS, in about half an hour.

First, the thing that confuses almost everyone

You cannot “install LangChain” on a server the way you install PostgreSQL or WordPress. LangChain is a library, not a service — there is no LangChain process to start and no LangChain page to visit. What you deploy is your application, which happens to import LangChain, the same way it imports requests.

That is good news: it means you do not need a special “LangChain host”. Any server with Python will do, and the steps below are the same whether your agent uses LangChain, LangGraph, CrewAI, or nothing but the OpenAI SDK.

How big a server do you need?

Smaller than people expect. The model itself runs on someone else’s hardware — your server holds a Python process, your dependencies, and whatever you cache. It is mostly waiting on network calls.

For a sense of scale, here is what we measured on real servers when we ran comparable self-hosted agents ourselves, taken 30 seconds after a live model request:

AgentMemory at idleRan fine on
OpenClaw278 MB1 vCPU / 1 GB
Hermes Agent120 MB1 vCPU / 1 GB
OpenHands (web workspace)846 MB1 vCPU / 2 GB

A typical LangChain agent sits at the light end of that range. Start at 1 GB. You need more when you run models locally, parse large documents, or hold big vector stores in memory — not because you added another chain.

Step 1 — Get a server with Python on it

Any Ubuntu 22.04 box works. On AgentOcean, choose the Python 3.12 preset at checkout and the runtime, pip and venv are already there when the server boots. On a bare server, install them yourself:

sudo apt update
sudo apt install -y python3.12 python3.12-venv python3-pip git

Step 2 — Put your code on the server

Git is the least painful route, and it makes updates one command later. Push your project to GitHub (a private repo is fine), then clone it:

sudo mkdir -p /opt/agent && sudo chown $USER /opt/agent
git clone https://github.com/you/your-agent.git /opt/agent
cd /opt/agent

No repo? scp -r ./your-agent root@your-server:/opt/agent copies a folder up directly. It works, but you will be doing it again every time you change something.

Step 3 — Install dependencies in a virtualenv

A virtualenv keeps your project’s packages away from the system Python, so an upgrade in one cannot break the other. If you do not have a requirements.txt, run pip freeze > requirements.txt on your laptop first.

cd /opt/agent
python3.12 -m venv .venv
.venv/bin/pip install --upgrade pip
.venv/bin/pip install -r requirements.txt

Note the .venv/bin/pip paths. Calling the virtualenv’s binaries directly means you never have to remember whether it is “activated” — which matters in Step 5, where systemd has no shell to activate anything in.

Step 4 — Keep your API keys out of your code

Put secrets in a file the service reads at startup, and make sure only root can read it. A key pasted into a Python file gets committed to git eventually — that is not a hypothetical, it is the single most common way agent keys leak.

sudo tee /opt/agent/.env > /dev/null <<'EOF'
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
LANGSMITH_API_KEY=
EOF
sudo chmod 600 /opt/agent/.env

Also add .env to your .gitignore before your next push.

Step 5 — Run it as a service that survives reboots

Starting your agent with python main.py in an SSH session lasts exactly as long as that session. systemd restarts it when it crashes and starts it again when the server reboots.

sudo tee /etc/systemd/system/agent.service > /dev/null <<'EOF'
[Unit]
Description=LangChain agent
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
WorkingDirectory=/opt/agent
EnvironmentFile=/opt/agent/.env
ExecStart=/opt/agent/.venv/bin/python main.py
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now agent
systemctl status agent --no-pager

Restart=always plus RestartSec=5 is what turns a crash into a five-second gap instead of a dead agent you notice on Monday.

Step 6 — If it serves HTTP, put HTTPS in front

Skip this if your agent only polls or listens on Telegram. If it exposes an API — LangServe, FastAPI, a webhook receiver — bind it to localhost only and let Caddy handle the public side and the certificate.

# In your app: bind to 127.0.0.1, never 0.0.0.0
uvicorn.run(app, host="127.0.0.1", port=8000)
sudo tee /etc/caddy/Caddyfile > /dev/null <<'EOF'
agent.yourdomain.com {
    reverse_proxy 127.0.0.1:8000
}
EOF
sudo systemctl reload caddy

Caddy fetches and renews the TLS certificate on its own. Point an A record at your server’s IP first, or the certificate request will fail.

One trap worth knowing, because we measured it

If any part of your stack runs in Docker, a published port bypasses your firewall. Docker writes its own iptables rules ahead of UFW’s, so -p 8000:8000 is reachable from the internet even when ufw status insists the port is blocked. We confirmed this from outside on live servers. Always write -p 127.0.0.1:8000:8000 and let the reverse proxy be the only thing listening publicly.

More in our VPS security guide.

Step 7 — Logs, and shipping changes

Anything your agent prints goes to the journal, so you do not need a logging library to start debugging:

# follow live
journalctl -u agent -f

# last 200 lines, including previous crashes
journalctl -u agent -n 200 --no-pager

Deploying a change is three commands:

cd /opt/agent
git pull
.venv/bin/pip install -r requirements.txt
sudo systemctl restart agent

When this stops being enough

This setup carries a single agent a long way. The honest limits: one server means one point of failure, git pull plus a restart is a few seconds of downtime, and there is no rollback beyond checking out the previous commit. If you need zero-downtime deploys or several instances behind a load balancer, you have outgrown one box — but you will know when, and it is later than you think.

Related guides