Create deployment documentation

This commit provides comprehensive deployment documentation for production use.

README.md updates:
- Completely rewritten to reflect HTTP wrapper architecture
- Clear distinction from standalone MCP server
- Architecture diagram showing HTTP → wrapper → MCP → Gitea flow
- Quick start guide with Docker
- Configuration reference (required and optional)
- HTTP endpoints documentation
- Claude Desktop integration instructions
- Troubleshooting section for common issues
- Security considerations
- References to DEPLOYMENT.md for advanced scenarios

DEPLOYMENT.md (new):
- Complete production deployment guide
- Docker deployment (quick start and production config)
- Security best practices:
  - Authentication setup
  - HTTPS configuration
  - Secrets management
  - Network isolation
  - Token rotation
- Monitoring and health checks
- Reverse proxy configurations (Nginx, Caddy, Traefik)
- Cloud deployment guides:
  - AWS EC2 and ECS
  - Google Cloud Run
  - Azure Container Instances
- Kubernetes deployment with full manifests
- Troubleshooting production issues
- Scaling considerations (horizontal, load balancing, caching)
- Backup and disaster recovery
- Production deployment checklist

This documentation enables users to:
1. Get started quickly with Docker
2. Understand the architecture
3. Deploy securely in production
4. Scale and monitor the service
5. Troubleshoot common issues

The documentation is deployment-focused and production-ready, covering real-world scenarios from local testing to enterprise cloud deployment.

Closes #16

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-03 16:13:50 -05:00
parent 4e81b9bb96
commit f2cba079eb
2 changed files with 945 additions and 254 deletions

712
DEPLOYMENT.md Normal file
View File

@@ -0,0 +1,712 @@
# Deployment Guide
This guide covers production deployment of the Gitea HTTP MCP Wrapper in various environments.
## Table of Contents
1. [Prerequisites](#prerequisites)
2. [Docker Deployment](#docker-deployment)
3. [Security Best Practices](#security-best-practices)
4. [Monitoring and Health Checks](#monitoring-and-health-checks)
5. [Reverse Proxy Configuration](#reverse-proxy-configuration)
6. [Cloud Deployment](#cloud-deployment)
7. [Kubernetes Deployment](#kubernetes-deployment)
8. [Troubleshooting](#troubleshooting)
## Prerequisites
### Required
- Docker and Docker Compose (for Docker deployment)
- Gitea instance with API access
- Gitea API token with appropriate permissions
- Network connectivity between wrapper and Gitea instance
### Recommended
- HTTPS-capable reverse proxy (Nginx, Caddy, Traefik)
- Secrets management solution (not `.env` files in production)
- Monitoring and logging infrastructure
- Firewall or VPN for network security
## Docker Deployment
### Quick Start
1. **Clone the repository:**
```bash
git clone https://github.com/lmiranda/gitea-mcp-remote.git
cd gitea-mcp-remote
```
2. **Create configuration:**
```bash
cp .env.docker.example .env
nano .env # Edit with your values
```
Required configuration:
```bash
GITEA_URL=https://gitea.example.com
GITEA_TOKEN=your_gitea_api_token
GITEA_OWNER=your_username_or_org
GITEA_REPO=your_default_repo
AUTH_TOKEN=your_bearer_token # Recommended
```
3. **Start the service:**
```bash
docker-compose up -d
```
4. **Verify deployment:**
```bash
curl http://localhost:8000/health
```
### Production Configuration
For production, use a more robust `docker-compose.yml`:
```yaml
version: '3.8'
services:
gitea-mcp-wrapper:
build:
context: .
dockerfile: Dockerfile
image: gitea-mcp-wrapper:latest
container_name: gitea-mcp-wrapper
restart: always
ports:
- "127.0.0.1:8000:8000" # Bind to localhost only
environment:
- GITEA_URL=${GITEA_URL}
- GITEA_TOKEN=${GITEA_TOKEN}
- GITEA_OWNER=${GITEA_OWNER}
- GITEA_REPO=${GITEA_REPO}
- HTTP_HOST=0.0.0.0
- HTTP_PORT=8000
- AUTH_TOKEN=${AUTH_TOKEN}
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health').read()"]
interval: 30s
timeout: 3s
retries: 3
start_period: 5s
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
networks:
- gitea-mcp-network
networks:
gitea-mcp-network:
driver: bridge
```
### Docker Build Options
**Build the image:**
```bash
docker build -t gitea-mcp-wrapper:latest .
```
**Build with specific Python version:**
```bash
docker build --build-arg PYTHON_VERSION=3.11 -t gitea-mcp-wrapper:latest .
```
**Tag for registry:**
```bash
docker tag gitea-mcp-wrapper:latest registry.example.com/gitea-mcp-wrapper:latest
docker push registry.example.com/gitea-mcp-wrapper:latest
```
## Security Best Practices
### 1. Use Authentication
Always set `AUTH_TOKEN` in production:
```bash
# Generate a secure token
openssl rand -base64 32
# Add to .env
AUTH_TOKEN=<generated_token>
```
### 2. Use HTTPS
Never expose the wrapper directly to the internet without HTTPS. Use a reverse proxy (see below).
### 3. Network Isolation
- Bind to localhost only (`127.0.0.1`) if using a reverse proxy
- Use Docker networks to isolate services
- Consider VPN or private networking for access
### 4. Secrets Management
Don't use `.env` files in production. Use Docker secrets, Kubernetes secrets, or a secrets manager:
**Docker Secrets Example:**
```yaml
services:
gitea-mcp-wrapper:
secrets:
- gitea_token
- auth_token
environment:
- GITEA_TOKEN_FILE=/run/secrets/gitea_token
- AUTH_TOKEN_FILE=/run/secrets/auth_token
secrets:
gitea_token:
external: true
auth_token:
external: true
```
### 5. Regular Updates
- Rotate Gitea API token regularly
- Rotate AUTH_TOKEN regularly
- Keep Docker base image updated
- Update dependencies: `pip install --upgrade -r requirements.txt`
### 6. Minimal Permissions
Grant the Gitea API token only the minimum required permissions:
- Repository read/write
- Issue management
- Label management
- Milestone management
Avoid granting admin or organization-level permissions.
## Monitoring and Health Checks
### Health Check Endpoints
The wrapper provides three health check endpoints:
```bash
GET /health
GET /healthz
GET /ping
```
All return `{"status": "healthy"}` with HTTP 200 when the server is operational.
### Docker Health Checks
Docker automatically monitors the health check and can restart if unhealthy:
```yaml
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 3s
retries: 3
start_period: 5s
```
### Monitoring Integration
**Prometheus metrics:** (Not yet implemented, but can be added)
**Log monitoring:**
```bash
# View logs
docker-compose logs -f gitea-mcp-wrapper
# JSON structured logs
docker logs gitea-mcp-wrapper --tail 100
```
**Uptime monitoring:**
Use tools like UptimeRobot, Pingdom, or Datadog to monitor `/health` endpoint.
## Reverse Proxy Configuration
### Nginx
```nginx
server {
listen 443 ssl http2;
server_name mcp.example.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Pass through Authorization header
proxy_set_header Authorization $http_authorization;
proxy_pass_header Authorization;
# WebSocket support (if needed in future)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Timeouts
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# Health check endpoint (optional, can bypass auth)
location /health {
proxy_pass http://127.0.0.1:8000/health;
access_log off;
}
}
```
### Caddy
```caddyfile
mcp.example.com {
reverse_proxy localhost:8000 {
# Pass through Authorization header
header_up Authorization {>Authorization}
}
# Optional: Rate limiting
rate_limit {
zone mcp_zone
rate 100r/m
}
}
```
### Traefik
```yaml
# docker-compose.yml
services:
gitea-mcp-wrapper:
labels:
- "traefik.enable=true"
- "traefik.http.routers.mcp.rule=Host(`mcp.example.com`)"
- "traefik.http.routers.mcp.entrypoints=websecure"
- "traefik.http.routers.mcp.tls.certresolver=letsencrypt"
- "traefik.http.services.mcp.loadbalancer.server.port=8000"
```
## Cloud Deployment
### AWS EC2
1. **Launch EC2 instance:**
- Amazon Linux 2 or Ubuntu 22.04
- t3.micro or larger
- Security group: Allow port 443 (HTTPS)
2. **Install Docker:**
```bash
sudo yum update -y
sudo yum install -y docker
sudo service docker start
sudo usermod -aG docker ec2-user
```
3. **Deploy wrapper:**
```bash
git clone https://github.com/lmiranda/gitea-mcp-remote.git
cd gitea-mcp-remote
cp .env.docker.example .env
nano .env # Configure
docker-compose up -d
```
4. **Configure Nginx or ALB for HTTPS**
### AWS ECS (Fargate)
1. **Create task definition:**
```json
{
"family": "gitea-mcp-wrapper",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "256",
"memory": "512",
"containerDefinitions": [
{
"name": "gitea-mcp-wrapper",
"image": "your-ecr-repo/gitea-mcp-wrapper:latest",
"portMappings": [
{
"containerPort": 8000,
"protocol": "tcp"
}
],
"environment": [
{"name": "GITEA_URL", "value": "https://gitea.example.com"},
{"name": "HTTP_HOST", "value": "0.0.0.0"},
{"name": "HTTP_PORT", "value": "8000"}
],
"secrets": [
{
"name": "GITEA_TOKEN",
"valueFrom": "arn:aws:secretsmanager:region:account:secret:gitea-token"
},
{
"name": "AUTH_TOKEN",
"valueFrom": "arn:aws:secretsmanager:region:account:secret:auth-token"
}
],
"healthCheck": {
"command": ["CMD-SHELL", "curl -f http://localhost:8000/health || exit 1"],
"interval": 30,
"timeout": 5,
"retries": 3,
"startPeriod": 10
}
}
]
}
```
2. **Create ECS service with ALB**
### Google Cloud Run
1. **Build and push image:**
```bash
gcloud builds submit --tag gcr.io/PROJECT_ID/gitea-mcp-wrapper
```
2. **Deploy:**
```bash
gcloud run deploy gitea-mcp-wrapper \
--image gcr.io/PROJECT_ID/gitea-mcp-wrapper \
--platform managed \
--region us-central1 \
--allow-unauthenticated \
--set-env-vars GITEA_URL=https://gitea.example.com \
--set-secrets GITEA_TOKEN=gitea-token:latest,AUTH_TOKEN=auth-token:latest \
--port 8000
```
### Azure Container Instances
```bash
az container create \
--resource-group myResourceGroup \
--name gitea-mcp-wrapper \
--image your-registry/gitea-mcp-wrapper:latest \
--ports 8000 \
--dns-name-label gitea-mcp \
--environment-variables \
GITEA_URL=https://gitea.example.com \
HTTP_HOST=0.0.0.0 \
HTTP_PORT=8000 \
--secure-environment-variables \
GITEA_TOKEN=your_token \
AUTH_TOKEN=your_auth_token
```
## Kubernetes Deployment
### Deployment Manifest
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: gitea-mcp-wrapper
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: gitea-mcp-wrapper
template:
metadata:
labels:
app: gitea-mcp-wrapper
spec:
containers:
- name: gitea-mcp-wrapper
image: your-registry/gitea-mcp-wrapper:latest
ports:
- containerPort: 8000
env:
- name: GITEA_URL
value: "https://gitea.example.com"
- name: HTTP_HOST
value: "0.0.0.0"
- name: HTTP_PORT
value: "8000"
- name: GITEA_TOKEN
valueFrom:
secretKeyRef:
name: gitea-secrets
key: token
- name: AUTH_TOKEN
valueFrom:
secretKeyRef:
name: gitea-secrets
key: auth-token
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 5
periodSeconds: 10
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
---
apiVersion: v1
kind: Service
metadata:
name: gitea-mcp-wrapper
namespace: default
spec:
selector:
app: gitea-mcp-wrapper
ports:
- protocol: TCP
port: 80
targetPort: 8000
type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: gitea-mcp-wrapper
namespace: default
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
tls:
- hosts:
- mcp.example.com
secretName: mcp-tls
rules:
- host: mcp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: gitea-mcp-wrapper
port:
number: 80
```
### Secrets Management
```bash
# Create secret
kubectl create secret generic gitea-secrets \
--from-literal=token=your_gitea_token \
--from-literal=auth-token=your_auth_token \
--namespace=default
```
## Troubleshooting
### Container Won't Start
```bash
# Check logs
docker-compose logs gitea-mcp-wrapper
# Check container status
docker-compose ps
# Rebuild image
docker-compose build --no-cache
docker-compose up -d
```
### Health Check Failing
```bash
# Test health endpoint directly
docker exec gitea-mcp-wrapper curl http://localhost:8000/health
# Check if server is listening
docker exec gitea-mcp-wrapper netstat -tlnp
```
### Cannot Reach Gitea from Container
```bash
# Test connectivity
docker exec gitea-mcp-wrapper curl -v https://gitea.example.com
# Check DNS resolution
docker exec gitea-mcp-wrapper nslookup gitea.example.com
# For docker-compose, ensure network allows egress
```
### High Memory Usage
```bash
# Check container stats
docker stats gitea-mcp-wrapper
# Adjust resource limits in docker-compose.yml
deploy:
resources:
limits:
memory: 256M
```
### Authentication Failures
```bash
# Verify AUTH_TOKEN is set
docker exec gitea-mcp-wrapper printenv AUTH_TOKEN
# Test with curl
curl -H "Authorization: Bearer YOUR_TOKEN" http://localhost:8000/tools/list
# Check logs for auth failures
docker-compose logs gitea-mcp-wrapper | grep -i auth
```
## Scaling Considerations
### Horizontal Scaling
The wrapper is stateless and can be scaled horizontally:
```yaml
# docker-compose.yml
services:
gitea-mcp-wrapper:
deploy:
replicas: 3
```
Or in Kubernetes:
```bash
kubectl scale deployment gitea-mcp-wrapper --replicas=5
```
### Load Balancing
Use a load balancer to distribute traffic:
- Docker Swarm: Built-in load balancing
- Kubernetes: Service with multiple pods
- Cloud: AWS ALB, GCP Load Balancer, Azure Load Balancer
### Caching
Consider caching responses to reduce Gitea API load:
- Add Redis or Memcached
- Cache tool list responses
- Cache frequently accessed issues/labels
### Rate Limiting
Implement rate limiting at reverse proxy level to prevent API abuse:
**Nginx:**
```nginx
limit_req_zone $binary_remote_addr zone=mcp:10m rate=10r/s;
limit_req zone=mcp burst=20 nodelay;
```
**Caddy:**
```caddyfile
rate_limit {
rate 100r/m
}
```
## Backup and Disaster Recovery
### Configuration Backup
```bash
# Backup .env file
cp .env .env.backup.$(date +%Y%m%d)
# Backup docker-compose.yml
cp docker-compose.yml docker-compose.yml.backup.$(date +%Y%m%d)
```
### Image Backup
```bash
# Save Docker image
docker save gitea-mcp-wrapper:latest | gzip > gitea-mcp-wrapper-backup.tar.gz
# Load Docker image
docker load < gitea-mcp-wrapper-backup.tar.gz
```
### Recovery Plan
1. Restore configuration files
2. Rebuild or load Docker image
3. Start services: `docker-compose up -d`
4. Verify health: `curl http://localhost:8000/health`
5. Test authentication and tool access
## Production Checklist
- [ ] HTTPS configured via reverse proxy
- [ ] `AUTH_TOKEN` set and secure
- [ ] Secrets stored in secrets manager (not `.env`)
- [ ] Health checks configured
- [ ] Monitoring and alerting set up
- [ ] Logs aggregated and retained
- [ ] Firewall rules configured
- [ ] Rate limiting enabled
- [ ] Resource limits set
- [ ] Backup strategy in place
- [ ] Disaster recovery plan documented
- [ ] Security updates scheduled
- [ ] Token rotation process defined
---
**For questions or issues, please open an issue on the [GitHub repository](https://github.com/lmiranda/gitea-mcp-remote/issues).**