← Blog

How to Set Up Claude API in a Docker Container

2026-10-28 · 5 min read · SubToAPI Team

Setting up Claude API access inside a Docker container mainly comes down to two things: getting your API credentials into the container securely, and making sure outbound HTTPS traffic from the container can actually reach the API endpoint. Neither is complicated, but there are a few mistakes — baking keys into images, using plaintext env files committed to git, missing SSL certs in minimal base images — that cause most of the pain developers run into.

This guide walks through a working Dockerfile and docker-compose setup for calling Claude from a containerized app, how to pass credentials safely, and what changes if you're running multiple services that each need API access.

Base image and dependencies

Pick a base image that already has a current CA certificate bundle and a recent runtime. For Node.js:

FROM node:20-slim

WORKDIR /app

COPY package*.json ./
RUN npm install --production

COPY . .

CMD ["node", "server.js"]

For Python:

FROM python:3.12-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["python", "server.py"]

Both -slim variants include ca-certificates, which you need for outbound TLS calls to any API endpoint. Alpine-based images sometimes don't, and you'll see SSL: CERTIFICATE_VERIFY_FAILED errors until you manually install the package.

Never bake the API key into the image

The most common mistake: putting ENV ANTHROPIC_API_KEY=sk-... or similar directly in the Dockerfile. That key becomes part of the image layer history and will leak if the image is ever pushed to a public or shared registry.

Instead, pass the key at runtime:

docker run -e ANTHROPIC_API_KEY="your-key" -p 3000:3000 my-claude-app

Or with an .env file (kept out of version control via .gitignore):

docker run --env-file .env -p 3000:3000 my-claude-app

In docker-compose.yml:

services:
  app:
    build: .
    ports:
      - "3000:3000"
    env_file:
      - .env

For production deployments on Kubernetes or ECS, use native secrets managers (Kubernetes Secrets, AWS Secrets Manager, Docker Swarm secrets) instead of plain env files. The pattern is the same everywhere: the key never touches the image, only the running container's environment.

Making the API call from inside the container

Once the key is available as an environment variable, your application code reads it like any other secret:

const response = await fetch("https://api.anthropic.com/v1/messages", {
  method: "POST",
  headers: {
    "x-api-key": process.env.ANTHROPIC_API_KEY,
    "anthropic-version": "2023-06-01",
    "content-type": "application/json",
  },
  body: JSON.stringify({
    model: "claude-opus-4",
    max_tokens: 1024,
    messages: [{ role: "user", content: "Hello from inside Docker" }],
  }),
});

This works fine for a single service. Where it gets more involved is multi-container setups — a worker service, a web service, and maybe a background job runner all needing to call Claude, each requiring their own rate limits, usage tracking, and key rotation policy.

Multi-service setups and key sprawl

In a typical docker-compose stack with several services, you end up either:

This is where a layer like SubToAPI simplifies things if you're already paying for Claude access and want application-level API keys instead of managing Anthropic credentials directly inside every container. You generate scoped keys (sub_live_...) per service from one dashboard, point each container at https://api.subtoapi.app/v1/messages instead of the raw Anthropic endpoint, and get usage metadata and seat-level tracking without changing your container architecture. The request/response shape is the same, so the Dockerfile and compose setup above don't change — only the base URL and bearer token do:

const response = await fetch("https://api.subtoapi.app/v1/messages", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.SUBTOAPI_KEY}`,
    "content-type": "application/json",
  },
  body: JSON.stringify({
    model: "claude-opus-4",
    max_tokens: 1024,
    messages: [{ role: "user", content: "Hello from inside Docker" }],
  }),
});

The same env-var-at-runtime pattern applies: SUBTOAPI_KEY gets injected via docker run -e, --env-file, or your orchestrator's secrets mechanism, never hardcoded. Each container or service gets its own key, so you can revoke or rate-limit one without touching the others. See the /docs/quickstart guide for the full setup and /docs/messages for the request schema.

Networking and health checks

Two things trip people up specifically because of the container boundary:

A simple health check endpoint in your app that pings the API with a minimal request is worth adding to docker-compose.yml so container orchestration tools can detect a broken key or network path before traffic hits it:

healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
  interval: 30s
  timeout: 5s
  retries: 3

Streaming responses in a container

If your service streams Claude's output back to clients (e.g., over SSE or WebSocket), make sure your container's HTTP server and any reverse proxy in front of it (nginx, Envoy) don't buffer the response. Buffering defeats the purpose of streaming and adds latency. See /docs/streaming for details on handling streamed chunks correctly if you're using SubToAPI's endpoint, or check your provider's streaming docs otherwise.

questions

Do I need a special base image to call the Claude API from Docker? No. Any standard Linux-based image with current CA certificates (like node:20-slim or python:3.12-slim) works. Alpine images sometimes need ca-certificates installed manually.

How should I pass my API key into the container? Use runtime environment variables via docker run -e, --env-file, or your orchestrator's secrets manager. Never set the key with ENV in the Dockerfile itself, since it gets baked into the image layers.

Can I use one API key across multiple containers in the same stack? You can, but it makes usage tracking and revocation per-service impossible. Issuing separate keys per container, or using a dashboard-managed system like SubToAPI (see /pricing), keeps usage and limits isolated per service.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →