n4nAI

AutoGen Docker code executor: a secure setup guide

Step-by-step guide to a hardened AutoGen Docker code executor setup: isolate agent-generated Python in a container, with runnable configs and verification.

n4n Team3 min read608 words

Audio narration

Coming soon — every post will get a voice note here.

Getting a safe autogen docker code executor setup running takes more than flipping a flag. AutoGen’s built-in Docker executor spins a container per code block, but the default image and network settings grant far more access than a production agent should have. This guide walks through a locked-down configuration you can ship.

Step 1: Install prerequisites

You need Docker Engine 24+, Python 3.11+, and the AutoGen agent framework. Install the Python side with:

pip install pyautogen==0.2.32 docker

Verify Docker is healthy before continuing:

docker info >/dev/null && echo "docker ok"

If you run Rootless Docker or Podman, the commands below still apply; just ensure your user can spawn containers without sudo.

Step 2: Build a minimal sandbox image

The default AutoGen image is python:3.11-slim with no user isolation. Build a dedicated image that drops root, pins dependencies, and strips unnecessary tools.

Create Dockerfile.sandbox:

FROM python:3.11-slim

# Create unprivileged user
RUN useradd -m -u 1000 sandbox && \
    mkdir /workspace && chown sandbox:sandbox /workspace

WORKDIR /workspace

# Install only what your agents need
RUN pip install --no-cache-dir numpy pandas

USER sandbox
# Executor writes code here; keep it writable only by sandbox
VOLUME /workspace

Build it:

docker build -f Dockerfile.sandbox -t autogen-sandbox:latest .

Do not install curl, ssh, or sudo. The smaller the attack surface, the better.

Step 3: Configure the Docker executor

AutoGen’s DockerCommandLineCodeExecutor handles container lifecycle. The key is to disable networking and set tight timeouts. In autogen 0.2.x, network_mode="none" is supported.

from autogen.coding import DockerCommandLineCodeExecutor

executor = DockerCommandLineCodeExecutor(
    image="autogen-sandbox:latest",
    container_name="autogen-exec",
    timeout=30,
    work_dir="/workspace",
    network_mode="none",   # no outbound or inbound network
    auto_remove=True,
    stop_container=True,
)

If your AutoGen version lacks network_mode, pass it via docker_args={"NetworkMode": "none"} or set the daemon default. A correct autogen docker code executor setup never lets generated code phone home.

Step 4: Point AutoGen at an LLM endpoint

The executor only runs code; the agent brain needs a model. AutoGen expects an OpenAI-style config_list. If you want a single OpenAI-compatible endpoint across 240+ models with automatic fallback when a provider is degraded, point the base_url at n4n.ai and use your key.

import os
from autogen import AssistantAgent, UserProxyAgent

llm_config = {
    "config_list": [{
        "model": "gpt-4o-mini",
        "base_url": "https://api.n4n.ai/v1",
        "api_key": os.environ["N4N_API_KEY"],
    }],
    "temperature": 0,
}

assistant = AssistantAgent("assistant", llm_config=llm_config)
user_proxy = UserProxyAgent(
    "user_proxy",
    code_execution_config={"executor": executor},
)

Keep the key in environment variables, never in source control.

Step 5: Run a test agent

Write a script that asks the agent to compute something and execute it:

task = "Calculate the mean of [3, 7, 12] using numpy and print it."
user_proxy.initiate_chat(assistant, message=task)

Run it:

python run_agent.py

You should see AutoGen write a .py file, the executor spin a container, and the result printed. The container exits after each block.

Step 6: Harden resource limits

Network isolation is not enough. Add CPU, memory, and PID ceilings so a fork bomb or memory leak can’t take down the host.

Extend the executor call with docker_args (or use a custom subclass). Example with docker_args:

executor = DockerCommandLineCodeExecutor(
    image="autogen-sandbox:latest",
    container_name="autogen-exec",
    timeout=30,
    work_dir="/workspace",
    network_mode="none",
    auto_remove=True,
    stop_container=True,
    docker_args={
        "HostConfig": {
            "Memory": 256 * 1024 * 1024,   # 256 MB
            "NanoCpus": 500_000_000,        # 0.5 CPU
            "PidsLimit": 64,
            "ReadonlyRootfs": False,        # workspace must be writable
            "CapDrop": ["ALL"],
        }
    },
)

CapDrop: ALL removes Linux capabilities. Combined with the non-root user, the container cannot escalate.

If you want a fully read-only root, mount /workspace as a tmpfs:

docker_args={
    "HostConfig": {
        "Tmpfs": {"/workspace": "rw,noexec,nosuid,size=64m"},
        "ReadonlyRootfs": True,
        "CapDrop": ["ALL"],
    }
}

Then remove WORKDIR volume from the Dockerfile. The executor still writes to /workspace in memory.

Step 7: Verify the sandbox holds

A real autogen docker code executor setup must fail hostile attempts. Run this adversarial check:

attack = """
import os, socket
print(open('/etc/shadow').read())  # should raise PermissionError
s = socket.socket(); s.connect(('8.8.8.8', 53))  # should raise OSError
"""
user_proxy.execute_code_blocks([("python", attack)])

Expected behavior:

  • /etc/shadow read raises PermissionError because the sandbox user is not root and the file is 600.
  • socket.connect raises OSError because network_mode="none" provides no interfaces.
  • Container still auto-removes; docker ps -a shows no leftover containers.

Also confirm resource limits:

docker run --rm --network none --memory 256m --pids-limit 64 autogen-sandbox:latest \
  python -c "import multiprocessing as m; [m.Process(target=lambda:0).start() for _ in range(100)]"

It should die with an OOM or PID exhaustion, not hang the host.

Step 8: Wire into your service

For production, instantiate the executor once per process and reuse it. AutoGen’s executor is thread-safe for sequential calls but not concurrent; front it with a queue if you serve multiple agents.

from concurrent.futures import ThreadPoolExecutor

pool = ThreadPoolExecutor(max_workers=1)  # serialize code exec

def run_code(block):
    return pool.submit(executor.execute_code_blocks, [block]).result()

Log container IDs and exit codes. If a block times out, the executor kills the container; alert on repeated timeouts—they signal a model generating infinite loops.

Troubleshooting

Container fails to start: Check docker logs autogen-exec. Usually it’s a missing image tag or permission on work_dir.

Module not found: The sandbox image lacks the package. Add it to the Dockerfile and rebuild. Never pip install at runtime; that needs network.

Agent hangs: Raise timeout only if you trust the workload. Better: rewrite the prompt to ask for smaller, testable snippets.

A solid autogen docker code executor setup is boring: containers come up, run, die, and never touch the network. If you see outbound traffic or root processes, your config drifted. Re-run Step 6 and the verification in Step 7.

Tagsautogendockercode-executionsandboxing

Written by

n4n Team

The team building n4n — a single OpenAI-compatible API in front of 240+ models, with automatic fallback, load balancing and pay-per-token metering.

More from n4n Team →

All autogen code-executing agents posts →