Table of Contents
- Quick Start Guide
- Prerequisites
- Important: Redis/Valkey Requirement
- Architecture Overview
- Setup Methods
- Docker Compose Setup
- Step 1: Configure Traefik Static Configuration
- Step 2: Configure Dynamic Configuration
- Step 3: Docker Compose File
- Step 4: Start Services
- Standalone Traefik Setup
- Step 1: Add Plugin and Redis Provider to Traefik Configuration
- Step 2: Create Middleware Configuration
- Step 3: Configure Routers
- Step 4: Restart Traefik
- Setup Your First Repository
- Step 1: Create Repository Structure
- Step 2: Create .pages File
- Step 3: Add Your Static Files
- Step 4: Commit and Push
- Step 5: Access Your Site
- Verification Steps
- Troubleshooting
- Next Steps
- Additional Resources
- Support
Quick Start Guide
This guide will help you set up Bovine Pages Server with Traefik to host static sites from your Forgejo or Gitea repositories.
Prerequisites
Before you begin, ensure you have:
- Traefik v2.0+ installed and running (Installation Guide)
- Forgejo or Gitea instance running and accessible
- Docker (if using Docker setup) (Get Docker)
- Domain name configured to point to your Traefik server
- Redis or Valkey server for full functionality (see note below)
- Basic understanding of Traefik configuration
Important: Redis/Valkey Requirement
⚠️ Redis (or Valkey) is strongly recommended for production deployments.
While Bovine Pages Server can run with in-memory caching only, you need Redis or Valkey to unlock these critical features:
- ✅ Custom Domain HTTPS - Automatic SSL certificate generation for custom domains requires Redis provider in Traefik
- ✅ Persistent Caching - High-performance caching that survives plugin restarts
- ✅ Shared Cache - Multiple Traefik instances can share the same cache
- ✅ Custom Domain Mappings - Persistent storage of domain-to-repository mappings
Without Redis/Valkey:
- ❌ Custom domains won't get automatic HTTPS certificates
- ❌ Cache is lost on every plugin restart
- ❌ Performance will be significantly degraded
- ❌ Custom domain mappings won't persist
Quick Setup:
# Docker
docker run -d --name redis -p 6379:6379 redis:7-alpine
# Or use Valkey (Redis fork)
docker run -d --name valkey -p 6379:6379 valkey/valkey:7-alpine
See the Docker Compose example below for a complete Redis setup with Traefik.
Architecture Overview
Bovine Pages Server works as a Traefik middleware plugin:
graph LR
A[User Browser] -->|HTTPS Request| B[Traefik Reverse Proxy]
B -->|Middleware| C[Bovine Pages Server Plugin]
C -->|Fetch Content| D[Forgejo/Gitea API]
D -->|Repository Data| C
C -->|Cache| E[(Redis Cache)]
C -->|Static Files| B
B -->|HTTPS Response| A
style B fill:#37a8db,stroke:#2980b9,stroke-width:2px,color:#fff
style C fill:#9b59b6,stroke:#8e44ad,stroke-width:2px,color:#fff
style D fill:#27ae60,stroke:#229954,stroke-width:2px,color:#fff
style E fill:#e74c3c,stroke:#c0392b,stroke-width:2px,color:#fff
The plugin intercepts requests matching your pages domain pattern (e.g., *.pages.example.com), fetches content from Forgejo repositories via the API, optionally caches it in Redis for performance, and serves it as static websites through Traefik.
Setup Methods
Choose your setup method based on how you run Traefik:
- Docker Compose Setup (Recommended)
- Standalone Traefik
Docker Compose Setup
Step 1: Configure Traefik Static Configuration
Create or update your traefik.yml static configuration file:
# traefik.yml
api:
dashboard: true
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
certificatesResolvers:
letsencrypt-http:
acme:
email: your-email@example.com
storage: /letsencrypt/acme.json
httpChallenge:
entryPoint: web
# Enable plugin support
experimental:
plugins:
pages-server:
moduleName: code.squarecows.com/SquareCows/pages-server
version: v0.0.8
providers:
docker:
exposedByDefault: false
file:
directory: /etc/traefik/dynamic
watch: true
redis:
endpoints:
- "redis:6379"
rootKey: "traefik"
# Optional: Add password if Redis requires authentication
# password: "your-redis-password"
Important Configuration Notes:
experimental.pluginsenables the Bovine Pages Server plugincertificatesResolversconfigures automatic HTTPS with Let's Encryptproviders.fileallows loading dynamic configuration from filesproviders.redisenables dynamic router registration for custom domains (required for automatic SSL)- Redis provider allows Bovine Pages Server to dynamically register routers for custom domains
- See Traefik Static Configuration for more options
- See Traefik Redis Provider for Redis-specific configuration
Step 2: Configure Dynamic Configuration
Create a dynamic configuration file for the pages server middleware and routers:
File: dynamic/pages-config.yml
# dynamic/pages-config.yml
http:
middlewares:
pages-server:
plugin:
pages-server:
# Required settings
pagesDomain: pages.example.com
forgejoHost: https://git.example.com
# Optional: Authentication for private repos
# forgejoToken: your-api-token-here
# Optional: Redis caching for better performance
# enableRedisCache: true
# redisAddress: redis:6379
# redisPassword: your-redis-password
# Optional: Password protection settings
# authSecretKey: your-secret-key-here
# authCookieDuration: 3600
# Optional: Custom domains
# enableCustomDomains: true
# customDomainCacheTTL: 600
# Optional: Traefik Redis provider integration
# traefikRedisRouterEnabled: true
# traefikRedisCertResolver: letsencrypt-http
routers:
# HTTPS router for pages domain
pages-https:
rule: "HostRegexp(`{subdomain:[a-z0-9-]+}.pages.example.com`)"
entryPoints:
- websecure
middlewares:
- pages-server
service: noop@internal
tls:
certResolver: letsencrypt-http
# HTTPS router for custom domains (if enabled)
pages-custom-domains-https:
rule: "HostRegexp(`{domain:.+}`)"
entryPoints:
- websecure
middlewares:
- pages-server
service: noop@internal
priority: 1
tls:
certResolver: letsencrypt-http
# HTTP router (handles ACME challenges and redirects to HTTPS)
pages-http:
rule: "HostRegexp(`{subdomain:[a-z0-9-]+}.pages.example.com`) || HostRegexp(`{domain:.+}`)"
entryPoints:
- web
middlewares:
- pages-server
service: noop@internal
priority: 1
Configuration Highlights:
- Replace
pages.example.comwith your actual pages domain - Replace
git.example.comwith your Forgejo/Gitea instance URL - The middleware automatically handles HTTPS redirects (except for ACME challenges)
- Uses
noop@internalservice (Traefik's built-in no-op service) - See Configuration Guide for all available options
Step 3: Docker Compose File
Create or update your docker-compose.yml:
version: '3.8'
services:
traefik:
image: traefik:v3.0
container_name: traefik
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "8080:8080" # Dashboard (optional, secure in production)
volumes:
# Mount Traefik configuration
- ./traefik.yml:/etc/traefik/traefik.yml:ro
- ./dynamic:/etc/traefik/dynamic:ro
# Mount Docker socket for Docker provider
- /var/run/docker.sock:/var/run/docker.sock:ro
# Mount Let's Encrypt storage
- ./letsencrypt:/letsencrypt
environment:
- TZ=UTC
networks:
- web
# Optional: Redis for caching
redis:
image: redis:7-alpine
container_name: redis
restart: unless-stopped
command: redis-server --requirepass your-redis-password
volumes:
- redis-data:/data
networks:
- web
networks:
web:
external: true
volumes:
redis-data:
Docker Setup Notes:
- Create the
webnetwork first:docker network create web - Traefik dashboard accessible at
http://localhost:8080(secure in production!) - Let's Encrypt certificates stored in
./letsencrypt/acme.json - See Traefik Docker Documentation for more details
Step 4: Start Services
# Create Docker network
docker network create web
# Create required directories
mkdir -p dynamic letsencrypt
# Set proper permissions for Let's Encrypt storage
touch letsencrypt/acme.json
chmod 600 letsencrypt/acme.json
# Start Traefik
docker-compose up -d
# Check logs
docker-compose logs -f traefik
Standalone Traefik Setup
If you're running Traefik without Docker, follow these steps:
Step 1: Add Plugin and Redis Provider to Traefik Configuration
Edit your traefik.yml static configuration:
# Enable plugin support
experimental:
plugins:
pages-server:
moduleName: code.squarecows.com/SquareCows/pages-server
version: v0.0.8
# Add Redis provider for dynamic router registration
providers:
file:
directory: /etc/traefik/dynamic
watch: true
redis:
endpoints:
- "localhost:6379" # Update if Redis is on different host
rootKey: "traefik"
# Optional: Add password if Redis requires authentication
# password: "your-redis-password"
Note: Redis provider is required for custom domain support with automatic SSL certificates.
Step 2: Create Middleware Configuration
Create a dynamic configuration file (e.g., /etc/traefik/dynamic/pages.yml):
http:
middlewares:
pages-server:
plugin:
pages-server:
pagesDomain: pages.example.com
forgejoHost: https://git.example.com
Step 3: Configure Routers
Add routers to your dynamic configuration:
http:
routers:
pages-https:
rule: "HostRegexp(`{subdomain:[a-z0-9-]+}.pages.example.com`)"
entryPoints:
- websecure
middlewares:
- pages-server
service: noop@internal
tls:
certResolver: letsencrypt-http
Step 4: Restart Traefik
# Systemd
sudo systemctl restart traefik
# Or if running manually
traefik --configFile=/etc/traefik/traefik.yml
Setup Your First Repository
Now that Traefik is configured, let's create your first static site:
Step 1: Create Repository Structure
In your Forgejo/Gitea repository, create this structure:
your-repository/
├── .pages # Configuration file
└── public/ # Static files directory
├── index.html # Your homepage
├── about.html
└── assets/
├── style.css
└── logo.png
Step 2: Create .pages File
In your repository root, create a .pages file:
enabled: true
Optional Settings:
enabled: true
directory_index: true # Enable directory listings
custom_domain: www.example.com # Use a custom domain
password: sha256-hash-here # Password protect your site
See Configuration Guide for all options.
Step 3: Add Your Static Files
Create a simple public/index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Static Site</title>
</head>
<body>
<h1>Welcome to My Static Site!</h1>
<p>Hosted with Bovine Pages Server</p>
</body>
</html>
Step 4: Commit and Push
git add .
git commit -m "Initial pages setup"
git push origin main
Step 5: Access Your Site
Your site is now live at:
https://username.pages.example.com/repository/
Replace:
usernamewith your Forgejo/Gitea usernamepages.example.comwith your configured pages domainrepositorywith your repository name
Verification Steps
1. Check Traefik Dashboard
Access the Traefik dashboard (if enabled) to verify:
- ✅ Plugin loaded successfully
- ✅ Middleware configured
- ✅ Routers active
2. Test Basic Functionality
# Test pages domain
curl -I https://username.pages.example.com/repository/
# Should return 200 OK and show your content
3. Check Logs
# Docker setup
docker-compose logs -f traefik
# Systemd setup
journalctl -u traefik -f
Look for:
- Plugin initialization messages
- No error messages about missing configuration
- Successful requests being served
Troubleshooting
Plugin Not Loading
Problem: Traefik doesn't load the plugin
Solutions:
- Verify
experimental.pluginssection in static config - Check Traefik version (requires v2.0+)
- Ensure internet connectivity to download plugin
- Check logs:
docker-compose logs traefik
404 Errors
Problem: Getting 404 when accessing pages URL
Checklist:
- ✅ Repository has
public/folder with content - ✅ Repository has
.pagesfile withenabled: true - ✅ Router rules match your domain pattern
- ✅ DNS points to Traefik server
- ✅
forgejoHostis correct in middleware config
SSL Certificate Issues
Problem: HTTPS not working or certificate errors
Solutions:
- Check Let's Encrypt rate limits
- Verify port 80 is accessible (required for HTTP challenge)
- Check
acme.jsonpermissions:chmod 600 acme.json - Review certificate resolver configuration
- See Traefik ACME Documentation
Redis Connection Errors
Problem: Redis caching not working
Solutions:
- Verify Redis is running:
docker-compose ps redis - Check Redis address in middleware config
- Verify Redis password matches
- Plugin will fall back to in-memory cache if Redis unavailable
Next Steps
Now that you have Bovine Pages Server running:
- 📖 Read the Configuration Guide - Learn about all available options
- 🔒 Setup Password Protection - Secure private sites
- 🌐 Configure Custom Domains - Use your own domains
- 📁 Enable Directory Listings - Browse files without index.html
- 🧹 Setup Cache Reaper - Automated cleanup for production
Additional Resources
Traefik Documentation
Docker Resources
Bovine Pages Server
Support
- Issues: Report a bug
- Wiki: Full Documentation
- Changelog: Version History