Vapora/docs/CUSTOM_DEPLOYMENT_SERVER.md
Jesús Pérez 7110ffeea2
Some checks failed
Rust CI / Security Audit (push) Has been cancelled
Rust CI / Check + Test + Lint (nightly) (push) Has been cancelled
Rust CI / Check + Test + Lint (stable) (push) Has been cancelled
chore: extend doc: adr, tutorials, operations, etc
2026-01-12 03:32:47 +00:00

597 lines
13 KiB
Markdown

# Custom Documentation Deployment Server
Complete guide for setting up and configuring custom deployment servers for mdBook documentation.
## Overview
VAPORA supports multiple custom deployment methods:
- **SSH/SFTP** — Direct file synchronization to remote servers
- **HTTP** — API-based deployment with REST endpoints
- **Docker** — Container registry deployment
- **AWS S3** — Cloud object storage with CloudFront CDN
- **Google Cloud Storage** — GCS with cache control
## 🔐 Prerequisites
### Repository Secrets Setup
Add these secrets to GitHub repository (**Settings** → **Secrets and variables****Actions**):
#### Core Secrets (all methods)
```
DOCS_DEPLOY_METHOD # ssh, sftp, http, docker, s3, gcs
```
#### SSH/SFTP Method
```
DOCS_DEPLOY_HOST # docs.your-domain.com
DOCS_DEPLOY_USER # docs (remote user)
DOCS_DEPLOY_PATH # /var/www/vapora-docs
DOCS_DEPLOY_KEY # SSH private key (base64 encoded)
```
#### HTTP Method
```
DOCS_DEPLOY_ENDPOINT # https://deploy.your-domain.com/api/deploy
DOCS_DEPLOY_TOKEN # Authentication bearer token
```
#### AWS S3 Method
```
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
AWS_DOCS_BUCKET # vapora-docs-prod
AWS_REGION # us-east-1
```
#### Google Cloud Storage Method
```
GCS_CREDENTIALS_FILE # Service account JSON (base64 encoded)
GCS_DOCS_BUCKET # vapora-docs-prod
```
#### Docker Registry Method
```
DOCKER_REGISTRY # registry.your-domain.com
DOCKER_USERNAME
DOCKER_PASSWORD
```
---
## 📝 Deployment Script
The deployment script is located at: `.scripts/deploy-docs.sh`
### Script Features
- ✅ Supports 6 deployment methods
- ✅ Pre-flight validation (connectivity, required files)
- ✅ Automatic backups (SSH/SFTP)
- ✅ Post-deployment verification
- ✅ Detailed logging
- ✅ Rollback capability (SSH)
### Configuration Files
```
.scripts/
├── deploy-docs.sh (Main deployment script)
├── .deploy-config.production (Production config)
└── .deploy-config.staging (Staging config)
```
### Running Locally
```bash
# Build locally first
cd docs && mdbook build
# Deploy to production
bash .scripts/deploy-docs.sh production
# Deploy to staging
bash .scripts/deploy-docs.sh staging
# View logs
tail -f /tmp/docs-deploy-*.log
```
---
## 🔧 SSH/SFTP Deployment Setup
### 1. Create Deployment User on Remote Server
```bash
# SSH into your server
ssh user@docs.your-domain.com
# Create docs user
sudo useradd -m -d /var/www/vapora-docs -s /bin/bash docs
# Set up directory
sudo mkdir -p /var/www/vapora-docs/backups
sudo chown -R docs:docs /var/www/vapora-docs
sudo chmod 755 /var/www/vapora-docs
```
### 2. Configure SSH Key
```bash
# On your deployment server
sudo -u docs mkdir -p /var/www/vapora-docs/.ssh
sudo -u docs chmod 700 /var/www/vapora-docs/.ssh
# Create authorized_keys
sudo -u docs touch /var/www/vapora-docs/.ssh/authorized_keys
sudo -u docs chmod 600 /var/www/vapora-docs/.ssh/authorized_keys
```
### 3. Add Public Key to Server
```bash
# Locally, generate key (if needed)
ssh-keygen -t ed25519 -f ~/.ssh/vapora-docs -N ""
# Add to server's authorized_keys
cat ~/.ssh/vapora-docs.pub | ssh user@docs.your-domain.com \
"sudo -u docs tee -a /var/www/vapora-docs/.ssh/authorized_keys"
# Test connection
ssh -i ~/.ssh/vapora-docs docs@docs.your-domain.com "ls -la"
```
### 4. Add to GitHub Secrets
```bash
# Encode private key (base64)
cat ~/.ssh/vapora-docs | base64 -w0 | pbcopy
# Paste into GitHub Secrets:
# Settings → Secrets → New repository secret
# Name: DOCS_DEPLOY_KEY
# Value: [paste base64-encoded key]
```
### 5. Add SSH Configuration Secrets
```
DOCS_DEPLOY_METHOD = ssh
DOCS_DEPLOY_HOST = docs.your-domain.com
DOCS_DEPLOY_USER = docs
DOCS_DEPLOY_PATH = /var/www/vapora-docs
DOCS_DEPLOY_KEY = [base64-encoded private key]
```
### 6. Set Up Web Server
```bash
# On remote server, configure nginx
sudo tee /etc/nginx/sites-available/vapora-docs > /dev/null << 'EOF'
server {
listen 80;
server_name docs.your-domain.com;
root /var/www/vapora-docs/docs;
location / {
index index.html;
try_files $uri $uri/ /index.html;
}
location ~ \.(js|css|fonts|images)$ {
expires 1h;
add_header Cache-Control "public, immutable";
}
}
EOF
# Enable site
sudo ln -s /etc/nginx/sites-available/vapora-docs \
/etc/nginx/sites-enabled/vapora-docs
# Test and reload
sudo nginx -t && sudo systemctl reload nginx
```
---
## 🌐 HTTP API Deployment Setup
### 1. Create Deployment Endpoint
Implement an HTTP endpoint that accepts deployments:
```python
# Example: Flask deployment API
from flask import Flask, request, jsonify
import tarfile
import os
from pathlib import Path
app = Flask(__name__)
DOCS_PATH = "/var/www/vapora-docs"
BACKUP_PATH = f"{DOCS_PATH}/backups"
@app.route('/api/deploy', methods=['POST'])
def deploy():
# Verify token
token = request.headers.get('Authorization', '').replace('Bearer ', '')
if not verify_token(token):
return {'error': 'Unauthorized'}, 401
# Check for archive
if 'archive' not in request.files:
return {'error': 'No archive provided'}, 400
archive = request.files['archive']
# Create backup
os.makedirs(BACKUP_PATH, exist_ok=True)
backup_name = f"backup_{int(time.time())}"
os.rename(f"{DOCS_PATH}/current",
f"{BACKUP_PATH}/{backup_name}")
# Extract archive
os.makedirs(f"{DOCS_PATH}/current", exist_ok=True)
with tarfile.open(fileobj=archive) as tar:
tar.extractall(f"{DOCS_PATH}/current")
# Update symlink
os.symlink(f"{DOCS_PATH}/current", f"{DOCS_PATH}/docs")
return {'status': 'deployed', 'backup': backup_name}, 200
@app.route('/health', methods=['GET'])
def health():
return {'status': 'healthy'}, 200
def verify_token(token):
# Implement your token verification
return token == os.getenv('DEPLOY_TOKEN')
if __name__ == '__main__':
app.run(host='127.0.0.1', port=5000)
```
### 2. Configure Nginx Reverse Proxy
```nginx
upstream deploy_api {
server 127.0.0.1:5000;
}
server {
listen 443 ssl http2;
server_name deploy.your-domain.com;
ssl_certificate /etc/letsencrypt/live/deploy.your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/deploy.your-domain.com/privkey.pem;
# API endpoint
location /api/deploy {
proxy_pass http://deploy_api;
client_max_body_size 100M;
}
# Health check
location /health {
proxy_pass http://deploy_api;
}
}
```
### 3. Add GitHub Secrets
```
DOCS_DEPLOY_METHOD = http
DOCS_DEPLOY_ENDPOINT = https://deploy.your-domain.com/api/deploy
DOCS_DEPLOY_TOKEN = your-secure-token
```
---
## ☁️ AWS S3 Deployment Setup
### 1. Create S3 Bucket and IAM User
```bash
# Create bucket
aws s3 mb s3://vapora-docs-prod --region us-east-1
# Create IAM user
aws iam create-user --user-name vapora-docs-deployer
# Create access key
aws iam create-access-key --user-name vapora-docs-deployer
# Create policy
cat > /tmp/s3-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::vapora-docs-prod",
"arn:aws:s3:::vapora-docs-prod/*"
]
}
]
}
EOF
# Attach policy
aws iam put-user-policy \
--user-name vapora-docs-deployer \
--policy-name S3Access \
--policy-document file:///tmp/s3-policy.json
```
### 2. Configure CloudFront (Optional)
```bash
# Create distribution
aws cloudfront create-distribution \
--origin-domain-name vapora-docs-prod.s3.amazonaws.com \
--default-root-object index.html
```
### 3. Add GitHub Secrets
```
DOCS_DEPLOY_METHOD = s3
AWS_ACCESS_KEY_ID = AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
AWS_DOCS_BUCKET = vapora-docs-prod
AWS_REGION = us-east-1
```
---
## 🐳 Docker Registry Deployment Setup
### 1. Create Docker Registry
```bash
# Using Docker Registry (self-hosted)
docker run -d \
-p 5000:5000 \
--restart always \
--name registry \
-e REGISTRY_STORAGE_DELETE_ENABLED=true \
registry:2
# Or use managed: AWS ECR, Docker Hub, etc.
```
### 2. Configure Registry Authentication
```bash
# Create credentials
echo "username:$(openssl passwd -crypt password)" > /auth/htpasswd
# Docker login
docker login registry.your-domain.com \
-u username -p password
```
### 3. Add GitHub Secrets
```
DOCS_DEPLOY_METHOD = docker
DOCKER_REGISTRY = registry.your-domain.com
DOCKER_USERNAME = username
DOCKER_PASSWORD = password
```
---
## 🔔 Webhooks & Notifications
### Slack Notification
Add webhook URL to secrets:
```
NOTIFICATION_WEBHOOK = https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXX
```
Workflow sends JSON payload:
```json
{
"status": "success",
"environment": "production",
"commit": "abc123...",
"branch": "main",
"timestamp": "2026-01-12T14:30:00Z",
"run_url": "https://github.com/vapora-platform/vapora/actions/runs/123"
}
```
### Custom Webhook Handler
```python
@app.route('/webhook/deployment', methods=['POST'])
def deployment_webhook():
data = request.json
if data['status'] == 'success':
send_slack_message(f"✅ Docs deployed: {data['commit']}")
else:
send_slack_message(f"❌ Deployment failed: {data['commit']}")
return {'ok': True}
```
---
## 🔄 Deployment Workflow
### Automatic Deployment Flow
```
Push to main (docs/ changes)
mdBook Build & Deploy Workflow
├─ Build (2-3s)
├─ Quality Check
└─ Upload Artifact
mdBook Publish Workflow (triggered)
├─ Download Artifact
├─ Deploy to Custom Server
│ ├─ Pre-flight Checks
│ ├─ Deployment Method
│ │ ├─ SSH: rsync files + backup
│ │ ├─ HTTP: upload tarball
│ │ ├─ S3: sync to bucket
│ │ └─ Docker: push image
│ └─ Post-deployment Verify
├─ Create Deployment Record
└─ Send Notifications
Documentation Live
```
### Manual Deployment
```bash
# Local build
cd docs && mdbook build
# Deploy using script
bash .scripts/deploy-docs.sh production
# Or specific environment
bash .scripts/deploy-docs.sh staging
```
---
## 🆘 Troubleshooting
### SSH Deployment Fails
**Error**: `Permission denied (publickey)`
**Fix**:
```bash
# Verify key is in authorized_keys
cat ~/.ssh/vapora-docs.pub | ssh user@server \
"sudo -u docs cat >> /var/www/vapora-docs/.ssh/authorized_keys"
# Test connection
ssh -i ~/.ssh/vapora-docs -v docs@server.com
```
### HTTP Deployment Fails
**Error**: `HTTP 401 Unauthorized`
**Fix**:
- Verify token in GitHub Secrets matches server
- Check HTTPS certificate validity
- Verify endpoint is reachable
```bash
curl -H "Authorization: Bearer $TOKEN" https://deploy.server.com/health
```
### S3 Deployment Fails
**Error**: `NoSuchBucket`
**Fix**:
- Verify bucket name in secrets
- Check IAM policy allows the action
- Verify AWS credentials
```bash
aws s3 ls s3://vapora-docs-prod/
```
### Docker Deployment Fails
**Error**: `unauthorized: authentication required`
**Fix**:
- Verify credentials in secrets
- Test Docker login locally
```bash
docker login registry.your-domain.com
```
---
## 📊 Deployment Configuration Reference
### Production Template
```bash
# .deploy-config.production
DEPLOY_METHOD="ssh"
DEPLOY_HOST="docs.vapora.io"
DEPLOY_USER="docs"
DEPLOY_PATH="/var/www/vapora-docs"
BACKUP_RETENTION_DAYS=30
NOTIFY_ON_SUCCESS="true"
NOTIFY_ON_FAILURE="true"
```
### Staging Template
```bash
# .deploy-config.staging
DEPLOY_METHOD="ssh"
DEPLOY_HOST="staging-docs.vapora.io"
DEPLOY_USER="docs-staging"
DEPLOY_PATH="/var/www/vapora-docs-staging"
BACKUP_RETENTION_DAYS=7
NOTIFY_ON_SUCCESS="false"
NOTIFY_ON_FAILURE="true"
```
---
## ✅ Verification Checklist
- [ ] SSH/SFTP user created and configured
- [ ] SSH keys generated and added to server
- [ ] Web server (nginx/apache) configured
- [ ] GitHub secrets added for deployment method
- [ ] Test push to main with docs/ changes
- [ ] Monitor Actions tab for workflow
- [ ] Verify deployment completed
- [ ] Check documentation site
- [ ] Test rollback procedure (if applicable)
- [ ] Set up monitoring/alerts
---
## 📚 Additional Resources
- [AWS S3 Documentation](https://docs.aws.amazon.com/s3/)
- [Google Cloud Storage](https://cloud.google.com/storage/docs)
- [Docker Registry](https://docs.docker.com/registry/)
- [GitHub Actions Documentation](https://docs.github.com/en/actions)
---
**Last Updated**: 2026-01-12
**Status**: ✅ Production Ready
For deployment script details, see: `.scripts/deploy-docs.sh`