07. Tailscale Networking & Security
Overview
We rely on Tailscale to create a flat, secure mesh network. This allows valid devices (developers' laptops, AI agent runners) to access the services without exposing public ports.
Concepts
- Tailnet: Your private network.
- ACLs (Access Control Lists): Rules defining who can talk to whom.
- MagicDNS: Automatic hostname resolution (e.g.,
http://rag-mcp-node).
Configuration Strategy
1. Installation
In cloud-init, we installed Tailscale and advertised the machine as an exit node (optional) but primarily purely as a node.
2. Interface binding
The Docker services bind to 0.0.0.0 inside the container.
Current Implementation (docker-compose.yml):
We use a Tailscale Sidecar to handle authentication and networking, ensuring the RAG service is not exposed constantly to the public internet.
3. Tailscale Sidecar (Implemented)
To strictly restrict access to the MCP server, we run a ts-serve sidecar (named ts-proxy).
# 3. Tailscale Sidecar (Auth Proxy)
ts-proxy:
image: tailscale/tailscale:latest
hostname: rag-internal
restart: always
environment:
- TS_AUTHKEY=${TS_AUTHKEY_PROXY}
- TS_STATE_DIR=/var/lib/tailscale
- TS_DEST_IP=rag-service
volumes:
- ts-state:/var/lib/tailscale
cap_add:
- NET_ADMIN
- NET_RAW
networks:
- internal-net
The Application Service (rag-service) binds only to localhost:
ports:
- "127.0.0.1:8082:8080"
JSON ACLs (Tailscale Console)
Enforce that only "devs" tag can reach the "prod" tag.
{
"groups": {
"group:admins": ["alice@email.com"],
"group:bots": ["tag:ai-agent"]
},
"acls": [
{
"action": "accept",
"src": ["group:admins"],
"dst": ["*:*"]
},
{
"action": "accept",
"src": ["group:bots"],
"dst": ["tag:prod:8080"] // Only MCP port
}
]
}
Connecting the AI Agent
To let a local AI agent (like Cursor/Windsurf) use the remote tool:
- Ensure laptop is on Tailscale.
- Config MCP tool URL:
http://rag-mcp-node:8080/sse(orhttp://rag-internal:8080if using MagicDNS). The secure tunnel is transparent.