← Blog

Claude API Docker Container Setup Guide

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

Running a Claude API integration inside a Docker container is the standard way to make your app portable, reproducible, and ready for deployment to any cloud platform. This guide walks through building a Dockerfile for a Claude-powered service, handling API keys and secrets safely, and avoiding the common networking and build mistakes that trip people up.

The short version: you don't containerize "the Claude API" itself — Anthropic's API is a hosted HTTPS service, not something you run locally. What you containerize is your application that calls that API. The setup guide below covers a Node.js example, but the same pattern applies to Python, Go, or any other runtime.

Why containerize a Claude API app

Docker gives you three things that matter for AI-backed services:

This matters whether you're calling Anthropic's API directly or routing through a proxy like SubToAPI, which exposes your Claude access as a standard HTTPS API with its own sub_live_ key — the container setup is the same either way, since from your app's perspective it's just an HTTP client making requests.

Basic Dockerfile for a Claude API service

Here's a minimal, production-reasonable Dockerfile for a Node.js app that calls a Claude-compatible API:

FROM node:20-slim AS base
WORKDIR /app

COPY package*.json ./
RUN npm ci --omit=dev

COPY . .

ENV NODE_ENV=production
EXPOSE 3000

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

Key points:

For multi-stage builds (recommended if you use TypeScript or bundlers):

FROM node:20-slim AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-slim AS runtime
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY --from=build /app/node_modules ./node_modules
COPY package*.json ./
ENV NODE_ENV=production
EXPOSE 3000
CMD ["node", "dist/server.js"]

This keeps your final image lean since dev dependencies and build tooling never ship.

Handling the API key safely

Never bake your API key into the image with ENV in the Dockerfile — it ends up permanently in the image layers and in docker history. Instead, pass it at runtime:

docker run -d \
  -e SUBTOAPI_KEY=sub_live_xxx \
  -p 3000:3000 \
  my-claude-app:latest

Or with a .env file and Docker Compose:

version: "3.9"
services:
  app:
    build: .
    ports:
      - "3000:3000"
    env_file:
      - .env
# .env (never commit this file)
SUBTOAPI_KEY=sub_live_xxx

Your application code then reads the key from process.env:

import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic({
  apiKey: process.env.SUBTOAPI_KEY,
  baseURL: "https://api.subtoapi.app/v1",
});

const message = await client.messages.create({
  model: "claude-sonnet-4-5",
  max_tokens: 1024,
  messages: [{ role: "user", content: "Summarize this in one sentence." }],
});

If you're calling the Anthropic SDK against SubToAPI's gateway instead of Anthropic directly, check /docs/quickstart for the exact base URL and auth header format, and /docs/messages for request/response shapes.

Networking: container to internet

A common mistake is assuming a container has no outbound internet access by default — it does, unless you've explicitly restricted it with a custom network or firewall rule. Claude API calls go out over HTTPS on port 443, so standard Docker networking (bridge mode) works without extra configuration. Things to verify if requests fail from inside a container:

Streaming responses from inside a container

If your app streams Claude responses (useful for chat UIs), make sure your reverse proxy or load balancer in front of the container doesn't buffer the response. Nginx, for example, needs proxy_buffering off; on the relevant location block, otherwise streamed tokens arrive in one burst instead of incrementally. See /docs/streaming for the server-sent-events format if you're consuming a streaming endpoint.

Health checks and graceful shutdown

Add a HEALTHCHECK so orchestrators (Docker Compose, ECS, Kubernetes) know when your app is actually ready to serve traffic, not just that the process started:

HEALTHCHECK --interval=30s --timeout=5s \
  CMD curl -f http://localhost:3000/health || exit 1

And handle SIGTERM in your app so in-flight Claude API calls aren't dropped mid-stream when the container is scaled down or redeployed:

process.on("SIGTERM", () => {
  server.close(() => process.exit(0));
});

A note on API key management across environments

If you run multiple containers across dev, staging, and production, resist the temptation to share one API key across all of them — it makes usage tracking and incident response much harder. SubToAPI lets you issue separate sub_live_ keys per environment or team member from one dashboard, with usage metadata per key, which is a cleaner fit for containerized multi-environment setups than managing raw Anthropic keys by hand. See /signup if you want to try that approach alongside your existing Docker setup.

questions

Do I need Docker to use the Claude API? No. Docker is optional — it's useful for packaging and deploying your application consistently, but you can call the API from any environment, local or otherwise.

Can I run Claude models locally inside my container? No. Claude is a hosted model accessed via HTTPS API calls; your container runs your application code that makes those calls, not the model itself.

Why is my container getting TLS or connection errors to the API? Usually missing CA certificates in a minimal base image, DNS failures inside the container network, or an outbound firewall/proxy on the host blocking port 443 traffic.

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 →