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/shadowread raisesPermissionErrorbecause the sandbox user is not root and the file is 600.socket.connectraisesOSErrorbecausenetwork_mode="none"provides no interfaces.- Container still auto-removes;
docker ps -ashows 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.