Author: admin_ts

  • Build an AI Agent: Python, Docker & Deployment Guide

    How to Build an AI Agent: A Practical Developer’s Guide

    Disclosure: This post contains one or more links to providers we have a real, registered affiliate/referral relationship with. We may earn a commission at no extra cost to you if you sign up through them.

    If you’ve spent any time on developer Twitter or Hacker News in the last year, you’ve seen the term “AI agent” thrown around constantly. Most of the explanations are either too abstract (“it’s software that thinks!”) or too shallow (a single API call wrapped in a for-loop). This guide skips the hype and shows you how to build an AI agent that actually does something useful, then run it in production like any other service in your stack — containerized, monitored, and secured.

    We’ll build a real agent in Python, containerize it with Docker, and deploy it to a VPS. By the end, you’ll understand the architecture well enough to build your own agents for DevOps automation, log triage, or customer support.

    What Is an AI Agent, Really?

    An AI agent is a program that uses a large language model (LLM) as its reasoning engine, but unlike a chatbot, it doesn’t just generate text — it takes actions. It calls functions, hits APIs, reads files, queries databases, and uses the results to decide what to do next. The defining trait is the loop: observe, reason, act, repeat — until the task is done or a stopping condition is hit.

    Agents vs. Simple Chatbots

    A chatbot answers one prompt and stops. An agent:

  • Breaks a goal into sub-tasks
  • Chooses which tool to call for each sub-task (a shell command, an API, a search query)
  • Evaluates the tool’s output and decides the next step
  • Keeps state across multiple steps until the goal is satisfied
  • If you’ve used GitHub’s Copilot Workspace or any coding assistant that can run commands and fix its own errors, you’ve already used an agent. The same pattern applies to server automation, incident response, and content pipelines — which is exactly the kind of workload this site’s readers deal with daily.

    Core Components of an AI Agent

    Every agent, regardless of framework, is built from the same four pieces:

  • A model — the LLM that does the reasoning (GPT-4, Claude, Llama, etc.)
  • A tool set — functions the agent is allowed to call (shell exec, HTTP requests, DB queries)
  • Memory — short-term context for the current task, and optionally long-term storage for prior runs
  • A control loop — the code that ties it all together and decides when to stop
  • The Reasoning Loop

    The control loop is the part most tutorials gloss over. In practice it’s a simple while loop: send the model the current state, parse its response for a tool call, execute that tool, feed the result back in, repeat. The loop terminates when the model returns a final answer instead of a tool call, or when you hit a max-iteration safety limit (always set one — an ungoverned loop can burn through API credits fast).

    Tools and Function Calling

    Modern LLM APIs support structured “function calling,” where you describe available functions in JSON Schema and the model returns a structured call instead of free text. This is far more reliable than parsing natural language for commands.

    Memory and State

    For short tasks, an in-memory list of messages is enough. For anything long-running — like an agent that monitors your infrastructure over days — you’ll want persistent storage. Redis works well for this: fast, simple key-value storage for conversation state and tool results.

    Building Your First AI Agent in Python

    Here’s a minimal but functional agent that can execute shell commands and read files — useful as a base for a DevOps automation bot. It uses OpenAI’s function-calling API, but the same pattern works with Anthropic’s Claude API or any local model server.

    import json
    import subprocess
    from openai import OpenAI
    
    client = OpenAI()
    
    tools = [
        {
            "type": "function",
            "function": {
                "name": "run_shell_command",
                "description": "Run a read-only shell command and return its output",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "command": {"type": "string"}
                    },
                    "required": ["command"]
                }
            }
        }
    ]
    
    ALLOWED_COMMANDS = ("df", "uptime", "free", "docker ps", "systemctl status")
    
    def run_shell_command(command: str) -> str:
        if not command.startswith(ALLOWED_COMMANDS):
            return "Error: command not permitted by allowlist"
        result = subprocess.run(command, shell=True, capture_output=True, text=True, timeout=10)
        return result.stdout or result.stderr
    
    def run_agent(user_goal: str, max_steps: int = 6):
        messages = [{"role": "user", "content": user_goal}]
    
        for _ in range(max_steps):
            response = client.chat.completions.create(
                model="gpt-4o",
                messages=messages,
                tools=tools,
            )
            message = response.choices[0].message
            messages.append(message)
    
            if not message.tool_calls:
                return message.content  # final answer
    
            for call in message.tool_calls:
                args = json.loads(call.function.arguments)
                output = run_shell_command(args["command"])
                messages.append({
                    "role": "tool",
                    "tool_call_id": call.id,
                    "content": output,
                })
    
        return "Max steps reached without a final answer."
    
    if __name__ == "__main__":
        print(run_agent("Check disk usage and container status, summarize any issues"))

    Note the ALLOWED_COMMANDS allowlist. This is not optional — an agent with unrestricted shell access is a remote code execution vulnerability wearing a trench coat. Always constrain what tools your agent can actually invoke.

    If you’d rather not hand-roll the loop, frameworks like LangChain or LlamaIndex handle tool orchestration, retries, and memory for you, at the cost of extra abstraction layers you’ll eventually need to peel back to debug anything.

    Deploying Your AI Agent with Docker

    Once the agent works locally, containerize it so it runs identically in staging and production — the same reasoning we cover in our Docker Compose guide for multi-container apps applies here.

    Containerizing the Agent

    FROM python:3.12-slim
    
    WORKDIR /app
    
    COPY requirements.txt .
    RUN pip install --no-cache-dir -r requirements.txt
    
    COPY agent.py .
    
    # Never bake API keys into the image — inject at runtime
    ENV OPENAI_API_KEY=""
    
    USER nobody
    CMD ["python", "agent.py"]

    Build and run it with the key injected as an environment variable, not hardcoded:

    docker build -t my-ai-agent .
    docker run --rm 
      -e OPENAI_API_KEY="$OPENAI_API_KEY" 
      --memory=512m 
      --cpus=1 
      my-ai-agent

    The --memory and --cpus flags matter more for agents than for typical web services — a runaway reasoning loop can spike CPU usage if your max-step guard fails, so hard resource limits are cheap insurance.

    Running as a Persistent Service

    For an agent that needs to stay alive and respond to triggers (webhooks, cron, a message queue), wrap it in a small FastAPI service instead of a one-shot script, and run it under docker-compose alongside Redis for state:

    services:
      agent:
        build: .
        restart: unless-stopped
        environment:
          - OPENAI_API_KEY=${OPENAI_API_KEY}
          - REDIS_URL=redis://redis:6379
        depends_on:
          - redis
    
      redis:
        image: redis:7-alpine
        volumes:
          - redis-data:/data
    
    volumes:
      redis-data:

    Hosting Your AI Agent in Production

    An agent that calls external tools and possibly touches production infrastructure deserves a properly isolated VPS, not a shared dev box. A basic 2-vCPU / 4GB droplet from DigitalOcean is enough for most single-agent workloads, and their managed Redis add-on saves you from running your own. If you’re optimizing for cost-per-vCPU on long-running background workers, Hetzner cloud instances are consistently cheaper for the same specs — a detail we go into in our VPS cost comparison guide.

    Once deployed, you need visibility into whether the agent is actually alive and completing tasks, not silently stuck in a retry loop. BetterStack uptime and log monitoring can alert you the moment your agent’s health-check endpoint stops responding, which matters a lot more for autonomous services than for a static website — nobody’s refreshing a page to notice an agent has hung.

    Securing Your AI Agent

    Agents with tool access are a bigger attack surface than a typical CRUD app, because a cleverly crafted input (prompt injection) can trick the model into calling a tool it shouldn’t. Bake these controls in from day one:

  • Allowlist tools and commands explicitly — never let the model construct arbitrary shell strings
  • Run the container as a non-root user with no unnecessary filesystem access
  • Set hard timeouts and max-iteration limits on the reasoning loop
  • Log every tool call and its output so you can audit what the agent actually did
  • Keep API keys in environment variables or a secrets manager, never in the image or source control
  • Rate-limit external API calls the agent can trigger to avoid runaway cost or abuse
  • If your agent is public-facing (say, behind a webhook), put it behind Cloudflare for DDoS protection and WAF rules before traffic reaches your container — this is standard practice for any exposed endpoint, agent or not.

    Wrapping Up

    Building an AI agent isn’t fundamentally different from building any other backend service: you still need containerization, resource limits, monitoring, and a security model. The LLM is just the decision-making component in the middle. Start small — a single-tool agent solving one narrow problem — before reaching for multi-agent frameworks or long-running autonomous systems. Get the loop, the tool allowlist, and the deployment pipeline right first; complexity can come later once you trust the foundation.

    Recommended: Ready to put this into practice? DigitalOcean is a tool we use for exactly this, and we have a real, disclosed affiliate relationship with them.

    FAQ

    Do I need a framework like LangChain to build an AI agent?
    No. For a single-purpose agent with a handful of tools, a plain function-calling loop (as shown above) is easier to debug and has fewer moving parts. Frameworks earn their keep once you’re managing many agents, complex memory, or multi-step planning across sessions.

    Which LLM should I use for an agent?
    GPT-4o and Claude models both support reliable function calling and handle multi-step reasoning well. For cost-sensitive, high-volume agents, smaller or open-source models (Llama 3, Mistral) can work if the tool set is narrow and well-defined — test accuracy on your specific tasks before committing.

    How do I stop an agent from running forever or looping?
    Always cap iterations with a max_steps counter and enforce per-call timeouts on any tool the agent invokes. Combine this with container-level CPU and memory limits so a stuck loop can’t consume unbounded resources.

    Is it safe to let an agent run shell commands on my server?
    Only with a strict allowlist of specific commands, run as a non-root, non-privileged user, ideally inside an isolated container with no access to secrets it doesn’t need. Never give an agent unrestricted shell=True execution against production.

    Can I run an AI agent without paying for a cloud LLM API?
    Yes — self-hosted models via Ollama or a GPU VPS can replace the OpenAI/Anthropic API for many agent workloads, at the cost of managing your own inference infrastructure and generally lower reasoning quality on complex tool-use tasks.

    How much does it cost to run an AI agent in production?
    Costs split into two buckets: LLM API usage (billed per token, scales with loop iterations) and hosting (a small VPS is usually $10-40/month). Set hard iteration limits and log token usage per run so costs stay predictable as usage grows.

  • Building AI Agents: A Practical DevOps Guide

    Building AI Agents: A Developer’s Guide to Autonomous Workflows

    Disclosure: This post contains one or more links to providers we have a real, registered affiliate/referral relationship with. We may earn a commission at no extra cost to you if you sign up through them.

    Every few years a new abstraction shows up in software engineering that changes how we ship products. Containers did it for deployment. Kubernetes did it for orchestration. Now agentic AI is doing it for automation. If you’ve spent any time on engineering Twitter or Hacker News in the last year, you’ve seen the term thrown around constantly, but most of the content out there is either hand-wavy product marketing or academic papers you need a PhD to parse.

    This guide skips both. We’re going to treat building AI agents like any other DevOps problem: define the architecture, write the code, containerize it, deploy it, and monitor it in production. By the end you’ll have a working agent running in Docker, with a clear path to scaling it on real infrastructure.

    What Is an AI Agent, Actually?

    An AI agent is a program that uses a large language model (LLM) not just to generate text, but to make decisions in a loop: observe the current state, decide on an action, execute that action (often by calling a tool or API), and then observe the result before deciding again. The key difference from a simple chatbot is autonomy — an agent can chain multiple steps together without a human clicking “send” after every message.

    Agents vs. Simple LLM API Calls

    A lot of people confuse “calling GPT-4 in a script” with “building an agent.” They’re not the same thing. A single API call is stateless: you send a prompt, you get a completion, done. An agent wraps that call in a loop with memory, tool access, and a stopping condition. Concretely, an agent architecture usually includes:

  • A planner that breaks a goal into steps
  • A tool layer that lets the model call functions (search the web, query a database, hit an API)
  • A memory store that persists context across steps (often a vector database)
  • An executor loop that keeps iterating until the goal is met or a max-step limit is hit
  • If your script doesn’t have at least a loop and a tool layer, you’ve built a prompt wrapper, not an agent. That distinction matters when you’re scoping infrastructure — agents are stateful, long-running processes, which changes how you deploy and monitor them compared to a stateless API endpoint.

    Why Self-Hosting Matters for Agent Workloads

    Most tutorials assume you’ll run your agent on a managed platform or a laptop. Neither works well in production. Managed agent platforms lock you into their pricing and rate limits, and a laptop obviously can’t run 24/7. If your agent needs to poll a queue, watch a filesystem, or run scheduled tasks, you need a real server.

    This is also where cost control becomes a real concern. LLM API calls aren’t free, and a poorly bounded agent loop can burn through your token budget in minutes if it gets stuck retrying a failed tool call. Self-hosting the orchestration layer — while still calling out to an LLM API — gives you full control over rate limiting, retry logic, and logging, none of which you get with a black-box SaaS agent builder.

    Building a Simple AI Agent in Python

    Let’s build something real. We’ll use the OpenAI API for the model calls and keep the orchestration logic in plain Python so you can see exactly what’s happening at each step — no heavy framework required to start.

    First, set up your environment:

    mkdir agent-demo && cd agent-demo
    python3 -m venv venv
    source venv/bin/activate
    pip install openai requests python-dotenv

    Now create agent.py:

    import os
    import json
    import requests
    from openai import OpenAI
    from dotenv import load_dotenv
    
    load_dotenv()
    client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
    
    def get_weather(city: str) -> str:
        """Tool: fetch current weather for a city."""
        resp = requests.get(f"https://wttr.in/{city}?format=3", timeout=5)
        return resp.text.strip()
    
    TOOLS = [
        {
            "type": "function",
            "function": {
                "name": "get_weather",
                "description": "Get current weather for a given city",
                "parameters": {
                    "type": "object",
                    "properties": {"city": {"type": "string"}},
                    "required": ["city"],
                },
            },
        }
    ]
    
    def run_agent(user_goal: str, max_steps: int = 5):
        messages = [{"role": "user", "content": user_goal}]
    
        for step in range(max_steps):
            response = client.chat.completions.create(
                model="gpt-4o-mini",
                messages=messages,
                tools=TOOLS,
            )
            message = response.choices[0].message
            messages.append(message)
    
            if not message.tool_calls:
                return message.content
    
            for call in message.tool_calls:
                args = json.loads(call.function.arguments)
                if call.function.name == "get_weather":
                    result = get_weather(args["city"])
                else:
                    result = "Unknown tool"
    
                messages.append({
                    "role": "tool",
                    "tool_call_id": call.id,
                    "content": result,
                })
    
        return "Max steps reached without a final answer."
    
    if __name__ == "__main__":
        print(run_agent("What's the weather like in Lisbon right now?"))

    This is the entire skeleton of an agent: a loop, a tool the model can call, and a hard stop at max_steps so a broken loop can’t run forever and rack up API charges. Every production agent framework — LangChain, CrewAI, AutoGen — is a more elaborate version of this same pattern. Understanding this loop first will save you hours of debugging once you move to a framework, because you’ll actually know what’s happening under the abstraction.

    Adding Memory with a Vector Store

    Once your agent needs to recall information across sessions, a plain message list isn’t enough. Most production agents pair the loop above with a vector database like Chroma or Pinecone to store and retrieve embeddings of past interactions or documents. The pattern is straightforward: embed incoming text, store it with metadata, and query the store for relevant context before each LLM call. We won’t build the full retrieval pipeline here, but keep in mind that memory is a separate concern from the agent loop — don’t couple them tightly, or you’ll struggle to swap vector stores later.

    Containerizing Your Agent with Docker

    Once the logic works locally, package it so it runs identically anywhere. If you’re new to multi-service setups, our guide to Docker Compose fundamentals covers the basics this section builds on.

    FROM python:3.12-slim
    
    WORKDIR /app
    
    COPY requirements.txt .
    RUN pip install --no-cache-dir -r requirements.txt
    
    COPY agent.py .
    
    ENV PYTHONUNBUFFERED=1
    
    CMD ["python", "agent.py"]

    Running a Multi-Agent Stack with Docker Compose

    Real-world setups rarely involve a single agent. You’ll typically have an agent process, a vector database for memory, and maybe a Redis instance for task queuing. Here’s a docker-compose.yml that ties them together:

    version: "3.9"
    services:
      agent:
        build: .
        env_file: .env
        depends_on:
          - redis
          - chroma
        restart: unless-stopped
    
      redis:
        image: redis:7-alpine
        restart: unless-stopped
    
      chroma:
        image: chromadb/chroma:latest
        ports:
          - "8000:8000"
        volumes:
          - chroma-data:/chroma/chroma
        restart: unless-stopped
    
    volumes:
      chroma-data:

    Bring it up with docker compose up -d --build, and you have an isolated, reproducible agent stack that behaves the same on your laptop as it does on a production VPS. This matters more than it sounds — LLM agent behavior can be subtly sensitive to Python and library versions, and Docker eliminates the “works on my machine” class of bugs entirely.

    Monitoring and Scaling Agents in Production

    Agents fail differently than typical web services. Instead of a clean 500 error, an agent might silently loop, hallucinate a tool call that doesn’t exist, or quietly burn through your API budget over a weekend while nobody’s watching. Standard uptime monitoring isn’t enough here — you need to track step counts, token usage, and tool-call failure rates.

    Logging Every Step for Debuggability

    At minimum, log the full message history for every agent run, not just the final output. When an agent misbehaves, the failure is almost always buried three or four steps back in the transcript, not in the final response. Structure your logs as JSON so they’re easy to query later:

    import logging
    import json
    
    logger = logging.getLogger("agent")
    
    def log_step(step: int, message: dict):
        logger.info(json.dumps({"step": step, "message": message}))

    Ship those logs somewhere durable rather than relying on docker logs, which rotates and disappears. For teams that don’t want to run their own ELK stack, a hosted option like BetterStack gives you centralized log aggregation and uptime alerting without the operational overhead — genuinely useful once you have more than one agent running unattended. If you’re comparing observability options more broadly, see our breakdown of self-hosted monitoring stacks for the tradeoffs.

    Setting Hard Limits to Control Cost

    Beyond max_steps, add a token budget check before every LLM call and kill the run if it’s exceeded. This single guardrail has saved more than a few teams from a surprise five-figure API bill after an agent got stuck in a retry loop over a long weekend.

    Choosing Infrastructure for Your Agent Workloads

    Agents that run continuously — polling queues, watching webhooks, executing scheduled jobs — need a server, not a laptop or a serverless function with a 15-minute timeout. A small VPS is more than enough to start. DigitalOcean droplets are a solid default if you want a simple, well-documented control panel and predictable pricing while you’re iterating on the architecture. If you’re optimizing for cost once your agent stack stabilizes, Hetzner cloud instances offer significantly cheaper compute per dollar for the same workload, which adds up once you’re running multiple agents around the clock.

    Whichever provider you pick, harden the box before you deploy anything — our Linux server hardening checklist is a good starting point, since an agent with API keys and tool access on a poorly secured server is a bigger liability than a typical web app.

    Security Considerations for Autonomous Agents

    An agent that can execute code, hit arbitrary URLs, or write to a filesystem is functionally similar to giving a script root-ish access to your infrastructure. A few non-negotiables:

  • Never let an agent execute raw shell commands from model output without a strict allowlist of permitted operations
  • Scope API keys narrowly — a tool that only needs read access shouldn’t hold a key with write permissions
  • Sandbox any code-execution tools in a disposable container, not the host running your agent process
  • Rate-limit and log every outbound HTTP call the agent makes, since a compromised or confused agent can be tricked into exfiltrating data through a tool call
  • Treat all tool outputs as untrusted input — a malicious webpage or API response can attempt prompt injection against your own agent
  • That last point deserves emphasis: prompt injection through tool results is one of the most common real-world agent vulnerabilities, and it’s easy to overlook because it doesn’t look like a traditional security bug.

    Recommended: Ready to put this into practice? DigitalOcean is a tool we use for exactly this, and we have a real, disclosed affiliate relationship with them.

    FAQ

    What’s the difference between building AI agents and using a chatbot API?
    A chatbot API call is a single stateless request-response exchange. Building AI agents involves wrapping model calls in a loop with memory, tool access, and a decision-making process that can span multiple steps without human input at each stage.

    Do I need a framework like LangChain to build an agent?
    No. As shown in the Python example above, you can build a working agent loop with plain code and the OpenAI SDK. Frameworks add convenience for complex multi-agent orchestration, but understanding the raw loop first makes debugging framework-based agents much easier.

    How much does it cost to run an AI agent in production?
    Costs depend on token usage per step and how many steps your loop runs before stopping. A well-bounded agent with a hard max_steps limit and token budget checks typically costs a few cents to a few dollars per run, depending on the model. Unbounded loops are the main cause of runaway bills.

    Can I run AI agents entirely on my own hardware without cloud APIs?
    Yes, using local models served through tools like Ollama or vLLM instead of a hosted API. This removes per-token costs but requires GPU hardware and generally produces weaker reasoning than frontier hosted models, so it’s a tradeoff between cost and capability.

    Is Docker required to deploy an AI agent?
    Not strictly, but it’s strongly recommended. Agent behavior can be sensitive to Python and dependency versions, and Docker guarantees your local testing environment matches production exactly, which matters more for agents than for typical stateless services.

    How do I prevent an agent from getting stuck in an infinite loop?
    Always enforce a hard max_steps limit in your executor loop, plus a token budget check before each LLM call. Log every step so you can diagnose why a loop got stuck rather than just killing and restarting it blindly.

    Wrapping Up

    Building AI agents isn’t magic — it’s a loop, a tool layer, some memory, and a lot of the same DevOps discipline you’d apply to any other production service: containerize it, monitor it, log everything, and put hard limits on anything that costs money per call. Start with the plain Python loop above, containerize it with Docker once it works, and deploy it on a small VPS you actually control. That gets you further, faster, than reaching for a heavyweight framework before you understand what it’s abstracting away.

  • AI Agent Companies: A 2026 DevOps Buyer’s Guide

    AI Agent Companies: A DevOps Guide to Evaluating and Self-Hosting Agent Platforms

    Disclosure: This post contains one or more links to providers we have a real, registered affiliate/referral relationship with. We may earn a commission at no extra cost to you if you sign up through them.

    Every week another one of the AI agent companies announces a new framework, SDK, or “autonomous” platform. For developers and sysadmins who actually have to run this stuff in production, the marketing noise is less useful than a straight answer to two questions: who is actually building the infrastructure layer, and what does it take to self-host an agent stack without setting your cloud bill on fire?

    This post breaks down the landscape of AI agent companies from an infrastructure perspective — model providers, hyperscaler platforms, and open-source frameworks — and walks through a real Docker-based deployment you can run on your own VPS.

    The Three Types of AI Agent Companies (and Why That Matters for Infra)

    Not all AI agent companies solve the same problem. Before you pick a vendor, it helps to understand which category they fall into, because that determines how much infrastructure work lands on your plate.

    1. Model Providers Bolting On Agent Tooling

    Companies like OpenAI and Anthropic sell the underlying language model and layer agent primitives — tool calling, memory, planning loops — on top of their APIs. You don’t manage compute for inference, but you’re locked into their rate limits, pricing, and uptime. This is the fastest path to a working prototype and the worst path if you need predictable costs at scale.

    2. Cloud Hyperscaler Agent Platforms

    AWS Bedrock Agents, Google’s Vertex AI Agent Builder, and Azure AI Studio wrap orchestration, retrieval, and observability around foundation models inside their existing cloud ecosystems. These make sense if you’re already deep in one cloud’s IAM and networking stack, but they add a layer of proprietary configuration that doesn’t travel well if you ever want to migrate.

    3. Open-Source Agent Frameworks You Self-Host

    Projects like LangGraph and CrewAI give you the orchestration logic — state machines, agent-to-agent handoffs, tool routing — as code you run yourself, typically against whichever model API or local inference server you choose. This is the category most relevant to a DevOps-focused audience, because the entire deployment, scaling, and monitoring burden is yours. It’s also the only option that lets you swap the underlying model without rewriting your agent logic.

    For teams that already run their own container infrastructure, this third category is usually the right call — you keep control of cost, data residency, and uptime instead of inheriting someone else’s SLA.

    Evaluating AI Agent Companies: A DevOps Checklist

    Before signing up for any platform or pulling in a framework, run through this checklist:

  • Deployment model — Is it a hosted SaaS, a managed cloud service, or a self-hostable open-source project?
  • State and memory storage — Where does conversation and task state live, and can you point it at your own Postgres or Redis instance?
  • Rate limits and quotas — Are limits per-API-key, per-org, or negotiable at scale?
  • Observability hooks — Does it expose OpenTelemetry traces, structured logs, or webhooks you can pipe into your existing monitoring stack?
  • Model portability — Can you swap GPT-4-class models for a self-hosted Llama or Mistral deployment without rewriting the agent graph?
  • Data egress and compliance — Where is data processed, and does that satisfy your regulatory requirements?
  • If a vendor can’t give you clear answers on the first three, treat it as a prototype tool, not a production dependency.

    Deploying an Open-Source Agent Stack with Docker

    Here’s a minimal, realistic setup: a self-hosted agent orchestrator, a vector store for retrieval, and a Postgres instance for state, all wired together with Docker Compose. This mirrors the kind of stack you’d run for an internal support-ticket agent or a documentation Q&A bot.

    # docker-compose.yml
    version: "3.9"
    
    services:
      agent-orchestrator:
        image: python:3.11-slim
        working_dir: /app
        volumes:
          - ./agent:/app
        command: bash -c "pip install -r requirements.txt && python agent_server.py"
        environment:
          - OPENAI_API_KEY=${OPENAI_API_KEY}
          - DATABASE_URL=postgresql://agent:agent@postgres:5432/agentdb
          - VECTOR_DB_URL=http://qdrant:6333
        ports:
          - "8080:8080"
        depends_on:
          - postgres
          - qdrant
        restart: unless-stopped
    
      postgres:
        image: postgres:16-alpine
        environment:
          - POSTGRES_USER=agent
          - POSTGRES_PASSWORD=agent
          - POSTGRES_DB=agentdb
        volumes:
          - pgdata:/var/lib/postgresql/data
        restart: unless-stopped
    
      qdrant:
        image: qdrant/qdrant:latest
        volumes:
          - qdrantdata:/qdrant/storage
        restart: unless-stopped
    
    volumes:
      pgdata:
      qdrantdata:

    Bring it up with:

    export OPENAI_API_KEY=sk-your-key-here
    docker compose up -d
    docker compose logs -f agent-orchestrator

    This gives you a working orchestrator with persistent state and a vector store, all running on a single VPS. If you haven’t set up a production-grade Compose file before, our Docker Compose production guide covers health checks, restart policies, and secrets handling in more depth.

    Once you outgrow a single host — multiple agent workers, GPU nodes for local inference, autoscaling based on queue depth — you’ll want to move this onto an orchestrator. Our comparison of Kubernetes vs Docker Swarm walks through which one makes sense for a small ops team versus a larger platform engineering group.

    Monitoring Your Agent Infrastructure

    Agent workloads fail differently than typical web services — a stuck reasoning loop, a runaway tool call, or a silent API timeout can burn through budget without ever throwing a 500 error. At minimum, track:

  • Token usage per agent run, broken out by model
  • Tool call latency and error rate
  • Queue depth if you’re running async agent workers
  • Cost per completed task, not just per API call
  • A lightweight way to get alerting on these metrics without building a custom dashboard from scratch is to pipe structured logs into an uptime and monitoring service. BetterStack handles log aggregation and incident alerting well for this kind of workload and integrates cleanly with a Docker-based stack — worth checking out if you don’t already have something in place.

    Securing Agent Workloads

    Agents that can call tools — hitting internal APIs, writing to a database, executing shell commands — are a meaningfully larger attack surface than a plain chat interface. A few non-negotiables:

  • Run tool-execution sandboxes in isolated containers, never in the same process as the orchestrator
  • Scope API keys and database credentials per-agent, not shared across your whole fleet
  • Log every tool invocation with full arguments for post-incident review
  • Treat any user-supplied text that reaches a tool call as untrusted input, the same way you’d treat a raw SQL query
  • This isn’t optional hardening — prompt injection attacks that trick an agent into calling a destructive tool are a documented and increasingly common attack pattern, and the fix is standard application security discipline, not a special AI-specific tool.

    Cost Comparison: Managed vs Self-Hosted

    Managed AI agent platforms bill per-token and per-API-call, and those costs compound fast once an agent starts looping through multi-step reasoning chains. Self-hosting the orchestration layer doesn’t eliminate model costs if you’re still calling a hosted LLM API, but it does let you cap infrastructure spend to a predictable VPS bill. A mid-tier server from a provider like Hetzner or DigitalOcean running the Compose stack above typically costs less per month than a moderate volume of managed-platform API calls, especially once you add caching and rate-limiting in front of the model calls yourself. If you’re still comparing hosts, our VPS hosting comparison for 2026 has current pricing and benchmark numbers.

    Choosing the Right Approach for Your Team

    If you’re a solo developer or small team prototyping an idea, start with a hosted API and an open-source framework like LangGraph or CrewAI — you get to production faster and can always migrate the orchestration layer later since it’s just code you control. If you’re running this at company scale with compliance requirements, the hyperscaler agent platforms buy you integration with existing IAM and audit tooling at the cost of portability. Either way, keep the orchestration logic decoupled from the specific model provider — that’s the one decision that’s expensive to reverse later.

    Recommended: Ready to put this into practice? DigitalOcean is a tool we use for exactly this, and we have a real, disclosed affiliate relationship with them.

    FAQ

    What’s the difference between an AI agent company and a plain LLM API provider?
    An LLM API provider (like a raw OpenAI or Anthropic completions endpoint) just returns text. AI agent companies add orchestration on top — tool calling, multi-step planning, memory, and often a hosted runtime to execute agent loops, so the model can take actions rather than just respond to a single prompt.

    Can I self-host an AI agent framework without paying for a managed platform?
    Yes. Frameworks like LangGraph, CrewAI, and AutoGen are open source and run as regular Python processes — you only pay for the underlying model API calls (or your own inference hardware) and whatever compute hosts the orchestrator itself.

    Do I need a GPU to run an AI agent stack?
    Only if you’re running the language model itself locally. If you’re calling a hosted model API for inference and just self-hosting the orchestration and state layer, a standard CPU-based VPS is sufficient.

    How do I stop an AI agent from getting stuck in an infinite reasoning loop?
    Set a hard maximum step count and a wall-clock timeout at the orchestrator level, and log every intermediate step so you can debug loops after the fact rather than relying on the model to self-terminate.

    Are AI agent companies a security risk if agents can execute code or call APIs?
    Yes, if tool execution isn’t sandboxed. Treat every tool call as you would an untrusted API request — isolate execution, scope credentials tightly, and log all inputs and outputs for auditing.

    Which AI agent company should I pick for a production deployment?
    There’s no single right answer — it depends on whether you need vendor-managed infrastructure (hyperscaler platforms), fast prototyping (hosted APIs with agent SDKs), or full control over cost and data (self-hosted open-source frameworks). Most teams that already run their own Docker infrastructure get the best cost-to-control ratio from the self-hosted route.

    The AI agent space is moving fast, but the infrastructure fundamentals haven’t changed: containerize your services, monitor token and tool-call costs like you’d monitor any other metered resource, and keep your orchestration logic portable across model providers. Do that, and it won’t matter much which of the current crop of AI agent companies wins the marketing war next quarter.

  • Docker Compose Log Command: A Complete Debugging Guide

    Docker Compose Log Command: A Complete Debugging Guide

    Disclosure: This post contains one or more links to providers we have a real, registered affiliate/referral relationship with. We may earn a commission at no extra cost to you if you sign up through them.

    If your containers are misbehaving, the first place to look is the log output — and the docker compose logs command is how you get it. This guide covers everything from basic syntax to advanced filtering, log driver configuration, and shipping logs to a centralized platform for production monitoring.

    Whether you’re running a single Compose stack on your laptop or a multi-service application in production, mastering the docker compose log workflow will save you hours of guesswork when something breaks.

    This article assumes you already have Docker and Docker Compose installed and a working docker-compose.yml — if you’re setting up a stack from scratch, get the containers running first with docker compose up -d, then come back here once you need to actually read what they’re doing. Everything below works identically whether your compose file defines two services or twenty, and the same flags apply whether you’re debugging on a local dev machine or SSH’d into a remote host.

    What Is the docker compose logs Command?

    docker compose logs is a subcommand of the Docker Compose CLI that aggregates and displays the stdout/stderr output from every container defined in your docker-compose.yml file (or a specific service, if you name one). Unlike docker logs, which only works against a single container, docker compose logs understands your entire stack — it knows which containers belong to which project and can interleave their output with service-name prefixes so you can tell at a glance which container printed what.

    This matters because most real applications aren’t a single container. A typical stack might include a web server, a database, a cache, and a background worker — four separate log streams that you’d otherwise have to tail individually with four terminal windows.

    Basic Syntax and Options

    The command follows this pattern:

    docker compose logs [OPTIONS] [SERVICE...]

    Run it with no arguments from the directory containing your docker-compose.yml and you’ll get the full log history for every service in the project:

    docker compose logs

    To scope it to one or more services, just name them:

    docker compose logs web db

    Following Logs in Real Time

    Static output is useful for a quick check, but during active debugging you want a live stream. Use -f or --follow:

    docker compose logs -f web

    This behaves like tail -f — new log lines appear as they’re written, and the command keeps running until you press Ctrl+C. This is the single most-used flag in the docker compose logs toolkit, and it’s usually the first thing you run after docker compose up -d.

    Filtering Logs by Service

    When you’re running several services and only care about one, always scope by service name rather than grepping through the combined output:

    docker compose logs -f --tail=100 api

    You can also pass multiple service names at once to watch related containers together, which is handy when debugging an interaction between, say, a frontend proxy and its backend API.

    Limiting Log Output with –tail

    By default, docker compose logs prints the entire buffered history, which can be enormous for long-running containers. The --tail flag limits output to the last N lines:

    docker compose logs --tail=50 web

    Combine it with -f to see recent context and then continue following:

    docker compose logs -f --tail=50 web

    Advanced Log Filtering Techniques

    Timestamps and Time Ranges

    Add -t (or --timestamps) to prefix every line with an ISO 8601 timestamp — essential when correlating log events with an incident timeline:

    docker compose logs -t web

    To narrow output to a specific window, use --since and --until:

    docker compose logs --since 2026-07-08T10:00:00 --until 2026-07-08T10:15:00 web

    You can also use relative durations like --since 30m or --since 2h, which is often faster than typing out a full timestamp when you’re chasing something that just happened.

    Combining Logs with grep

    docker compose logs doesn’t have a built-in search flag, but because it writes to stdout, you can pipe it straight into standard Unix tools:

    docker compose logs --no-color web | grep -i "error"

    The --no-color flag strips ANSI color codes so your grep matches aren’t broken up by escape sequences. This pattern — Compose logs piped into grep, awk, or jq (for JSON-formatted app logs) — covers the vast majority of manual debugging you’ll ever need to do.

    Handling Logs for Scaled Services

    If you’re running multiple replicas of a service with docker compose up --scale worker=3, docker compose logs worker interleaves output from all three containers, each prefixed with its own container name so you can tell them apart. This is useful for spotting whether a bug affects every replica or just one — a single misbehaving replica often points to a stuck connection or a stale cache entry rather than a code bug. If you need to isolate a single replica’s output, use docker ps to find its container ID and switch to plain docker logs <container_id> instead.

    Configuring Log Drivers in Docker Compose

    By default, Docker uses the json-file logging driver, which writes each container’s output to a JSON file on disk. That’s fine for development, but it has two problems in production: unbounded log files can fill your disk, and json-file logs disappear if the host is replaced.

    You can configure log rotation and an alternate driver per service directly in your docker-compose.yml:

    services:
      web:
        image: myapp:latest
        logging:
          driver: json-file
          options:
            max-size: "10m"
            max-file: "3"

    This caps each container’s log file at 10 MB and keeps a maximum of 3 rotated files, which prevents runaway disk usage — a surprisingly common cause of production outages that has nothing to do with your application code.

    For teams that need durable, searchable logs, switching to a shipping-friendly driver like journald or syslog, or running a sidecar log forwarder, is the next step. That’s a bigger topic than this article can fully cover, but if you’re already tuning Docker networking for multi-container apps, log driver configuration belongs in the same pass.

    Centralizing Logs for Production

    docker compose logs is a local debugging tool — it reads whatever the log driver has retained on that specific host. That’s a real limitation once you’re running more than one server, since logs vanish when a container is removed or a host is rebuilt. For production stacks, you want logs shipped somewhere durable and searchable.

    A few practical options:

  • Log shipping agents like Filebeat, Fluentd, or Vector can tail the Docker log directory and forward entries to a central store.
  • Managed log platforms such as BetterStack give you searchable, alertable log aggregation without running your own Elasticsearch cluster — worth evaluating if you’re outgrowing docker compose logs -f as your primary debugging tool.
  • Cloud-native logging — if you’re hosting on a VPS, pairing your Compose stack with a provider like DigitalOcean makes it straightforward to attach block storage for log retention or spin up a dedicated logging droplet.
  • Structured logging — configure your application to emit JSON logs so downstream tools can parse fields instead of regex-matching plain text.
  • If you’re just getting started with Compose in general, our Docker Compose restart policies guide is a good companion piece — restart behavior and logging are usually the first two things you tune once a stack graduates from “works on my machine” to “runs in production.”

    For the official reference on every driver and option, the Docker documentation on logging drivers covers configuration syntax that’s easy to get subtly wrong, particularly around driver-specific options that Compose passes through without validation.

    Rotating Logs Automatically

    Log rotation deserves its own callout because it’s the most commonly skipped step. Without max-size and max-file set, json-file logs grow forever. On a busy service, that can mean gigabytes of logs eating disk space within days. Add rotation to every service in your Compose file, not just the noisy ones — the quiet services are the ones nobody remembers to check until the disk is full.

    Using docker compose logs in CI/CD Pipelines

    CI runners are another place docker compose logs earns its keep. When an integration test fails inside a containerized service, the test runner has usually already exited before you can attach a terminal. The fix is to dump logs as a post-failure step in your pipeline configuration, for example in a GitHub Actions job:

    - name: Dump logs on failure
      if: failure()
      run: docker compose logs --no-color > compose-output.log

    Running this on failure means you get the full container output attached to the CI job log, instead of a bare “test failed” message with no context. This one habit saves more debugging time than almost any other logging practice on this list.

    Common Issues and Troubleshooting

    A few problems come up often enough to call out specifically:

  • “No such service” error — you named a service that doesn’t exist in docker-compose.yml, or you’re running the command from the wrong directory. docker compose logs only sees services defined in the compose file in your current working directory (or the one passed via -f).
  • Logs appear empty or truncated — check the container’s log driver. If it’s set to none or a non-default driver like syslog without local buffering, docker compose logs won’t have anything to show, since it reads from the driver’s local output, not the application directly.
  • Color codes cluttering piped output — always add --no-color when piping into grep, awk, or a file.
  • Logs missing after container restart — by default, Docker keeps logs from the current container instance. If a container was recreated (not just restarted), previous logs may be gone unless you’re shipping them elsewhere.
  • Interleaved output is hard to read — when following multiple services at once, each line is prefixed with the service name and color-coded in an interactive terminal, but this can still get noisy with high-throughput services. Narrow to one service when you need to focus.
  • Comparing docker logs vs docker compose logs

    It’s worth being explicit about the difference, since the two commands look similar but aren’t interchangeable:

    docker logs my_container_1
    docker compose logs my_service

    docker logs operates on a single container by name or ID and knows nothing about Compose projects. docker compose logs operates on services defined in your compose file and can span multiple containers per service if you’re running replicas. If you only remember one rule, remember this: use docker compose logs when you’re thinking in terms of your application’s services, and docker logs when you’re debugging one specific container instance.

    Recommended: Ready to put this into practice? DigitalOcean is a tool we use for exactly this, and we have a real, disclosed affiliate relationship with them.

    FAQ

    Q: How do I see logs for only one service in a multi-service Compose stack?
    A: Pass the service name as an argument: docker compose logs web. You can list multiple service names separated by spaces to watch several at once.

    Q: How do I follow logs in real time?
    A: Add the -f or --follow flag: docker compose logs -f. Press Ctrl+C to stop following.

    Q: Why does docker compose logs show no output at all?
    A: Usually because the container isn’t running, the log driver is set to something that doesn’t retain local output (like none), or you’re running the command outside the directory containing your docker-compose.yml.

    Q: Can I export docker compose logs to a file?
    A: Yes — redirect stdout: docker compose logs --no-color > app.log. Use --no-color first so the file doesn’t contain ANSI escape codes.

    Q: How do I limit how much log history is shown?
    A: Use --tail=N to show only the last N lines per service, or --since to restrict output to a time window.

    Q: Does docker compose logs work after a container has stopped?
    A: Yes, as long as the container hasn’t been removed. Docker retains the log file for stopped containers until they’re deleted with docker compose down or docker rm.

    Wrapping Up

    The docker compose logs command is the fastest path from “something’s wrong” to “here’s why.” Start with -f and --tail for everyday debugging, add --since and -t when you need to correlate events with a timeline, and don’t skip log rotation once you’re running anything in production. When local log files stop being enough, that’s your signal to invest in centralized, searchable logging rather than scrolling through terminal history.

  • AI Agent Platforms: Self-Hosting Guide for DevOps Teams

    AI Agent Platforms: A Practical Self-Hosting Guide for Developers

    Disclosure: This post contains one or more links to providers we have a real, registered affiliate/referral relationship with. We may earn a commission at no extra cost to you if you sign up through them.

    AI agent platforms have moved from research demos to production infrastructure. If you run a homelab, manage a small SaaS, or just want an LLM-powered agent that isn’t locked behind a third-party API with rate limits and unpredictable pricing, self-hosting is now a realistic option. This guide walks through what AI agent platforms actually are, how the major open-source options compare, and how to deploy one with Docker on a Linux VPS.

    What Is an AI Agent Platform?

    An AI agent platform is software that wraps a large language model (LLM) with tools, memory, and orchestration logic so it can complete multi-step tasks autonomously — calling APIs, running code, querying databases, or chaining multiple agents together. Unlike a simple chatbot, an agent platform typically provides:

  • A task/planning loop (the agent decides what to do next based on prior results)
  • Tool/function calling (web search, shell execution, API calls)
  • Memory persistence (vector databases or key-value stores)
  • Multi-agent orchestration (agents delegating subtasks to other agents)
  • An API or UI for triggering and monitoring runs
  • Popular options developers are self-hosting right now include AutoGen, CrewAI, LangGraph, and n8n (which added agent nodes on top of its existing workflow engine). Each has a different philosophy, and the right choice depends on whether you need strict orchestration control, rapid prototyping, or a low-code interface for non-developers on your team.

    Why Self-Host Instead of Using a SaaS Agent Platform

    Managed agent platforms (hosted versions of the tools above, or newer commercial offerings) are convenient, but they come with tradeoffs that matter for production DevOps work:

  • Data residency — agent runs often touch sensitive internal data (logs, customer records, infra credentials). Keeping that on infrastructure you control matters for compliance.
  • Cost predictability — SaaS agent platforms typically bill per-run or per-token on top of your LLM API costs, which compounds fast at scale.
  • Latency and reliability — self-hosted agents on your own network reduce round trips to third-party orchestration layers.
  • Customization — you can swap models, add custom tools, and modify the planning loop without waiting on a vendor’s roadmap.
  • If you’re already running services on a VPS provisioning workflow for other Dockerized apps, adding an agent platform is a natural extension rather than a new operational burden.

    Comparing the Major Self-Hostable Agent Frameworks

    Here’s a quick breakdown for developers evaluating options:

    | Platform | Best for | Orchestration model | Language |
    |—|—|—|—|
    | AutoGen | Multi-agent research, complex reasoning chains | Conversational agents talking to each other | Python |
    | CrewAI | Role-based agent teams (e.g., researcher + writer + reviewer) | Sequential/hierarchical crews | Python |
    | LangGraph | Fine-grained control over agent state machines | Graph-based state transitions | Python/TS |
    | n8n | Ops teams wanting a visual builder with agent nodes bolted onto existing automations | Workflow + agent hybrid | Node.js |

    For most DevOps teams already comfortable with Docker Compose, n8n or CrewAI are the fastest path to something running in production because both ship official container images and don’t require you to hand-roll a serving layer.

    Deploying an AI Agent Platform with Docker

    Below is a working example using CrewAI wrapped in a minimal FastAPI service, containerized and run behind Nginx on a Linux VPS. This pattern generalizes to any of the frameworks above — swap the Python service logic and keep the same container/reverse-proxy structure.

    Step 1: Project Structure and Dependencies

    mkdir agent-platform && cd agent-platform
    mkdir app
    touch app/main.py app/requirements.txt Dockerfile docker-compose.yml

    # app/requirements.txt
    fastapi==0.111.0
    uvicorn[standard]==0.30.1
    crewai==0.41.1
    openai==1.35.10
    python-dotenv==1.0.1

    Step 2: A Minimal Agent Service

    # app/main.py
    import os
    from fastapi import FastAPI
    from pydantic import BaseModel
    from crewai import Agent, Task, Crew
    
    app = FastAPI()
    
    researcher = Agent(
        role="Researcher",
        goal="Find accurate, current information on a given topic",
        backstory="An analyst who verifies facts before summarizing.",
        verbose=False,
    )
    
    class AgentRequest(BaseModel):
        topic: str
    
    @app.post("/run")
    def run_agent(req: AgentRequest):
        task = Task(
            description=f"Research the topic: {req.topic}. Return a concise summary.",
            agent=researcher,
            expected_output="A 3-paragraph summary with cited sources.",
        )
        crew = Crew(agents=[researcher], tasks=[task])
        result = crew.kickoff()
        return {"topic": req.topic, "result": str(result)}
    
    @app.get("/health")
    def health():
        return {"status": "ok"}

    Step 3: Dockerfile

    FROM python:3.11-slim
    
    WORKDIR /app
    COPY app/requirements.txt .
    RUN pip install --no-cache-dir -r requirements.txt
    
    COPY app/ .
    
    EXPOSE 8000
    CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

    Step 4: docker-compose.yml with Environment Isolation

    version: "3.9"
    services:
      agent-api:
        build: .
        container_name: agent-platform
        restart: unless-stopped
        env_file:
          - .env
        ports:
          - "127.0.0.1:8000:8000"
        networks:
          - agent-net
    
    networks:
      agent-net:
        driver: bridge

    Note the API is bound to 127.0.0.1 only — you should never expose an agent’s raw API port directly to the internet. Put it behind a reverse proxy with TLS and authentication, which we cover next.

    # .env (never commit this file)
    OPENAI_API_KEY=sk-your-key-here

    Bring it up:

    docker compose build
    docker compose up -d
    curl -X POST http://127.0.0.1:8000/run -H "Content-Type: application/json" 
      -d '{"topic": "latest trends in container orchestration"}'

    Step 5: Reverse Proxy and Access Control

    Agent platforms execute arbitrary tool calls, which makes them a higher-value target than a typical CRUD API. At minimum, put Nginx in front with basic auth or an API key check, and restrict rate limits:

    server {
        listen 443 ssl;
        server_name agent.yourdomain.com;
    
        ssl_certificate /etc/letsencrypt/live/agent.yourdomain.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/agent.yourdomain.com/privkey.pem;
    
        location / {
            auth_basic "Restricted";
            auth_basic_user_file /etc/nginx/.htpasswd;
            limit_req zone=agentlimit burst=10 nodelay;
            proxy_pass http://127.0.0.1:8000;
            proxy_set_header Host $host;
        }
    }

    For production monitoring of the container’s health and resource usage, pair this with an uptime checker — we’ve covered lightweight monitoring stacks in our Docker container monitoring guide, which applies directly to agent workloads since they can spike CPU/memory unpredictably during long reasoning chains.

    Handling Secrets and Tool Permissions Safely

    Agent platforms frequently need credentials for the tools they call — a database connection string, a cloud API key, or shell access. Treat every credential passed to an agent as if it could be exfiltrated, because a sufficiently manipulated prompt can trick an agent into leaking data it has access to. Practical mitigations:

  • Run agent containers with a non-root user and a read-only filesystem where possible
  • Scope API keys to the minimum permissions the agent’s tools actually need
  • Never give an agent direct shell access to a container that also holds production secrets
  • Log every tool call the agent makes for auditability
  • Use short-lived tokens instead of long-lived API keys when the underlying service supports it
  • # Hardened Dockerfile additions
    RUN useradd -m -u 1001 agentuser
    USER agentuser

    If your agent platform needs to persist memory between runs, avoid storing it in plaintext on the container filesystem. A managed Postgres instance with pgvector, or a dedicated vector database, is a safer and more scalable choice than local disk.

    Scaling Beyond a Single VPS

    Once a single agent instance proves out, teams typically hit two walls: concurrent request handling and cost of LLM calls at scale. For the former, horizontal scaling behind a load balancer works the same way it does for any stateless API — just make sure agent memory/state lives in shared storage (Redis or Postgres), not in-process. For the latter, review your provider’s token pricing carefully; agentic workflows can call the LLM 5-20x per task depending on how many reasoning steps and tool calls are involved.

    If you’re evaluating where to host this stack, a VPS with dedicated vCPUs handles agent workloads noticeably better than burstable/shared instances, since reasoning loops are CPU and memory intensive during tool execution. Providers like DigitalOcean offer straightforward Docker-ready droplets that work well for this, and Hetzner is a solid budget option if you’re running this as a side project rather than a funded product.

    Recommended: Ready to put this into practice? DigitalOcean is a tool we use for exactly this, and we have a real, disclosed affiliate relationship with them.

    FAQ

    Q: Do I need a GPU to self-host an AI agent platform?
    A: No, in most cases. The orchestration layer (CrewAI, AutoGen, LangGraph) runs fine on a standard CPU VPS since the actual LLM inference happens via API call to OpenAI, Anthropic, or another provider. You only need local GPU compute if you’re also self-hosting the underlying model.

    Q: Which AI agent platform is easiest for a first deployment?
    A: CrewAI or n8n. Both have official Docker images and require less boilerplate than AutoGen or LangGraph, which expose more low-level control but demand more setup.

    Q: Is it safe to give an agent shell access on my server?
    A: Only in an isolated, disposable container with no access to production secrets or networks. Treat shell-enabled agents the same way you’d treat an untrusted CI job.

    Q: How much does it cost to run an AI agent platform in production?
    A: Infrastructure cost is usually small (a $10-40/month VPS is plenty). The real cost driver is LLM API usage, since agentic tasks can trigger many model calls per run — monitor token usage closely in the first few weeks.

    Q: Can I run multiple agent platforms on the same VPS?
    A: Yes, as long as each runs in its own container with isolated networks and resource limits set via Docker Compose or docker run --memory/--cpus flags, to prevent one agent’s workload from starving the others.

    Q: Do these frameworks support open-source/local LLMs instead of OpenAI?
    A: Yes — AutoGen, CrewAI, and LangGraph all support local models via Ollama or any OpenAI-compatible endpoint, which is worth exploring if API costs or data residency are a concern.

    Wrapping Up

    Self-hosting an AI agent platform is no longer an experimental weekend project — it’s a viable production pattern for teams that want control over cost, data, and customization. Start small with a single containerized agent behind a reverse proxy, harden the credential handling early, and scale the orchestration layer only once you’ve validated the workload pattern. The Docker fundamentals here are identical to any other service you’ve already deployed; the main difference is treating the agent’s tool permissions with the same care you’d give a CI pipeline with production access.

    If you’re setting this up alongside other self-hosted services, our self-hosted Docker stack guide covers the broader reverse-proxy and TLS patterns referenced above in more depth.

  • No Code AI Agent Builder: Self-Host Guide 2026

    No Code AI Agent Builder: A Self-Hosted, Docker-First Guide for Developers

    Disclosure: This post contains one or more links to providers we have a real, registered affiliate/referral relationship with. We may earn a commission at no extra cost to you if you sign up through them.

    Every week another SaaS company ships a “no code AI agent builder” with a slick drag-and-drop canvas and a pricing page that scales badly the moment you have real usage. If you’re a developer or sysadmin, you don’t need the SaaS wrapper — you need the underlying workflow engine, running on infrastructure you control, with logs you can actually read at 2 AM when something breaks.

    This guide covers what a no code AI agent builder actually is under the hood, which self-hostable platforms are worth your time in 2026, and how to deploy one on a VPS with Docker, connect it to an LLM API, and keep it monitored and secure. No proprietary black boxes, no per-execution billing surprises.

    What Is a No Code AI Agent Builder?

    A no code AI agent builder is a visual workflow platform that lets you chain together triggers, LLM calls, tool integrations, and conditional logic without writing custom application code. Under the hood, most of these tools are just orchestration engines — they take a JSON or YAML definition of nodes and edges, execute them in sequence or parallel, and expose the whole thing through a web UI so non-engineers (and busy engineers) can wire up automations quickly.

    The “agent” part means the workflow can reason, call tools, and make decisions using a large language model rather than following a purely static script. A support ticket triage bot, a research assistant that pulls from your internal wiki, or an on-call summarizer that pings Slack — these are all agents, and most of them don’t need custom Python to build.

    Why Developers Are Adopting No Code AI Agent Builders

    It’s tempting to assume “no code” is only for non-technical teams, but that’s not why this category has exploded. The real reasons developers reach for a no code AI agent builder:

  • Faster iteration — testing a prompt chain change takes seconds in a visual canvas versus a redeploy cycle.
  • Lower maintenance surface — the orchestration logic lives in a database record, not a repo you have to keep patched forever.
  • Easier handoff — ops and support teams can adjust workflows without opening a pull request.
  • Built-in observability — most platforms log every node execution, which beats grepping through custom logging you’d have to write yourself.
  • The tradeoff is control. If you use a hosted SaaS version, you’re renting someone else’s infrastructure and someone else’s uptime guarantees. That’s exactly why self-hosting the open-source versions of these tools is the better move for anyone comfortable with Docker.

    The Best Self-Hostable No Code AI Agent Builder Platforms

    A few platforms dominate the self-hosted space right now:

  • n8n — the most mature open-source workflow automation tool, with native AI agent nodes, LangChain integration, and a huge library of pre-built connectors.
  • Flowise — purpose-built for LLM chains and agents, with a canvas modeled closely on LangChain concepts.
  • Dify — combines a no-code agent builder with a hosted prompt IDE and built-in vector database support.
  • Langflow — another LangChain-native visual builder, popular for RAG pipeline prototyping.
  • All four ship official Docker images, which means you can run any of them on a single VPS in under ten minutes. For most teams building their first internal automation, n8n is the safest starting point because of its connector ecosystem and active community — but if you’re building LLM-specific agents exclusively, Flowise or Dify will feel more purpose-fit.

    If you’re also running Docker-based media or streaming services on the same host, it’s worth reviewing our Docker Compose guide for beginners first so your networking and volume conventions stay consistent across stacks.

    Self-Hosting Your No Code AI Agent Builder with Docker

    Here’s a minimal docker-compose.yml to get n8n running with persistent storage and a Postgres backend, which you’ll want once you go beyond a handful of workflows:

    version: "3.8"
    
    services:
      postgres:
        image: postgres:16
        restart: unless-stopped
        environment:
          POSTGRES_USER: n8n
          POSTGRES_PASSWORD: ${DB_PASSWORD}
          POSTGRES_DB: n8n
        volumes:
          - postgres_data:/var/lib/postgresql/data
    
      n8n:
        image: n8nio/n8n:latest
        restart: unless-stopped
        ports:
          - "5678:5678"
        environment:
          DB_TYPE: postgresdb
          DB_POSTGRESDB_HOST: postgres
          DB_POSTGRESDB_DATABASE: n8n
          DB_POSTGRESDB_USER: n8n
          DB_POSTGRESDB_PASSWORD: ${DB_PASSWORD}
          N8N_HOST: agents.yourdomain.com
          N8N_PROTOCOL: https
          WEBHOOK_URL: https://agents.yourdomain.com/
          GENERIC_TIMEZONE: UTC
        volumes:
          - n8n_data:/home/node/.n8n
        depends_on:
          - postgres
    
    volumes:
      postgres_data:
      n8n_data:

    Store your database password in a .env file next to the compose file rather than hardcoding it:

    echo "DB_PASSWORD=$(openssl rand -base64 24)" > .env
    docker compose up -d

    That’s the entire backend. No code was written — just infrastructure declared.

    Step-by-Step: Deploying a No Code AI Agent Builder on a VPS

    Once Docker and Compose are installed on your VPS, the deployment flow looks like this:

    1. Provision a VPS with at least 2 vCPUs and 4GB RAM — LLM-backed workflows are memory-hungry once you add vector store nodes.
    2. Point a DNS A record at the server and put a reverse proxy (Caddy or Traefik) in front of it for automatic TLS.
    3. Copy the docker-compose.yml above onto the server and run docker compose up -d.
    4. Log in to the n8n UI, create your owner account, and generate an API credential for your LLM provider (OpenAI, Anthropic, or a self-hosted model via Ollama).
    5. Build your first agent workflow: a trigger node, an AI Agent node with your chosen model, and an output action (Slack message, database write, or webhook response).

    A basic Caddy config for TLS termination is just three lines:

    agents.yourdomain.com {
        reverse_proxy localhost:5678
    }

    Caddy handles Let’s Encrypt certificate issuance and renewal automatically — no cron job, no certbot script to maintain.

    Connecting Your Agent to External APIs and LLMs

    The real power of a no code AI agent builder shows up once you start chaining tool calls. A typical support-triage agent might:

  • Receive a webhook from your helpdesk when a new ticket is created.
  • Call an LLM node to classify urgency and topic.
  • Query an internal API or database for related documentation.
  • Post a summarized response back to Slack or the ticketing system.
  • Each of these is a drag-and-drop node with credentials stored centrally, encrypted at rest. If you’re already running a home theater or streaming review pipeline, the same pattern applies — for example, an agent that watches an RSS feed for new device firmware releases and drafts a summary for your editorial team, similar to the automation we describe in our self-hosted VPS setup walkthrough.

    Monitoring and Securing Your AI Agent Stack

    A no code AI agent builder is still a production service the moment it’s handling real workflows, and it deserves the same rigor as any other app on your VPS.

    Monitoring Your AI Agent Builder in Production

    At minimum, track:

  • Uptime of the web UI and webhook endpoints.
  • Execution failures — most platforms expose a REST API or webhook you can pipe into an alerting tool.
  • Resource usage — LLM nodes can spike memory when processing large context windows.
  • API rate limits on whatever model provider you’re calling.
  • A lightweight uptime and status-page tool like BetterStack plugs in well here — point it at your n8n health check endpoint and you’ll get paged the moment the container crashes or the reverse proxy drops.

    For infrastructure, don’t run this on a cheap shared host you’re also using for anything customer-facing. A dedicated small VPS from DigitalOcean or a cost-efficient dedicated box from Hetzner gives you enough headroom to run Postgres, the agent builder, and a reverse proxy without contention. If your agents are publicly reachable via webhook, put Cloudflare in front for DDoS protection and to hide your origin IP.

    Security basics that are easy to skip but shouldn’t be:

  • Put the agent builder’s admin UI behind basic auth or a VPN, not just the app’s own login.
  • Rotate API keys stored as credentials inside the platform on a schedule.
  • Restrict outbound webhook destinations with an allowlist if your platform supports it.
  • Back up the workflow database — losing years of built agents to a disk failure is avoidable with a nightly pg_dump cron job.
  • 0 3 * * * docker exec postgres pg_dump -U n8n n8n | gzip > /backups/n8n-$(date +%F).sql.gz

    If you’re also optimizing content around this stack for organic traffic, a rank-tracking tool like SE Ranking can help you validate which agent-builder comparison keywords are actually worth targeting before you invest more writing time.

    Choosing the Right No Code AI Agent Builder for Your Team

    There’s no single best answer — it depends on what you’re automating:

  • If you need broad connector coverage (CRMs, Slack, databases, email), go with n8n.
  • If you’re building strictly LLM/RAG-heavy agents, Flowise or Dify will save setup time.
  • If your team already lives in LangChain code and just wants a visual layer on top, Langflow is the closest match.
  • Whichever you pick, self-hosting via Docker means you can migrate between them later without re-architecting your infrastructure — the compose file and reverse proxy pattern stays nearly identical.

    Recommended: Ready to put this into practice? SE Ranking is a tool we use for exactly this, and we have a real, disclosed affiliate relationship with them.

    FAQ

    Is a no code AI agent builder the same as a chatbot builder?
    No. Chatbot builders are typically limited to conversational front-ends, while an agent builder can trigger on any event (webhook, schedule, database change) and take autonomous multi-step actions, not just reply to messages.

    Do I need to know how to code to use one?
    Not for basic workflows. But knowing Docker, basic networking, and reading JSON payloads will get you much further when debugging failed executions or writing custom expressions inside nodes.

    Can I self-host a no code AI agent builder for free?
    Yes — n8n, Flowise, Dify, and Langflow are all open source and free to self-host. You only pay for your VPS and whatever LLM API calls the agents make.

    How much does the LLM API cost add up to?
    It depends entirely on model choice and volume. Using a cheaper model for classification steps and reserving expensive models for final generation steps typically cuts costs by more than half.

    Is it safe to expose these tools to the public internet?
    Only the webhook endpoints should be public, and even then behind a CDN/WAF like Cloudflare. Keep the admin dashboard restricted to a VPN or IP allowlist.

    What’s the biggest mistake teams make with these platforms?
    Treating them as toys instead of production services — skipping backups, monitoring, and credential rotation until after an incident forces the issue.

    Final Thoughts

    A no code AI agent builder gives you the speed of visual workflow design without giving up the control you get from running your own infrastructure. Start with n8n or Flowise on a small VPS, put Docker Compose and a reverse proxy in front of it, and treat the stack with the same monitoring and backup discipline you’d apply to any other production service. The visual canvas is the easy part — the operational discipline around it is what actually keeps your agents reliable.

  • AI Agents for Business: Self-Hosted Deployment Guide

    AI Agents for Business: A Practical DevOps Deployment Guide

    Disclosure: This post contains one or more links to providers we have a real, registered affiliate/referral relationship with. We may earn a commission at no extra cost to you if you sign up through them.

    Every vendor pitch deck in 2026 has a slide about AI agents for business — autonomous workflows that triage tickets, write code, manage infrastructure, or handle customer support without a human in the loop. What most of those decks skip is the part engineering teams actually have to deal with: how do you run these agents reliably, keep them secure, and avoid a surprise five-figure API bill? This guide covers the deployment side of AI agents for business, from container architecture to monitoring, written for developers and sysadmins who have to ship and operate this stuff, not just demo it.

    What “AI Agents for Business” Actually Means in Production

    An AI agent, in the production sense, is a process that takes a goal, calls a language model to decide on next steps, executes tools (API calls, shell commands, database queries), and loops until the goal is met or it hits a limit. That’s a very different system from a chatbot. Agents have state, they take actions with side effects, and they need the same operational discipline you’d apply to any other service that touches production data.

    Autonomous vs. Assisted Agents

    Before you write a line of deployment code, decide which pattern you’re building:

  • Assisted agents propose an action and wait for human approval — good for anything touching money, customer data, or infrastructure changes.
  • Autonomous agents execute without a human in the loop — appropriate for low-risk, reversible tasks like log summarization or internal documentation updates.
  • Hybrid agents run autonomously within a scoped permission set and escalate anything outside it.
  • Most businesses starting out should default to assisted or tightly-scoped hybrid agents. The failure mode of a fully autonomous agent with broad tool access is not “it makes a typo” — it’s “it deletes a production table” or “it emails a customer something you can’t unsend.”

    Where Self-Hosting Beats SaaS Agent Platforms

    Hosted agent platforms are fine for prototyping, but three things push serious teams toward self-hosting:

  • Data residency and compliance — you can’t send customer PII through a third-party agent platform if your contracts or regulations forbid it.
  • Cost at scale — per-seat or per-call SaaS pricing gets expensive fast once agents are running continuously rather than on-demand.
  • Control over the model and tool layer — self-hosting lets you swap models, pin versions, and audit exactly what tools an agent can call.
  • If none of those apply to you yet, a managed platform might be the faster path. If any of them do, keep reading.

    Core Architecture for Self-Hosted AI Agents

    A production agent stack has four layers: the model backend, the orchestration/agent framework, the tool/API layer, and the infrastructure it all runs on. Treating these as separate, independently deployable containers is what makes the system maintainable.

    The Container Stack

    A minimal but realistic stack uses Docker Compose to wire together a local LLM backend (or a proxy to a hosted model), an agent orchestration service, and a vector store for retrieval-augmented context. Here’s a working starting point:

    # docker-compose.yml
    version: "3.9"
    services:
      ollama:
        image: ollama/ollama:latest
        volumes:
          - ollama_data:/root/.ollama
        ports:
          - "11434:11434"
        deploy:
          resources:
            reservations:
              devices:
                - driver: nvidia
                  count: 1
                  capabilities: [gpu]
    
      vectordb:
        image: qdrant/qdrant:latest
        volumes:
          - qdrant_data:/qdrant/storage
        ports:
          - "6333:6333"
    
      agent:
        build: ./agent
        depends_on:
          - ollama
          - vectordb
        environment:
          - MODEL_HOST=http://ollama:11434
          - VECTOR_HOST=http://vectordb:6333
          - LOG_LEVEL=info
        restart: unless-stopped
    
      caddy:
        image: caddy:2-alpine
        ports:
          - "443:443"
          - "80:80"
        volumes:
          - ./Caddyfile:/etc/caddy/Caddyfile
          - caddy_data:/data
    
    volumes:
      ollama_data:
      qdrant_data:
      caddy_data:

    This follows the same pattern we cover in our Docker Compose fundamentals guide — each concern gets its own container, and the agent service itself is stateless so you can scale it horizontally behind the reverse proxy. For the full Compose networking and volume options, the official Docker Compose documentation is worth bookmarking.

    Deploying Your First Agent Stack

    With the Compose file in place, bring the stack up and pull a model into the local backend:

    # Bring up the stack
    docker compose up -d
    
    # Pull a model into the local LLM backend
    docker exec -it $(docker compose ps -q ollama) ollama pull llama3.1:8b
    
    # Verify the agent service is healthy
    curl -s http://localhost:8080/health | jq
    
    # Tail logs while you run a test task
    docker compose logs -f agent

    For teams that don’t want to manage GPU infrastructure, Ollama also supports running against smaller quantized models on CPU, which is often good enough for business-process agents that don’t need frontier-model reasoning — think ticket classification or data extraction rather than open-ended coding.

    The agent service itself should expose a small, explicit set of tools rather than unrestricted shell or network access. A typical tool definition looks like this in Python:

    from agent_sdk import tool
    
    @tool(name="lookup_order", description="Fetch order details by ID")
    def lookup_order(order_id: str) -> dict:
        # Read-only, scoped to a single service account
        return orders_db.query("SELECT * FROM orders WHERE id = %s", [order_id])
    
    @tool(name="refund_order", description="Issue a refund, requires human approval")
    def refund_order(order_id: str, amount: float, approved_by: str) -> dict:
        if not approved_by:
            raise PermissionError("Refunds require human approval")
        return payments_api.refund(order_id, amount)

    Notice the second tool enforces an approval gate at the function level, not just in a prompt. Prompts can be manipulated; code paths can’t.

    Monitoring, Logging, and Uptime

    Agents fail differently than normal web services — they can loop, hallucinate a tool call that doesn’t exist, or silently stall waiting on a model response. Standard uptime monitoring isn’t enough on its own. You need:

  • Uptime checks on the agent API endpoint and the model backend independently, so you know which layer failed.
  • Loop and cost alerts — track token usage per task and alert if a single run exceeds a threshold, which usually indicates a runaway loop.
  • Structured logging of every tool call, its inputs, and its output, so you can reconstruct exactly what an agent did after the fact.
  • Latency percentiles, not just averages — agent tasks have high variance, and p95/p99 latency tells you far more than a mean.
  • We run our own agent workloads with BetterStack for uptime and log aggregation — it’s a solid fit here because it handles both incident alerting and structured log search without stitching together three separate tools, and our self-hosted monitoring walkthrough goes deeper into wiring it up alongside Prometheus for container-level metrics.

    Security and Compliance Considerations

    Treat agent tool access the same way you’d treat a service account’s IAM permissions — least privilege, scoped, and audited.

  • Never give an agent’s shell tool access to a production host directly; route it through a constrained execution sandbox.
  • Log every prompt and every tool call with enough context to reconstruct an incident during a post-mortem.
  • Rate-limit and cost-cap the model backend so a misbehaving agent can’t run up a bill or hammer an upstream API.
  • Put the agent’s public-facing endpoint behind a WAF and DDoS protection — Cloudflare is a common choice here since it also handles TLS termination for the reverse proxy layer.
  • Review the OWASP Top 10 for LLM Applications before going to production; prompt injection and excessive agency are the two risks most teams underestimate.
  • If your business handles regulated data, map your agent’s tool permissions against your compliance framework before launch, not after. Retrofitting audit logging into an agent that’s already handling customer data is far more painful than building it in from day one.

    Scaling on Cloud Infrastructure

    Once the stack is stable locally, moving it to a VPS is mostly a matter of resources. GPU-backed instances are pricier but let you run larger local models; CPU-only instances work fine if you’re proxying to a hosted model API instead of self-hosting the LLM itself.

  • DigitalOcean is a good default for teams that want managed Kubernetes or simple droplets with predictable pricing and fast provisioning.
  • Hetzner offers some of the best price-to-performance on dedicated and cloud servers in Europe, which matters if your agent workloads are compute-heavy and running continuously.
  • Either way, put your agent behind a reverse proxy with TLS from day one, and keep the model backend on an internal network, never exposed directly to the internet.

    Recommended: Ready to put this into practice? DigitalOcean is a tool we use for exactly this, and we have a real, disclosed affiliate relationship with them.

    FAQ

    Do AI agents for business need a GPU to run?
    Not always. Smaller quantized models run fine on CPU for classification, extraction, and routing tasks. GPUs matter when you need larger models for complex reasoning or code generation, or when latency under load is critical.

    Is it safer to self-host or use a hosted agent API?
    Self-hosting gives you more control over data residency and tool permissions, but you own the operational burden — patching, scaling, and monitoring. Hosted APIs shift that burden to the vendor but require you to trust their data handling. Choose based on your compliance requirements, not just cost.

    How do I stop an agent from looping forever?
    Set a hard step limit and a token budget per task at the orchestration layer, not just in the prompt. Combine that with cost alerts so a runaway loop triggers a page before it becomes a bill.

    Can AI agents for business replace existing automation tools?
    Usually not entirely. Agents are best for tasks with ambiguous inputs that benefit from reasoning — triage, summarization, drafting. Deterministic workflows (payroll runs, scheduled reports) are still better served by traditional automation because they’re cheaper and more predictable.

    What’s the biggest mistake teams make deploying their first agent?
    Giving the agent too much tool access too early. Start with read-only tools, add write access incrementally, and gate anything irreversible behind human approval until you have solid logging and enough production history to trust the failure modes.

    How much does it cost to run a self-hosted agent stack?
    For a small internal agent handling a few hundred tasks a day on a CPU-only VPS, expect somewhere in the $20–80/month range for infrastructure alone, excluding any hosted model API costs if you’re not running the LLM locally. GPU-backed setups for larger models scale up from there depending on instance size and uptime.

    Deploying AI agents for business isn’t fundamentally different from deploying any other production service — it just adds a nondeterministic decision-making layer on top of your usual container, networking, and monitoring stack. Get the boring parts right — scoped permissions, structured logging, cost caps, and real uptime monitoring — and the agent layer becomes far easier to trust in production.

  • AI Agents Companies: Top Platforms for DevOps 2026

    AI Agents Companies: A DevOps Guide to Evaluating and Self-Hosting Agent Platforms

    Disclosure: This post contains one or more links to providers we have a real, registered affiliate/referral relationship with. We may earn a commission at no extra cost to you if you sign up through them.

    Autonomous AI agents have moved from research demos to production workloads faster than most infrastructure teams expected. If you’re a developer or sysadmin trying to figure out which AI agents companies are worth building on — and whether to run their stack yourself or hand it off to a managed service — this guide is for you. We’ll cover the current landscape, the tradeoffs between self-hosted and managed platforms, and give you working Docker configs to stand up an agent runtime on your own VPS.

    Why AI Agents Companies Matter for DevOps Teams

    An “AI agent” is software that can plan, call tools, and take multi-step actions toward a goal without a human clicking through every step. The companies building these platforms fall into two broad camps: infrastructure providers that give you the raw orchestration layer (LangChain, Microsoft AutoGen, CrewAI), and model providers that expose agentic capability directly through their APIs (Anthropic, OpenAI). Understanding which camp a vendor sits in matters more than the marketing copy, because it determines how much operational burden lands on your team.

    If you pick a pure orchestration framework, you’re responsible for hosting, scaling, logging, and securing the runtime — the framework just wires together the logic. If you pick a fully managed agent platform, you trade control for convenience and usually pay per-execution pricing that can balloon fast under heavy tool-calling workloads.

    The Rise of Autonomous Agent Platforms

    The shift started when function-calling and structured tool use became reliable enough that agents could chain API calls without constant human correction. Companies like LangChain built developer tooling around this early, followed by Microsoft’s AutoGen for multi-agent conversation patterns, and CrewAI for role-based agent teams. On the model side, Anthropic and OpenAI both ship native agentic tool-use APIs, which means you can skip a third-party orchestration layer entirely for simpler use cases.

    For DevOps teams, the practical question isn’t “which company has the flashiest demo” — it’s “which stack can I deploy, monitor, and roll back like any other production service.” That’s the lens we’ll use throughout this article.

    Self-Hosted vs Managed AI Agents Companies

    Here’s the tradeoff in plain terms:

  • Self-hosted (LangChain, AutoGen, CrewAI, open-source runtimes): Full control over data, logging, and cost. You own the ops burden — scaling, patching, secrets management, uptime.
  • Managed (vendor-hosted agent platforms): Faster to ship, someone else handles scaling and uptime, but you’re locked into their pricing model, rate limits, and data-handling policies.
  • Hybrid: Run your own orchestration layer (LangChain/AutoGen) on a VPS you control, but call out to managed model APIs (Anthropic, OpenAI) for the actual inference. This is the most common pattern we see in production DevOps environments today.
  • Most teams we’ve worked with land on hybrid, because it keeps infrastructure costs predictable while avoiding the operational nightmare of self-hosting large language models.

    Top AI Agents Companies to Evaluate in 2026

    A quick rundown of the platforms worth putting on your shortlist, organized by what they’re actually good at:

  • LangChain / LangGraph — best for building custom agent workflows with fine-grained control over state and tool routing.
  • Microsoft AutoGen — strong for multi-agent conversations where agents need to critique and refine each other’s output.
  • CrewAI — role-based agent orchestration, good fit if you’re modeling a team of specialized agents (researcher, writer, reviewer).
  • Anthropic (Claude API) — native agentic tool use with strong reliability on long-running multi-step tasks.
  • OpenAI (Assistants/Agents API) — mature ecosystem, broad plugin support, tightly integrated with their function-calling spec.
  • Open-Source vs Proprietary AI Agent Platforms

    Open-source frameworks like LangChain and AutoGen give you the source code, which means you can audit exactly what’s being sent to third-party APIs — critical if you’re handling sensitive data. Proprietary managed platforms abstract that away, which is fine for prototyping but can become a compliance headache once you’re processing customer data through an agent you can’t fully inspect.

    If your organization has any regulatory requirements around data residency or auditability, default to self-hosting the orchestration layer even if you’re calling a managed model API underneath. You get the audit trail without needing to run your own inference cluster.

    Deploying an AI Agent Stack on Your Own VPS

    Let’s get concrete. Below is a minimal but production-viable setup for running a LangChain-based agent service behind a reverse proxy, with logging and restart policies configured — the same way you’d deploy any other containerized service. If you haven’t containerized a service like this before, our Docker Compose guide covers the basics in more depth.

    Docker Compose Example for a Self-Hosted Agent Runtime

    # docker-compose.yml
    version: "3.9"
    
    services:
      agent-runtime:
        build: ./agent-runtime
        container_name: agent-runtime
        restart: unless-stopped
        environment:
          - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
          - AGENT_LOG_LEVEL=info
          - MAX_TOOL_CALLS_PER_RUN=15
        ports:
          - "127.0.0.1:8080:8080"
        volumes:
          - ./logs:/app/logs
        deploy:
          resources:
            limits:
              memory: 1g
              cpus: "1.0"
    
      caddy:
        image: caddy:2-alpine
        container_name: agent-proxy
        restart: unless-stopped
        ports:
          - "80:80"
          - "443:443"
        volumes:
          - ./Caddyfile:/etc/caddy/Caddyfile
          - caddy_data:/data
    
    volumes:
      caddy_data:

    A minimal Python entrypoint for the agent-runtime service using LangChain:

    # agent-runtime/main.py
    import os
    from fastapi import FastAPI, HTTPException
    from langchain_anthropic import ChatAnthropic
    from langchain.agents import AgentExecutor, create_tool_calling_agent
    from langchain_core.prompts import ChatPromptTemplate
    
    app = FastAPI()
    
    llm = ChatAnthropic(
        model="claude-sonnet-5",
        api_key=os.environ["ANTHROPIC_API_KEY"],
        max_tokens=1024,
    )
    
    prompt = ChatPromptTemplate.from_messages([
        ("system", "You are a DevOps assistant agent with access to tools."),
        ("human", "{input}"),
        ("placeholder", "{agent_scratchpad}"),
    ])
    
    @app.post("/run")
    async def run_agent(payload: dict):
        task = payload.get("task")
        if not task:
            raise HTTPException(status_code=400, detail="Missing 'task' field")
        response = llm.invoke(task)
        return {"result": response.content}

    Bring it up with:

    docker compose up -d --build
    docker compose logs -f agent-runtime

    Note the memory and CPU limits in the compose file — agent workloads can spike unpredictably during long tool-calling chains, and an unbounded container will happily eat your whole VPS. Set hard limits from day one.

    Monitoring and Securing Your AI Agents Infrastructure

    Agents that call external tools and APIs are a different security surface than a normal web app. A misconfigured agent can leak API keys into logs, make unbounded outbound requests, or get prompt-injected into taking actions you didn’t intend. Treat this the same way you’d treat any service with outbound network access: least privilege, rate limits, and centralized logging.

    Logging, Rate Limiting, and Cost Control

    Practical steps we recommend for any self-hosted agent deployment:

  • Cap MAX_TOOL_CALLS_PER_RUN (or equivalent) so a runaway agent loop can’t rack up API costs overnight.
  • Ship logs to a centralized system rather than trusting local container logs — if you don’t already have log aggregation in place, see our self-hosted monitoring stack guide.
  • Never let the agent process hold long-lived cloud credentials directly; scope API keys narrowly and rotate them.
  • Run the agent container as a non-root user and apply the same Linux server hardening practices you’d use for any internet-facing service.
  • Set outbound firewall rules so the agent can only reach the APIs it actually needs, not the entire internet.
  • For uptime monitoring on the agent endpoint itself, a lightweight external checker like BetterStack will alert you the moment the runtime stops responding — useful since agent processes can hang silently on a stuck tool call in a way a normal web request wouldn’t.

    Choosing the Right Infrastructure Provider

    Agent workloads are bursty — mostly idle, then a spike of CPU and memory during a multi-step run. A VPS with predictable flat-rate pricing beats pure serverless here, since agent runs can take minutes rather than seconds and serverless cold starts add latency to every tool call.

    We’ve run agent stacks like the one above on both DigitalOcean droplets and Hetzner cloud servers. DigitalOcean’s managed load balancers make it easy to scale the proxy layer horizontally if you’re running multiple agent replicas; Hetzner is the better pick if you’re cost-sensitive and want more RAM per dollar for the container memory limits mentioned above. Either way, put Cloudflare in front of the public endpoint — it absorbs abusive traffic before it ever reaches your agent runtime, which matters a lot when a single malicious request can trigger an expensive multi-step tool chain.

    Putting It All Together

    The AI agents companies landscape is consolidating around a hybrid pattern: self-hosted orchestration for control and auditability, managed model APIs for the actual inference. That split gives DevOps teams the best of both worlds — you’re not running your own GPU cluster, but you retain full visibility into what the agent is doing and full control over the deployment lifecycle. Start small: one containerized agent service, hard resource limits, centralized logging, and a firewall that only allows the outbound calls you actually need. Scale from there once you understand your real usage patterns and cost profile.

    Recommended: Ready to put this into practice? DigitalOcean is a tool we use for exactly this, and we have a real, disclosed affiliate relationship with them.

    FAQ

    What’s the difference between an AI agent and a chatbot?
    A chatbot responds to messages. An AI agent plans multi-step actions, calls external tools or APIs, and can act autonomously toward a goal without a human approving each step.

    Should I self-host my agent orchestration layer or use a managed platform?
    Self-host if you need auditability, data residency control, or predictable costs. Use a managed platform if you’re prototyping and want to ship fast without owning the ops burden.

    Which AI agents companies are best for enterprise compliance requirements?
    Open-source frameworks like LangChain and Microsoft AutoGen give you full visibility into what data leaves your infrastructure, which is usually easier to justify to a compliance team than a fully black-box managed platform.

    How do I prevent an agent from racking up huge API costs?
    Set a hard cap on tool calls per run, enforce request timeouts, and monitor per-run token usage. Treat cost limits the same way you’d treat rate limiting on any public API.

    Can I run an agent stack on a small VPS?
    Yes — the orchestration layer itself is lightweight. A 2GB-4GB RAM VPS is enough for moderate traffic as long as you’re calling out to a managed model API rather than hosting your own LLM inference.

    Do I need Kubernetes to run AI agents in production?
    Not for most teams. A single VPS with Docker Compose, proper resource limits, and a reverse proxy handles low-to-moderate traffic fine. Move to Kubernetes only once you need multi-node scaling or zero-downtime rolling deploys across several agent replicas.

  • AI Agents Company: A DevOps Guide to Evaluation

    How to Evaluate an AI Agents Company Before You Deploy in Production

    Disclosure: This post contains one or more links to providers we have a real, registered affiliate/referral relationship with. We may earn a commission at no extra cost to you if you sign up through them.

    Every vendor pitch deck now claims to be an “ai agents company.” Strip away the marketing and what you’re actually buying is a runtime, an orchestration layer, and a set of API integrations sitting on top of an LLM. As a sysadmin or platform engineer, your job is to evaluate that stack the same way you’d evaluate any other piece of production infrastructure: uptime guarantees, data egress, observability, and exit costs.

    What an AI Agents Company Actually Sells You

    Strip the branding and every “agent platform” is composed of four layers:

  • Orchestration — a loop that decides which tool to call next (ReAct, plan-and-execute, or a custom state machine)
  • Tool/function execution — sandboxed code execution, API calls, browser automation
  • Memory — vector store or key-value store for context persistence
  • Model routing — calls to one or more LLM providers, sometimes with fallback logic
  • When a vendor says “proprietary agent framework,” they usually mean a wrapper around LangChain or a similar open-source project, plus a hosted UI. That’s not necessarily bad — but it changes your leverage in negotiations and your disaster-recovery options if the company shuts down or changes pricing.

    Questions to Ask Before Signing a Contract

    Before you commit budget to any ai agents company, get concrete answers on these points:

  • Where is agent execution actually running — their cloud, yours, or a shared multi-tenant environment?
  • Can you export conversation logs and memory stores in an open format?
  • What happens to in-flight agent runs during a provider outage?
  • Is there a self-hosted or on-prem tier, and what does it cost relative to the SaaS tier?
  • Who owns the data used for fine-tuning, if any?
  • If you can’t get a straight answer on data residency, treat that as a red flag — not just for compliance, but because it tells you how mature their own infrastructure practices are.

    Self-Hosting vs. Managed AI Agent Platforms

    For teams with existing DevOps capacity, self-hosting an open agent stack is often cheaper and gives you full control over logging, secrets, and network egress. The tradeoff is that you own patching, scaling, and monitoring. If your team is already comfortable running containerized services — the kind of workload we cover in our Docker Compose production guide — self-hosting an agent framework isn’t a huge leap.

    Managed platforms win when you need agent capability shipped fast and don’t have spare ops headcount. But recalculate that tradeoff every 6-12 months; hosted agent pricing scales with token volume and tool calls in ways that surprise teams who scoped for a pilot, not production traffic.

    Deploying an Open-Source Agent Stack with Docker

    Here’s a minimal, production-leaning setup using an open agent runtime, a vector store for memory, and Redis for task queuing. This mirrors what most “agent platforms” run under the hood.

    # docker-compose.yml
    version: "3.9"
    services:
      agent-runtime:
        image: ghcr.io/your-org/agent-runtime:latest
        restart: unless-stopped
        environment:
          - OPENAI_API_KEY=${OPENAI_API_KEY}
          - VECTOR_DB_URL=http://qdrant:6333
          - REDIS_URL=redis://redis:6379/0
        depends_on:
          - qdrant
          - redis
        ports:
          - "8080:8080"
        deploy:
          resources:
            limits:
              cpus: "2"
              memory: 2G
    
      qdrant:
        image: qdrant/qdrant:latest
        restart: unless-stopped
        volumes:
          - qdrant-data:/qdrant/storage
    
      redis:
        image: redis:7-alpine
        restart: unless-stopped
        command: ["redis-server", "--appendonly", "yes"]
        volumes:
          - redis-data:/data
    
    volumes:
      qdrant-data:
      redis-data:

    Bring it up with:

    docker compose up -d
    docker compose logs -f agent-runtime

    Set resource limits from day one. Agent workloads that spawn subprocess-based tools (browser automation, code execution sandboxes) can spike memory unpredictably, and an unbounded container will eventually take down neighboring services on the same host.

    Locking Down Tool Execution

    If your agents execute arbitrary code or shell commands as a “tool,” that container needs to be treated like an untrusted workload:

    docker run --rm 
      --read-only 
      --network=none 
      --memory=512m 
      --pids-limit=64 
      --security-opt=no-new-privileges 
      sandbox-executor:latest

    No network access, read-only filesystem, and a PID limit are the minimum bar. If the agent needs outbound network access for a specific API, use an egress allowlist via a proxy sidecar rather than opening the container to the internet directly. We go deeper on isolating untrusted workloads in our Linux server hardening guide.

    Monitoring and Observability for AI Agent Workloads

    Agent systems fail differently than typical web services — you’ll see infinite tool-call loops, silent hallucinated outputs, and slow degradation from rate-limited upstream APIs rather than clean crashes. Standard uptime checks won’t catch most of this.

    At minimum, instrument:

  • Token usage per request — catches runaway loops before they blow your API bill
  • Tool call latency — flags a degraded upstream API before users notice
  • Task completion rate — the agent-specific equivalent of an error rate
  • Queue depth — if you’re using Redis or a similar broker, growing queue depth means your workers can’t keep up
  • A basic Prometheus scrape config for the runtime above:

    scrape_configs:
      - job_name: 'agent-runtime'
        static_configs:
          - targets: ['agent-runtime:8080']
        metrics_path: /metrics
        scrape_interval: 15s

    For alerting on top of this, a hosted uptime and incident tool saves you from building your own paging pipeline. BetterStack is a solid option if you want status pages and on-call alerting without standing up your own Alertmanager stack — worth it once agents are running anything customer-facing.

    Where to Host the Stack

    Agent runtimes with a vector database and Redis are lightweight enough to run on a single well-specced VPS for small to mid-size workloads — you don’t need Kubernetes to get started, contrary to what most vendor blog posts imply. A 4-8 vCPU droplet with SSD storage from DigitalOcean handles a moderate agent workload comfortably, and you can scale to a managed Kubernetes cluster later if tool-call volume actually justifies it. If you’re serving agent APIs to external clients, put Cloudflare in front for DDoS protection and to keep your origin IP off the public internet.

    Cost Comparison: Managed Platform vs. Self-Hosted

    A rough monthly comparison for a team running ~500K agent invocations:

  • Managed ai agents company platform: $2,000-8,000/mo depending on seat count and token overage fees
  • Self-hosted on a VPS: $80-200/mo for compute, plus your LLM API token costs (same either way), plus engineering time for maintenance
  • The self-hosted number looks like an obvious win until you price in the engineer-hours spent on patching, scaling, and incident response. For a team of one or two, the managed platform is often cheaper in practice. For a team with an existing platform engineer, self-hosting usually wins within two to three months.

    Recommended: Ready to put this into practice? DigitalOcean is a tool we use for exactly this, and we have a real, disclosed affiliate relationship with them.

    FAQ

    What’s the difference between an AI agent and a chatbot?
    A chatbot responds to messages. An agent decides which tools to call, executes multi-step plans, and can act without a human approving each step — that autonomy is exactly what needs the extra monitoring and sandboxing covered above.

    Do I need Kubernetes to run an AI agent stack?
    No. A single VPS with Docker Compose handles moderate workloads fine. Move to Kubernetes when you need multi-region failover or horizontal autoscaling based on queue depth, not before.

    How do I evaluate an ai agents company’s security posture?
    Ask for their SOC 2 report, ask exactly where agent execution happens, and ask what network access their tool-execution sandbox has by default. Vague answers on any of these are a red flag.

    Can I switch between managed and self-hosted later?
    Yes, if you chose a platform built on open standards (LangChain, OpenAI-compatible APIs) from the start. Proprietary agent DSLs make migration expensive — factor that lock-in risk into your initial vendor decision.

    What’s the biggest cost surprise with hosted agent platforms?
    Token and tool-call overage fees once you move from pilot to production traffic. Model your expected invocation volume before signing, not after the first invoice.

    Is self-hosting more secure than a managed platform?
    Not automatically — it’s only more secure if you actually apply the same hardening (network isolation, resource limits, patching cadence) a competent vendor would apply. Self-hosting without that discipline is worse, not better.

  • Docker Compose Volumes: The Complete Setup Guide

    Docker Compose Volumes: A Practical Guide to Persistent Data

    Disclosure: This post contains one or more links to providers we have a real, registered affiliate/referral relationship with. We may earn a commission at no extra cost to you if you sign up through them.

    If you’ve ever restarted a container and watched your database vanish into thin air, you already understand why docker compose volumes matter. Containers are ephemeral by design — anything written inside a container’s writable layer disappears the moment that container is removed. Volumes are Docker’s answer to this problem, and getting them right is one of the first things you need to master before running anything stateful in production.

    This guide covers everything you need to know about docker compose volumes: named volumes, bind mounts, tmpfs mounts, permissions, backups, and the common mistakes that cause data loss. We’ll use real, runnable docker-compose.yml examples throughout.

    Why Volumes Exist

    Docker containers are meant to be disposable. You should be able to destroy a container and recreate it from its image without worrying about what happens to your application’s state. But that raises an obvious problem: where does your database, your uploaded files, or your configuration live if the container itself is throwaway?

    The answer is volumes — storage that exists independently of the container lifecycle. Docker supports three main mechanisms for persisting data:

  • Named volumes — managed by Docker, stored under /var/lib/docker/volumes/ on the host
  • Bind mounts — a direct mapping between a host path and a container path
  • tmpfs mounts — in-memory storage that never touches disk, useful for secrets or caches
  • Each has different tradeoffs, and Compose makes it easy to declare any of them declaratively in a single YAML file.

    Named Volumes: The Default Choice

    Named volumes are the recommended approach for most production workloads. Docker manages the storage location for you, and volumes persist independently of any container — even if you run docker compose down, the volume survives unless you explicitly pass -v or --volumes.

    Here’s a basic example using PostgreSQL:

    services:
      db:
        image: postgres:16
        environment:
          POSTGRES_PASSWORD: examplepass
        volumes:
          - pgdata:/var/lib/postgresql/data
        ports:
          - "5432:5432"
    
    volumes:
      pgdata:

    Notice the two-part structure: the volumes: key under the service maps a named volume (pgdata) to a path inside the container. The top-level volumes: block declares that pgdata exists and lets Compose create it if it doesn’t already.

    You can inspect the volume directly:

    docker volume inspect pgdata
    docker volume ls

    Named volumes are portable across host filesystems, get automatic driver support (local, NFS, cloud-backed drivers), and are the correct choice when you don’t need to browse the files from the host directly.

    Bind Mounts: Direct Host Access

    Bind mounts map a specific directory or file on the host machine into the container. They’re most useful during development, when you want code changes on your host to reflect immediately inside the container without rebuilding the image.

    services:
      app:
        build: .
        volumes:
          - ./src:/usr/src/app
          - ./config/nginx.conf:/etc/nginx/nginx.conf:ro
        ports:
          - "3000:3000"

    The :ro suffix mounts the file read-only inside the container, which is a good habit for configuration files you don’t want the app accidentally overwriting. Bind mounts are also the standard way to expose the Docker socket for tools that need to manage containers, though that comes with security implications worth understanding before you do it in a shared environment — see Docker’s own guidance on socket security if you’re considering it.

    The downside of bind mounts is portability: the host path has to exist and be correct on every machine that runs the Compose file, which makes them a poor fit for production deployments across different servers.

    tmpfs Mounts: Ephemeral In-Memory Storage

    tmpfs mounts never persist to disk. They’re wiped when the container stops, which makes them ideal for temporary secrets, session data, or scratch space that shouldn’t leak onto the host filesystem.

    services:
      cache:
        image: redis:7
        tmpfs:
          - /data

    This is a niche use case compared to named volumes and bind mounts, but it’s worth knowing it exists — especially for compliance-sensitive workloads where you need a guarantee that certain data never touches persistent storage.

    A Real-World Multi-Service Example

    Here’s a more complete example combining a web app, a database, and a reverse proxy — a common pattern for anything you’d deploy on a VPS:

    services:
      web:
        build: .
        volumes:
          - ./app:/usr/src/app
          - static_files:/usr/src/app/static
        depends_on:
          - db
    
      db:
        image: postgres:16
        volumes:
          - pgdata:/var/lib/postgresql/data
        environment:
          POSTGRES_PASSWORD: examplepass
    
      nginx:
        image: nginx:alpine
        volumes:
          - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
          - static_files:/usr/src/app/static:ro
        ports:
          - "80:80"
    
    volumes:
      pgdata:
      static_files:

    This pattern shares the static_files volume between the web and nginx services, so nginx can serve static assets directly without proxying every request through the app server. If you’re setting up a similar stack on your own infrastructure, our guide on deploying Docker Compose to a production VPS walks through the full process including firewall and TLS setup.

    Permissions and Ownership Gotchas

    One of the most common issues developers hit with docker compose volumes is file permission mismatches. If your container runs as a non-root user (which it should, for security reasons), files written by that user inside a bind-mounted directory will be owned by the corresponding UID on the host — which may not match any real user on your system.

    A few practical fixes:

  • Match the container’s UID to your host user with the user: directive in Compose
  • Use a startup script that runs chown on the mounted directory before dropping privileges
  • For named volumes, let Docker manage ownership — it’s usually less painful than bind mounts for this exact reason
  • If you’re chasing a permission denied error, check docker compose exec <service> id and compare it against the ownership of the files with ls -la on the host. Mismatched UIDs are the cause more often than any actual bug in your application.

    Backing Up and Restoring Volumes

    Since named volumes live outside your source-controlled Compose file, you need a separate backup strategy. The simplest approach uses a throwaway container to tar up the volume contents:

    docker run --rm 
      -v pgdata:/data 
      -v $(pwd):/backup 
      alpine 
      tar czf /backup/pgdata-backup.tar.gz -C /data .

    To restore, reverse the process:

    docker run --rm 
      -v pgdata:/data 
      -v $(pwd):/backup 
      alpine 
      tar xzf /backup/pgdata-backup.tar.gz -C /data

    For anything running in production, don’t rely on manual backups alone. Automated monitoring that alerts you before a disk fills up or a backup job silently fails is worth the setup time — BetterStack offers uptime and log monitoring that integrates cleanly with Dockerized stacks if you want alerts wired up without building your own tooling from scratch.

    Choosing the Right Storage Backend for Your Host

    Where your volumes physically live matters more than most people realize until they hit an I/O bottleneck. If you’re running database-heavy workloads in Compose, the underlying disk speed of your VPS provider directly affects query latency. Providers like Hetzner and DigitalOcean both offer NVMe-backed instances that handle volume-heavy workloads noticeably better than budget shared hosting — worth considering if you’re scaling past a hobby project. If your Compose stack sits behind a domain and you want DDoS protection and caching in front of it, Cloudflare is a standard, low-friction addition to the stack.

    Common Mistakes to Avoid

  • Forgetting the top-level volumes: declaration — Compose will still create an anonymous volume if you skip it, but you lose the ability to reference it by name elsewhere
  • Using bind mounts for production databases — path mismatches between environments cause subtle, hard-to-debug failures
  • Running docker compose down -v without thinking — this deletes named volumes along with the containers, which has destroyed more than one person’s local database
  • Not setting :ro on config files — an app with a bug that writes to its own config file can silently corrupt your setup
  • Ignoring volume drivers — if you need multi-host storage (NFS, cloud block storage), you need a volume driver configured; the default local driver only works on a single host
  • If you’re moving from a single-container setup to a full multi-service stack, it’s also worth reading through our breakdown of Docker networking modes, since volumes and networking decisions often need to be made together when you’re designing how services talk to each other and to the outside world.

    Wrapping Up

    Docker Compose volumes aren’t complicated once you understand the distinction between named volumes, bind mounts, and tmpfs — the hard part is picking the right one for each use case and avoiding the permission and lifecycle mistakes that catch people off guard. For production database storage, default to named volumes. For local development where you need live code reloading, bind mounts make sense. Reserve tmpfs for genuinely ephemeral data that should never touch disk.

    Get comfortable inspecting volumes with docker volume ls and docker volume inspect, build a backup habit early, and pay attention to the underlying disk performance of whatever host you’re running on — it matters more than most Compose tutorials mention.

    Recommended: Ready to put this into practice? DigitalOcean is a tool we use for exactly this, and we have a real, disclosed affiliate relationship with them.

    FAQ

    Q: What’s the difference between a named volume and a bind mount?
    A: A named volume is managed entirely by Docker and stored in Docker’s own directory structure on the host, while a bind mount maps a specific host path directly into the container. Named volumes are more portable; bind mounts give you direct host-side access to the files.

    Q: Does docker compose down delete my volumes?
    A: No, by default docker compose down stops and removes containers but leaves named volumes intact. You have to explicitly add the -v flag (docker compose down -v) to remove volumes as well.

    Q: Can I share one volume between multiple services in the same Compose file?
    A: Yes. Declare the volume once in the top-level volumes: block and reference it in the volumes: section of each service that needs it, as shown in the nginx/web example above.

    Q: Why do I get permission denied errors when writing to a mounted volume?
    A: This usually happens because the UID the container process runs as doesn’t match the ownership of the files on the host. Check with docker compose exec <service> id and adjust ownership or the container’s user: directive accordingly.

    Q: How do I back up a named volume?
    A: Run a temporary container that mounts the volume alongside a host directory, then use tar to archive the volume’s contents to that host directory, as shown in the backup example above.

    Q: Should I use volumes for stateless services?
    A: Generally no. If a service doesn’t need to retain data across restarts, skip the volume entirely and let the container’s writable layer handle it — adding a volume you don’t need just adds cleanup overhead later.