Documentation Deployment¶
This guide covers the deployment of the MkDocs documentation to docs.meister-bill.com.
Architecture Overview¶
The documentation is hosted as a separate Fly.io app (meisterbill-docs) using a lightweight nginx container that serves the static MkDocs-generated HTML files.
Key Components: - MkDocs - Static site generator for documentation - nginx - Web server serving static files - Fly.io - Hosting platform with auto-scaling - Gitea CI/CD - Automated build and deployment
Infrastructure Setup¶
Fly.io Configuration¶
App Name: meisterbill-docs
Region: dfw (Dallas)
VM Size: shared-cpu-1x with 256MB memory
Auto-scaling: 0-N machines (scales to zero when idle)
URL: https://docs.meister-bill.com
File Structure¶
meister-bill/
├── mkdocs.yml # MkDocs configuration
├── docs/ # Documentation source files
├── site/ # Generated static files (gitignored)
├── infra/
│ ├── docker/
│ │ └── Dockerfile.docs # Multi-stage Docker build
│ ├── nginx/
│ │ └── docs.conf # Nginx configuration
│ └── fly/
│ └── docs.toml # Fly.io app configuration
└── .gitea/workflows/
└── deploy.yml # CI/CD pipeline
Deployment Pipeline¶
CI/CD Workflow¶
The documentation deployment is integrated into the main CI/CD pipeline in .gitea/workflows/deploy.yml:
- Build Phase: ```yaml
- Install mkdocs and mkdocs-material
- Run mkdocs build --strict
-
Verify site/ directory exists ```
-
Deploy Phase: ```yaml
- Deploy to Fly.io using remote builder
- Config: infra/fly/docs.toml
- Dockerfile: infra/docker/Dockerfile.docs ```
Docker Build Process¶
The Dockerfile uses a multi-stage build:
Stage 1: Builder
- Base image: squidfunk/mkdocs-material:latest
- Copies mkdocs.yml and docs/ directory
- Runs mkdocs build --strict to generate site/
Stage 2: Server
- Base image: nginx:stable-alpine
- Copies built site from stage 1
- Copies nginx configuration
- Exposes port 80
- Includes health check
Nginx Configuration¶
Located at infra/nginx/docs.conf:
Features:
- Static file serving from /usr/share/nginx/html
- Gzip compression for text files
- Aggressive caching for static assets (1 year)
- Short caching for HTML files (1 hour)
- Security headers (X-Frame-Options, X-Content-Type-Options, etc.)
- Custom 404 error page
- Denies access to hidden files
Initial Setup¶
1. Create Fly.io App¶
# Create the app
flyctl apps create meisterbill-docs
# Verify app was created
flyctl apps list | grep meisterbill-docs
2. Add SSL Certificate¶
# Add custom domain and provision SSL certificate
flyctl certs add docs.meister-bill.com --app meisterbill-docs
# Check certificate status
flyctl certs show docs.meister-bill.com --app meisterbill-docs
3. Configure DNS¶
Add DNS records for docs.meister-bill.com:
Type: A
Name: docs
Value: <fly-ipv4-address>
Type: AAAA
Name: docs
Value: <fly-ipv6-address>
Get the IP addresses:
flyctl ips list --app meisterbill-docs
4. Test Local Build¶
Before deploying, test the Docker build locally:
# Build the Docker image
docker build -f infra/docker/Dockerfile.docs -t meisterbill-docs .
# Run locally
docker run -p 8080:80 meisterbill-docs
# Test in browser
open http://localhost:8080
5. Manual Deployment (First Time)¶
# Deploy to Fly.io
flyctl deploy --remote-only \
--config infra/fly/docs.toml \
--dockerfile infra/docker/Dockerfile.docs
# Check deployment status
flyctl status --app meisterbill-docs
# View logs
flyctl logs --app meisterbill-docs
Automated Deployment¶
After initial setup, deployments happen automatically via CI/CD:
- Push changes to
mainbranch - CI/CD pipeline runs:
- Builds schemas
- Builds documentation (new step)
- Builds WEB app
- Runs WEB tests
- Builds API
- Runs API tests
- Deploys WEB
- Deploys API
- Deploys DOCS (new step)
Updating Documentation¶
Adding New Pages¶
- Create
.mdfile indocs/directory - Update
mkdocs.ymlnavigation section - Commit and push to
main - CI/CD automatically deploys
Example:
nav:
- Home: index.md
- New Section:
- New Page: path/to/new-page.md
Updating Existing Pages¶
- Edit
.mdfile indocs/directory - Test locally:
mkdocs serve - Commit and push to
main - CI/CD automatically deploys
Monitoring & Operations¶
Check App Status¶
# App status
flyctl status --app meisterbill-docs
# View logs
flyctl logs --app meisterbill-docs
# Check metrics
flyctl metrics --app meisterbill-docs
Scaling¶
The app is configured to auto-scale from 0 to N machines:
[http_service]
auto_stop_machines = 'stop'
auto_start_machines = true
min_machines_running = 0
Benefits: - Scales to zero when idle (cost savings) - Automatically starts on incoming requests - Cold start time: ~2-3 seconds
Manual Scaling¶
# Scale to specific number of machines
flyctl scale count 1 --app meisterbill-docs
# View current scaling
flyctl scale show --app meisterbill-docs
Troubleshooting¶
Documentation Not Building¶
Error: mkdocs build --strict fails
Solutions:
1. Check for broken links in documentation
2. Run locally: mkdocs build --strict to see error
3. Fix markdown syntax errors
4. Ensure all referenced files exist
Deployment Fails¶
Error: Fly.io deployment fails
Solutions:
1. Check Fly.io logs: flyctl logs --app meisterbill-docs
2. Verify FLY_TOKEN secret is set in Gitea
3. Check Docker build locally
4. Ensure app exists: flyctl apps list
Site Not Accessible¶
Error: docs.meister-bill.com not reachable
Solutions:
1. Check DNS propagation: dig docs.meister-bill.com
2. Verify certificate: flyctl certs show docs.meister-bill.com --app meisterbill-docs
3. Check app status: flyctl status --app meisterbill-docs
4. View logs: flyctl logs --app meisterbill-docs
Nginx Errors¶
Error: 404 or 500 errors from nginx
Solutions:
1. Check nginx config: infra/nginx/docs.conf
2. Verify files copied correctly in Dockerfile
3. Check container logs: flyctl logs --app meisterbill-docs
4. Test locally with Docker
Performance Optimization¶
Caching Strategy¶
Static Assets (CSS, JS, images):
- Cache duration: 1 year
- Cache-Control: public, immutable
- No access logs
HTML Files:
- Cache duration: 1 hour
- Cache-Control: public, must-revalidate
Compression¶
Gzip compression enabled for: - text/plain - text/css - text/javascript - application/json - application/javascript - image/svg+xml
Compression Level: 6 (balanced) Min Size: 1024 bytes
Health Checks¶
Docker Health Check:
- Interval: 30s
- Timeout: 3s
- Retries: 3
- Command: wget --spider http://localhost/
Fly.io Health Check:
- Type: HTTP
- Path: /
- Interval: 30s
- Grace Period: 10s
- Timeout: 5s
Cost Estimation¶
Fly.io Resources: - VM: shared-cpu-1x (256MB) = $0.00 (free tier) - Bandwidth: First 100GB free - Auto-scaling to zero = minimal costs
Expected Monthly Cost: $0 (within free tier limits)
Security¶
Implemented Security Measures:
- HTTPS Enforcement:
force_https = truein fly.toml - Security Headers:
- X-Frame-Options: SAMEORIGIN
- X-Content-Type-Options: nosniff
- X-XSS-Protection: 1; mode=block
- Referrer-Policy: no-referrer-when-downgrade
- Hidden File Protection: Nginx denies access to
.files - Minimal Attack Surface: Static files only, no backend
- Regular Updates: Alpine-based images for security patches
Maintenance¶
Regular Tasks¶
-
Update MkDocs:
bash pip install --upgrade mkdocs mkdocs-material -
Review Logs:
bash flyctl logs --app meisterbill-docs -
Check Certificate Expiry:
bash flyctl certs show docs.meister-bill.com --app meisterbill-docs -
Monitor Metrics:
bash flyctl metrics --app meisterbill-docs
Updating Infrastructure¶
To update Nginx config:
1. Edit infra/nginx/docs.conf
2. Test locally with Docker
3. Commit and push (triggers redeploy)
To update Fly.io config:
1. Edit infra/fly/docs.toml
2. Commit and push (triggers redeploy)
To update Dockerfile:
1. Edit infra/docker/Dockerfile.docs
2. Test locally: docker build -f infra/docker/Dockerfile.docs .
3. Commit and push (triggers redeploy)
References¶
See Also¶
- MkDocs Configuration:
mkdocs.ymlin project root - CI/CD Pipeline:
.gitea/workflows/deploy.ymlin project root - Fly.io Main Deployment - WEB and API deployment guide