Building Production Sites
Production Patterns
These patterns cover best practices for production deployments, building on the techniques from the examples.
Full-Site Architecture
Example 99 demonstrates a complete production site using all SSI features together.
# 1. Page processing
[[step]]
emoji = "π"
path = "pages/"
processing = "page"
# 2. Reusable HTML components
[[step]]
emoji = "π"
path = "blocks/"
processing = "include"
type = "html"
# 3. Content (per-page resolution)
[[step]]
emoji = "π"
path = "content/"
processing = "include"
type = "html"
# 4. Site-wide variables
[[step]]
emoji = "π¬"
path = "texts/"
processing = "include"
type = "plain"
options = ["inline"]
This architecture separates:
- Structure (
pages/) β HTML skeleton - Components (
blocks/) β Reusable UI widgets - Content (
content/) β Page-specific content - Variables (
texts/) β Site-wide strings
Directory structure:
site/
βββ ssi-config.toml
βββ pages/
β βββ index.html
β βββ about.html
β βββ details.html
βββ blocks/
β βββ header.html
β βββ footer.html
β βββ nav.html
βββ content/
β βββ index/ # Per-page content
β β βββ hero.html
β β βββ features.html
β βββ about/
β β βββ story.html
β βββ details/
β βββ info.html
βββ texts/
βββ site-name.txt
βββ license-notice.txt
βββ tagline.txt
Try it:
cd examples/99-full-site
ssi deploy site/ output/
Production Configuration Patterns
Validated Assets
Use checksums for critical files:
[[step]]
emoji = "π¦"
path = "assets/"
processing = "copy"
options = ["checksum"]
[[step]]
emoji = "π€"
path = "fonts/"
destination = "fonts"
processing = "copy"
Generate checksums:
xxh3sum assets/* > assets.xxh3
xxh3sum fonts/* > fonts.xxh3
Build Information Footer
Embed build metadata in every page:
[[step]]
emoji = "π"
processing = "include"
type = "datetime"
options = ["inline"]
[[step]]
emoji = "π§"
processing = "include"
type = "git"
path = ".git/"
options = ["inline"]
[[step]]
emoji = "π"
processing = "include"
type = "environment"
path = "allowed-env.txt"
options = ["inline"]
Footer component (blocks/build-info.html):
<footer class="build-info">
<p>Built: πiso</p>
<p>Version: abc123 (main)</p>
<p>Build: #πBUILD_NUMBER</p>
</footer>
Component Library
SSIβs flat processing means subdirectories are ignored. Use prefixed filenames to organize your components:
blocks/
βββ layout-header.html
βββ layout-footer.html
βββ ui-alert-info.html
βββ ui-card.html
βββ nav-breadcrumb.html
Multi-Environment Configuration
Use environment variables for deployment targets:
allowed-env.txt:
DEPLOY_ENV
API_ENDPOINT
CDN_URL
In templates:
<script>
const CONFIG = {
environment: 'πDEPLOY_ENV',
api: 'πAPI_ENDPOINT',
cdn: 'πCDN_URL'
};
</script>
Deploy:
# Production
DEPLOY_ENV=production \
API_ENDPOINT=https://api.example.com \
CDN_URL=https://cdn.example.com \
ssi deploy site/ production/
# Staging
DEPLOY_ENV=staging \
API_ENDPOINT=https://staging-api.example.com \
CDN_URL=https://staging-cdn.example.com \
ssi deploy site/ staging/
Performance
Incremental Deployments
Preserve dynamically-generated content across rebuilds:
[[step]]
emoji = "π"
path = "preservelist.txt"
processing = "preserve"
preservelist.txt:
# Search index (generated by external tool)
search-index.json
# Sitemap (updated separately)
sitemap.xml
# User uploads
uploads/*.jpg
uploads/*.png
Security
HTML Escaping
Use appropriate content types:
# Safe: HTML-escaped by default
[[step]]
emoji = "π"
path = "user-content/"
processing = "include"
type = "plain"
# Only for developer-controlled content
[[step]]
emoji = "π"
path = "trusted-blocks/"
processing = "include"
type = "html"
Environment Variable Allowlist
Never expose secrets:
# Good: build metadata
APP_VERSION
BUILD_NUMBER
DEPLOY_ENV
# Bad: never expose secrets
# DATABASE_PASSWORD
# API_KEY
# SECRET_TOKEN
Path Validation
Preserve lists are validated automatically:
# Good
sitemap.xml
images/hero.jpg
# Bad (rejected automatically)
# /etc/passwd β Absolute path
# ../../../secret β Path traversal
External Paths
Only enable when necessary:
[[step]]
emoji = "π"
path = "../shared-docs/"
processing = "include"
type = "markdown"
options = ["allow-external-paths"] # Explicit opt-in
Requires CLI flag:
ssi --allow-external-paths deploy site/ output/
CI/CD Integration
GitHub Actions
name: Deploy Site
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install SSI
run: |
cargo build --release --target x86_64-unknown-linux-musl
cp target/x86_64-unknown-linux-musl/release/ssi /usr/local/bin/
- name: Generate checksums
run: |
xxh3sum site/assets/* > site/assets.xxh3
- name: Deploy site
env:
BUILD_NUMBER: ${{ github.run_number }}
DEPLOY_ENV: production
run: |
ssi deploy site/ output/
- name: Upload to server
run: |
rsync -avz --delete output/ server:/var/www/html/
The same pattern adapts to GitLab CI, Codeberg Actions, and other CI systems β replace the Actions-specific syntax with the equivalent for your platform.
Deployment Checklist
Before production deployment:
- All examples tested locally
- Checksums generated for static assets
- Environment variables configured
- Preserve list reviewed (if using preserve)
- Build info footer added
- External paths minimized or eliminated
- No secrets in environment allowlist
- Link validation passed (
ssi validate) - No unused files (
ssi validate --warn-unused) - Tests pass in CI/CD
Common Patterns
Blog
[[step]]
emoji = "π"
path = "pages/"
processing = "page"
[[step]]
emoji = "π"
path = "posts/"
processing = "include"
type = "markdown"
options = ["markdown-h2"] # Shift headers for page structure
[[step]]
emoji = "π"
path = "blocks/"
processing = "include"
type = "html"
Documentation Site
[[step]]
emoji = "π"
path = "pages/"
processing = "page"
[[step]]
emoji = "π"
path = "docs/"
processing = "include"
type = "markdown"
[[step]]
emoji = "π"
path = "components/"
processing = "include"
type = "html"
[[step]]
emoji = "π¬"
path = "strings.toml"
processing = "include"
type = "plain"
options = ["inline"]
Landing Page
[[step]]
emoji = "π"
path = "pages/"
processing = "page"
[[step]]
emoji = "π"
path = "sections/" # Hero, features, testimonials
processing = "include"
type = "html"
[[step]]
emoji = "π¬"
path = "copy.toml" # Marketing copy
processing = "include"
type = "plain"
options = ["inline"]
[[step]]
emoji = "π¨"
path = "assets/"
processing = "copy"