Atomic Deployments
Super Simple Includes supports flexible deployment patterns for production use cases.
Atomic Deployments with ssi atomic
The ssi atomic command provides zero-downtime deployments using automatic directory naming and symlink updates:
Basic Usage
# Deploy with automatic git hash suffix
ssi atomic site/ /var/www/production
# Creates: /var/www/production.abc123456789
# Updates: /var/www/production -> production.abc123456789
# Deploy with custom suffix type
ssi atomic site/ /var/www/production --suffix=random --suffix-length=8
# Creates: /var/www/production.xyz98765
# Updates: /var/www/production -> production.xyz98765
Smart Suffix Selection
The atomic command automatically chooses the best suffix type:
- Git repository: Uses commit hash (12 characters by default)
- No git: Uses random alphanumeric string (12 characters by default)
# In a git repository
ssi atomic site/ /var/www/production
# β production.abc123456789 (git commit hash)
# Outside git repository
ssi atomic site/ /var/www/production
# β production.xyz123456789 (random string)
How Atomic Deployments Work
- Build Phase: SSI builds your site to a new directory with unique suffix
- Verification Phase: The build completes successfully or fails atomically
- Switch Phase: The symlink is automatically updated to point to the new directory
- Zero Downtime: Users see no interruption during the switch
Advanced Options
# Use git hash with specific length (requires .git in source directory)
ssi atomic site/ /var/www/production --suffix=git --suffix-length=short
# β production.abc1234567 (10 characters)
# Use timestamp suffix
ssi atomic site/ /var/www/production --suffix=timestamp
# β production.20240819105333123456789
# Preview what would happen
ssi --dry-run atomic site/ /var/www/production
Regular Deployments with ssi deploy
For non-atomic deployments, use the standard deploy command:
# Direct deployment to specific directory
ssi deploy site/ /var/www/html
# Deploy to versioned directory manually
ssi deploy site/ "/var/www/app-$(date +%Y%m%d)"
Web Server Configuration
Nginx Example
server {
listen 80;
server_name example.com;
# Serve from the symlink
root /var/www/production;
location / {
try_files $uri $uri/ /index.html;
}
}
Apache Example
<VirtualHost *:80>
ServerName example.com
# Serve from the symlink
DocumentRoot /var/www/production
<Directory /var/www/production>
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
</VirtualHost>
Personal Development Server
For local development with user home directories:
server {
listen 8080;
server_name localhost;
# Serve from user's public_html symlink
root /home/username/public_html;
location / {
try_files $uri $uri/ /index.html;
}
}
Rollback
Since each atomic deployment creates its own directory, rollback is simple:
# List available deployments (look for .suffix directories)
ls -la /var/www/production.*
# Rollback to specific deployment
ln -sfn /var/www/production.abc123456789 /var/www/production
# Or rollback to previous deployment automatically
PREV=$(ls -t /var/www/production.* | sed -n '2p')
ln -sfn "$PREV" /var/www/production
Cleanup
Remove old deployments to save disk space:
# Keep only the 5 most recent deployments
cd /var/www
ls -dt production.* | tail -n +6 | xargs rm -rf
Preserving Dynamic Files
Use the preserve feature to maintain files across deployments:
# In ssi-config.toml
[[step]]
emoji = "π"
path = "preservelist.txt"
processing = "preserve"
Example preservelist.txt:
sitemap.xml
robots.txt
uploads/
logs/
Recommended Practices
For Production Deployments
- Use
ssi atomicfor zero-downtime deployments - Monitor disk space and clean up old deployments regularly
- Use
--dry-runto preview deployments before running them
Development vs Production
# Development: Direct deployment
ssi deploy site/ output/
# Personal dev server: Deploy to home directory
ssi atomic site/ ~/public_html
# Staging: Test atomic deployment
ssi atomic site/ /var/www/staging
# Production: Atomic deployment
ssi atomic site/ /var/www/production
Automation Examples
# CI/CD pipeline deployment
ssi atomic site/ /var/www/production --suffix=git --suffix-length=12
# With health check
ssi atomic site/ /var/www/production && curl -f http://localhost/health
ssi atomic self-heals if the deployment target directory is deleted between runs
(for example, by a cleanup script or disk cleanup). It emits a warning and proceeds
automatically, making it safe for unattended cron or CI execution without any extra
guard logic.
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"