DEV Community

Sam Hartley
Sam Hartley

Posted on

I Built a Dead-Simple API Gateway for My Local LLMs in 50 Lines of Python

I Built a Dead-Simple API Gateway for My Local LLMs in 50 Lines of Python

I run three machines with local LLMs. A Mac Mini with an M4, a Windows box with an RTX 3060, and an Ubuntu server with a couple older GPUs. Each has Ollama installed. Each has different models loaded.

For months, I hardcoded URLs in my scripts. Need a quick answer? Query the Mac. Need a coding assistant? Hit the Windows machine. Need the big model? Wait for the Ubuntu server.

It was annoying. So I built a tiny API gateway that routes requests automatically. It took an afternoon. It runs on a single Python file. And it completely changed how I use my local AI setup.

The Problem: Three URLs, Zero Logic

Before the gateway, my scripts looked like this:

# quick_question.py
import requests

# Which machine do I use today?
# Mac Mini — fast, small models
response = requests.post("http://192.168.1.100:11434/api/generate", json={
    "model": "qwen2.5:7b",
    "prompt": "Explain Python decorators"
})
Enter fullscreen mode Exit fullscreen mode
# code_review.py
import requests

# Windows — has the GPU
response = requests.post("http://192.168.1.106:11434/api/generate", json={
    "model": "qwen3-coder:30b",
    "prompt": "Review this function..."
})
Enter fullscreen mode Exit fullscreen mode
# hard_question.py
import requests

# Ubuntu — has the most VRAM
response = requests.post("http://192.168.1.100:11434/api/generate", json={
    "model": "deepseek-r1:70b",
    "prompt": "Design a distributed task queue..."
})
Enter fullscreen mode Exit fullscreen mode

Three scripts. Three URLs. Zero flexibility. If the Windows machine was offline, the coding script just failed. If I added a new model, I had to update everything manually.

The Fix: A Stupid-Simple Gateway

I wanted one URL. One API. Let the gateway figure out which machine can handle the request.

Here's what I built:

# gateway.py
from flask import Flask, request, jsonify
import requests

app = Flask(__name__)

# My machines and what they can run
MACHINES = {
    "mac": {"url": "http://192.168.1.100:11434", "models": ["qwen2.5:7b", "granite3.2-vision:2b"]},
    "windows": {"url": "http://192.168.1.106:11434", "models": ["qwen3-coder:30b", "deepseek-r1:8b"]},
    "ubuntu": {"url": "http://192.168.1.100:11434", "models": ["deepseek-r1:70b", "minicpm-v"]},
}

def find_machine(model):
    for name, cfg in MACHINES.items():
        if model in cfg["models"]:
            return cfg["url"]
    return None

@app.route("/api/generate", methods=["POST"])
def generate():
    data = request.get_json()
    model = data.get("model")

    if not model:
        return jsonify({"error": "No model specified"}), 400

    machine_url = find_machine(model)
    if not machine_url:
        return jsonify({"error": f"Model {model} not found on any machine"}), 404

    try:
        response = requests.post(
            f"{machine_url}/api/generate",
            json=data,
            timeout=300
        )
        return response.json(), response.status_code
    except requests.exceptions.ConnectionError:
        return jsonify({"error": f"Machine for {model} is offline"}), 503

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=11435)
Enter fullscreen mode Exit fullscreen mode

That's it. 50 lines. Run it on any machine, point all your scripts at http://gateway:11435, and forget about which box has which model.

Why This Is Better Than I Expected

I can move models around. When I got a new GPU for the Windows machine, I moved the big coding model there. Changed one line in MACHINES. Every script kept working.

Health checks are trivial. I added a /health endpoint that pings each machine. If one is down, my main script knows and routes around it.

Load balancing is obvious. If two machines have the same model, I can pick whichever is less busy. I haven't needed this yet, but the structure supports it.

My scripts got dumber. In a good way. They don't need to know about the infrastructure anymore. They just ask for a model and get an answer.

What I Didn't Build (On Purpose)

No database. No config files. No Docker. No Kubernetes. No "service mesh."

This is a single Python file with a dictionary. If I need to change something, I edit the file and restart it. Takes 10 seconds.

I thought about making it "proper" — YAML configs, hot reloading, Prometheus metrics. But this is for my home lab. I'm the only user. Complexity is the enemy.

The Real Win: Mental Overhead

Before the gateway, using my local AI felt like work. I'd open a script, remember which machine had which model, check if it was online, then query it.

Now it feels like... using an API. Any API. I don't think about the infrastructure. I just write the prompt and get the result.

That's the whole point of infrastructure: it should disappear.

Numbers (Because Why Not)

  • Lines of Python: 50
  • Time to build: 2 hours (including testing)
  • Time saved per week: ~30 minutes of "which machine is this on again?"
  • Additional dependencies: Flask (already installed for other projects)
  • Cost: $0

Getting Started

If you have multiple Ollama instances, you can literally copy-paste the script above, change the IPs and models, and be done.

pip install flask requests
python gateway.py
Enter fullscreen mode Exit fullscreen mode

Then in your scripts:

import requests

# One URL. Any model. Gateway handles the rest.
response = requests.post("http://localhost:11435/api/generate", json={
    "model": "qwen3-coder:30b",
    "prompt": "Refactor this function..."
})
Enter fullscreen mode Exit fullscreen mode

The Honest Bottom Line

Is this production-ready? No. Does it handle edge cases? Barely. Is it good enough for my home lab? Absolutely.

Sometimes the right architecture is the one you'll actually maintain. A 50-line Python file I can debug in my head beats a "proper" solution I'd never finish.

If you're running multiple Ollama instances and manually switching between them — just build the gateway. It takes an afternoon and saves you from ever thinking about machine IPs again.


Sam Hartley is a solo dev running a multi-machine AI home lab in Turkey. Writes about the boring infrastructure that makes local AI actually usable.

Custom automation setups on Fiverr
Follow CelebiBots on Telegram

ai #ollama #selfhosted #api #python #homelab #buildinpublic

Top comments (0)