Skip to content

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:

  1. Build Phase: ```yaml
  2. Install mkdocs and mkdocs-material
  3. Run mkdocs build --strict
  4. Verify site/ directory exists ```

  5. Deploy Phase: ```yaml

  6. Deploy to Fly.io using remote builder
  7. Config: infra/fly/docs.toml
  8. 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:

  1. Push changes to main branch
  2. CI/CD pipeline runs:
  3. Builds schemas
  4. Builds documentation (new step)
  5. Builds WEB app
  6. Runs WEB tests
  7. Builds API
  8. Runs API tests
  9. Deploys WEB
  10. Deploys API
  11. Deploys DOCS (new step)

Updating Documentation

Adding New Pages

  1. Create .md file in docs/ directory
  2. Update mkdocs.yml navigation section
  3. Commit and push to main
  4. CI/CD automatically deploys

Example:

nav:
  - Home: index.md
  - New Section:
    - New Page: path/to/new-page.md

Updating Existing Pages

  1. Edit .md file in docs/ directory
  2. Test locally: mkdocs serve
  3. Commit and push to main
  4. 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:

  1. HTTPS Enforcement: force_https = true in fly.toml
  2. Security Headers:
  3. X-Frame-Options: SAMEORIGIN
  4. X-Content-Type-Options: nosniff
  5. X-XSS-Protection: 1; mode=block
  6. Referrer-Policy: no-referrer-when-downgrade
  7. Hidden File Protection: Nginx denies access to . files
  8. Minimal Attack Surface: Static files only, no backend
  9. Regular Updates: Alpine-based images for security patches

Maintenance

Regular Tasks

  1. Update MkDocs: bash pip install --upgrade mkdocs mkdocs-material

  2. Review Logs: bash flyctl logs --app meisterbill-docs

  3. Check Certificate Expiry: bash flyctl certs show docs.meister-bill.com --app meisterbill-docs

  4. 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.yml in project root
  • CI/CD Pipeline: .gitea/workflows/deploy.yml in project root
  • Fly.io Main Deployment - WEB and API deployment guide