How to deploy a secure MCP server
A remote MCP server is just an HTTP service, so it runs anywhere that runs your language. The part people skip is the security configuration that turns a working server into a safe one. This guide covers both.
Docker, the universal option
A multi-stage Dockerfile keeps the image small and runs as a non-root user. Build it, then pass your secrets and allowlists as environment variables at run time, never baked into the image.
docker run -p 8787:8787 \ -e NODE_ENV=production \ -e MCP_AUTH_TOKEN="$(openssl rand -hex 32)" \ -e ALLOWED_ORIGINS=https://app.example.com \ your-mcp-server
Fly, Railway, Render
- Fly:
fly launch, then set secrets withfly secrets set. - Railway / Render: point at your repo, set the build and start commands, add the env vars in the dashboard.
- VPS: build, run under systemd with an EnvironmentFile, and put it behind nginx or Caddy for TLS.
The settings you must not skip
- NODE_ENV=production so a fail-closed server refuses to start without auth.
- TLS in front of it. Never serve MCP over plaintext http in production.
- Allowed origins and hosts set, which also enables DNS-rebinding protection on the transport.
- Secrets via env or a secret manager, never in the image or the repo.
- Non-root user in the container.
What about serverless and Cloudflare Workers?
If your server uses Node's http module, a fetch-handler runtime like Cloudflare Workers needs the web-standard transport instead. Your auth, rate-limit, and SSRF modules port over unchanged, only the entry point changes to a fetch handler.
A server that deploys this way out of the box
MCP Forge Kit includes a Dockerfile, a deploy guide for Fly, Railway, Render, and a VPS, plus the security config wired up and fail-closed in production.
Get MCP Forge Kit, €39Related: Authentication · SSRF protection · Security checklist