AI Agents
    Open Source

    Deploy SmolAgents on a RamNode VPS

    Hugging Face's minimalist code-first agent framework, behind a FastAPI wrapper with Docker-sandboxed code execution and TLS-terminated Nginx.

    At a Glance

    ProjectSmolAgents 1.24+
    LicenseApache 2.0
    Recommended PlanRamNode Premium NVMe 4 vCPU / 8 GB
    OSUbuntu 24.04 LTS
    Estimated Setup Time45 minutes
    1

    Initial Server Hardening

    Create non-root user + base packages
    adduser --disabled-password --gecos "" agent
    usermod -aG sudo agent
    rsync --archive --chown=agent:agent ~/.ssh /home/agent
    
    sudo apt update && sudo apt -y upgrade
    sudo apt -y install build-essential ca-certificates curl gnupg lsb-release \
      git ufw fail2ban unattended-upgrades \
      python3.12 python3.12-venv python3-pip python3-dev
    SSH hardening
    # /etc/ssh/sshd_config.d/99-hardening.conf
    PermitRootLogin no
    PasswordAuthentication no
    KbdInteractiveAuthentication no
    AuthenticationMethods publickey
    AllowUsers agent
    UFW
    sudo systemctl reload ssh
    sudo ufw default deny incoming && sudo ufw default allow outgoing
    sudo ufw allow 22/tcp && sudo ufw allow 80/tcp && sudo ufw allow 443/tcp
    sudo ufw enable
    2

    Install Docker (Sandbox Executor)

    Add official repo + install
    sudo install -m 0755 -d /etc/apt/keyrings
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
      | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
    sudo chmod a+r /etc/apt/keyrings/docker.gpg
    
    echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
      https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" \
      | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    
    sudo apt update
    sudo apt -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
    sudo usermod -aG docker agent
    /etc/docker/daemon.json (sandbox safety net)
    {
      "log-driver": "json-file",
      "log-opts": {"max-size": "10m", "max-file": "3"},
      "default-ulimits": {"nofile": {"Name": "nofile", "Hard": 4096, "Soft": 4096}},
      "no-new-privileges": true,
      "icc": false,
      "userland-proxy": false
    }
    Restart
    sudo systemctl restart docker
    docker run --rm hello-world
    3

    Python Environment + SmolAgents

    Project + venv
    sudo mkdir -p /opt/smolagents && sudo chown agent:agent /opt/smolagents
    cd /opt/smolagents
    python3.12 -m venv .venv && source .venv/bin/activate
    pip install --upgrade pip wheel
    pip install "smolagents[toolkit,litellm,docker,mcp]" fastapi uvicorn python-dotenv
    pip freeze > requirements.txt
    /opt/smolagents/.env
    HF_TOKEN=hf_xxx
    OPENAI_API_KEY=sk-xxx
    ANTHROPIC_API_KEY=sk-ant-xxx
    Lock the file
    chmod 600 /opt/smolagents/.env
    4

    Minimal Agent Service

    /opt/smolagents/app.py
    import os
    from contextlib import asynccontextmanager
    from typing import Optional
    from dotenv import load_dotenv
    from fastapi import FastAPI, HTTPException
    from pydantic import BaseModel, Field
    from smolagents import CodeAgent, WebSearchTool, LiteLLMModel
    
    load_dotenv("/opt/smolagents/.env")
    MODEL_ID = os.environ.get("SMOLAGENTS_MODEL_ID", "anthropic/claude-sonnet-4-5")
    MAX_STEPS = int(os.environ.get("SMOLAGENTS_MAX_STEPS", "8"))
    EXECUTOR = os.environ.get("SMOLAGENTS_EXECUTOR", "docker")
    
    class RunRequest(BaseModel):
        task: str = Field(..., min_length=1, max_length=4000)
        max_steps: Optional[int] = Field(default=None, ge=1, le=20)
    
    class RunResponse(BaseModel):
        result: str; steps_used: int
    
    @asynccontextmanager
    async def lifespan(app: FastAPI):
        app.state.model = LiteLLMModel(model_id=MODEL_ID)
        yield
    
    app = FastAPI(lifespan=lifespan, title="SmolAgents Service")
    
    @app.get("/health")
    def health(): return {"status": "ok", "model": MODEL_ID, "executor": EXECUTOR}
    
    @app.post("/run", response_model=RunResponse)
    def run(req: RunRequest):
        try:
            with CodeAgent(tools=[WebSearchTool()], model=app.state.model,
                           executor_type=EXECUTOR, max_steps=req.max_steps or MAX_STEPS) as agent:
                result = agent.run(req.task)
                return RunResponse(result=str(result), steps_used=len(agent.memory.steps))
        except Exception as exc:
            raise HTTPException(status_code=500, detail=str(exc))
    5

    Run under systemd

    /etc/systemd/system/smolagents.service
    [Unit]
    Description=SmolAgents FastAPI service
    After=network-online.target docker.service
    Wants=network-online.target
    Requires=docker.service
    
    [Service]
    Type=simple
    User=agent
    Group=agent
    WorkingDirectory=/opt/smolagents
    EnvironmentFile=/opt/smolagents/.env
    ExecStart=/opt/smolagents/.venv/bin/uvicorn app:app \
      --host 127.0.0.1 --port 8000 --workers 2 \
      --proxy-headers --forwarded-allow-ips=127.0.0.1
    Restart=on-failure
    RestartSec=5
    
    NoNewPrivileges=true
    ProtectSystem=strict
    ProtectHome=true
    PrivateTmp=true
    ReadWritePaths=/opt/smolagents
    ProtectKernelTunables=true
    
    [Install]
    WantedBy=multi-user.target
    Enable
    sudo systemctl daemon-reload
    sudo systemctl enable --now smolagents
    journalctl -u smolagents -f
    6

    Nginx Reverse Proxy + TLS

    Install nginx + certbot
    sudo apt -y install nginx certbot python3-certbot-nginx
    /etc/nginx/sites-available/smolagents.conf
    server {
      listen 80;
      server_name agents.example.com;
      location / { return 301 https://$host$request_uri; }
    }
    server {
      listen 443 ssl http2;
      server_name agents.example.com;
      ssl_certificate     /etc/letsencrypt/live/agents.example.com/fullchain.pem;
      ssl_certificate_key /etc/letsencrypt/live/agents.example.com/privkey.pem;
    
      client_max_body_size 1m;
      proxy_read_timeout 300s;
    
      if ($http_x_agent_key != "REPLACE_WITH_LONG_RANDOM_STRING") { return 403; }
    
      location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      }
    }
    Enable + cert
    sudo ln -s /etc/nginx/sites-available/smolagents.conf /etc/nginx/sites-enabled/
    sudo nginx -t && sudo systemctl reload nginx
    sudo certbot --nginx -d agents.example.com --redirect
    7

    Hardening Checklist

    • Confirm uvicorn runs as agent, not root
    • Confirm ss -tlnp shows 8000 bound to 127.0.0.1 only
    • .env is mode 600, owned by agent
    • Set sane max_steps ceiling per request
    • Mount tmpfs into the Docker sandbox, never a host path
    • Audit every tool — each is part of the agent's attack surface