Cstate Static Status Page Installation

cState is an open-source static status page generator built on Hugo that requires no server-side runtime — pages are plain HTML served from GitHub Pages, Netlify, or any CDN. This guide covers setting up cState, managing incidents with Markdown, configuring component groups, and deploying to GitHub Pages or Netlify.

Prerequisites

  • Hugo extended version 0.110.0+ installed
  • Git installed
  • A GitHub account (for GitHub Pages deployment)
  • Or a Netlify account (for Netlify deployment)
  • Node.js (optional, for theme customization)

Install Hugo

# Ubuntu/Debian - install Hugo extended edition
HUGO_VERSION="0.121.0"
wget "https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.tar.gz"
tar -xzf "hugo_extended_${HUGO_VERSION}_linux-amd64.tar.gz"
sudo mv hugo /usr/local/bin/

# Verify installation (must be "extended" version)
hugo version
# Expected: hugo v0.121.0+extended linux/amd64

# CentOS/Rocky - use snap or download binary
sudo snap install hugo --channel=extended

Create a cState Site

cState uses Hugo modules or Git submodules for the theme:

# Create a new Hugo site
hugo new site mystatus
cd mystatus

# Initialize git
git init

# Add cState as a Hugo module
cat > go.mod << 'EOF'
module github.com/yourusername/mystatus

go 1.20
EOF

# Configure cState theme via Hugo modules
cat >> config.yaml << 'EOF'
module:
  imports:
    - path: github.com/cstate/cstate
EOF

# Download the cState module
hugo mod get github.com/cstate/cstate

# Alternatively, use Git submodules
git submodule add https://github.com/cstate/cstate themes/cstate

# Copy example content from cState
# Download the example site files
curl -LO https://github.com/cstate/cstate/archive/refs/heads/master.zip
unzip master.zip
cp -r cstate-master/exampleSite/. ./
rm -rf master.zip cstate-master/

Configure Components and Groups

The main configuration lives in config.yaml:

cat > config.yaml << 'EOF'
baseURL: "https://status.example.com/"
languageCode: "en-us"
title: "My Service Status"
theme: cstate

params:
  # Site information
  description: "Real-time status for our services"
  
  # Incident colors and labels
  ok: "Operational"
  disrupted: "Degraded Performance"
  down: "Service Outage"
  notice: "Under Maintenance"
  
  # Incident status categories
  alwaysKeepBanner: false
  
  # System components to monitor
  systems:
    - name: API Gateway
      category: Core
      link: "https://api.example.com"
      
    - name: Web Application
      category: Core
      link: "https://app.example.com"
      
    - name: Database
      category: Infrastructure
      
    - name: CDN
      category: Infrastructure
      
    - name: Email Service
      category: Communications
      link: "https://mail.example.com"

  # Time format
  dateFormat: "January 2, 2006 at 15:04 UTC"
  
  # Number of incidents to show on main page
  numberOfPinnedIssues: 3
  
  # Link to incident history
  useLargeIssues: true

module:
  imports:
    - path: github.com/cstate/cstate
EOF

Manage Incidents

Incidents are Markdown files in the content/issues/ directory:

mkdir -p content/issues

# Create an active incident
cat > content/issues/api-latency-2024-01-15.md << 'EOF'
---
title: "Elevated API Latency"
date: 2024-01-15T14:30:00Z
resolved: false
resolvedWhen: ""
severity: "disrupted"
affected:
  - API Gateway
section: issue
---

We are investigating elevated response times on the API Gateway. The issue began at approximately 14:20 UTC.

*Update: 14:45 UTC* - Root cause identified as database connection pool exhaustion. We are applying a fix.

*Update: 15:10 UTC* - Fix deployed and latency returning to normal levels. Monitoring closely.
EOF

# Create a resolved incident
cat > content/issues/database-outage-2024-01-10.md << 'EOF'
---
title: "Database Primary Failover"
date: 2024-01-10T02:15:00Z
resolved: true
resolvedWhen: 2024-01-10T02:47:00Z
severity: "down"
affected:
  - Database
  - API Gateway
  - Web Application
section: issue
---

The primary database server experienced an unexpected failure at 02:15 UTC. Automatic failover to the replica was triggered at 02:18 UTC.

During this period, write operations were unavailable for approximately 3 minutes and read operations experienced elevated latency for 30 minutes.

**Resolution**: Failover completed successfully. Root cause was a kernel OOM event on the primary node due to a misconfigured buffer pool size. Configuration has been corrected and memory limits adjusted.
EOF

# Create a maintenance notice
cat > content/issues/maintenance-2024-01-20.md << 'EOF'
---
title: "Scheduled Database Maintenance"
date: 2024-01-20T02:00:00Z
resolved: true
resolvedWhen: 2024-01-20T04:00:00Z
severity: "notice"
affected:
  - Database
section: issue
---

Scheduled maintenance to upgrade the database server from PostgreSQL 14 to 16. Write operations will be briefly interrupted during the version upgrade (estimated 5 minutes).
EOF

# Preview the site locally
hugo server -D --bind 0.0.0.0 --port 1313

Multilingual Support

cState supports multiple languages via Hugo's i18n system:

# Update config.yaml for multilingual support
cat >> config.yaml << 'EOF'

languages:
  en:
    languageName: English
    weight: 1
  es:
    languageName: Español
    weight: 2
    title: "Estado de Servicio"
    params:
      description: "Estado en tiempo real de nuestros servicios"
EOF

# Create Spanish translations directory
mkdir -p i18n

# Download cState's built-in translations
# cState ships translations for EN, ES, FR, DE, and more
# Check themes/cstate/i18n/ for available files

# Create a Spanish page override
mkdir -p content/es
cat > content/es/_index.md << 'EOF'
---
title: Estado del Sistema
---
EOF

Custom Theming

# Create custom CSS override
mkdir -p static/css
cat > static/css/custom.css << 'EOF'
:root {
  --color-brand: #2563eb;
  --color-ok: #16a34a;
  --color-disrupted: #d97706;
  --color-down: #dc2626;
  --color-notice: #6366f1;
}

/* Custom header */
.nav__brand {
  font-size: 1.25rem;
  font-weight: 700;
}

/* Override component status bar colors */
.component--ok { border-left-color: var(--color-ok); }
.component--disrupted { border-left-color: var(--color-disrupted); }
.component--down { border-left-color: var(--color-down); }
EOF

# Reference custom CSS in config.yaml
cat >> config.yaml << 'EOF'

params:
  customCSS:
    - css/custom.css
    
  # Custom logo
  logo: "img/logo.png"
EOF

mkdir -p static/img
# Copy your logo to static/img/logo.png

# Override a template (create a layouts directory)
mkdir -p layouts/partials
# Copy and modify templates from themes/cstate/layouts/

Deploy to GitHub Pages

# Create the GitHub Actions workflow
mkdir -p .github/workflows
cat > .github/workflows/pages.yml << 'EOF'
name: Deploy to GitHub Pages

on:
  push:
    branches: [main]
  workflow_dispatch:

permissions:
  contents: read
  pages: write
  id-token: write

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: recursive
          
      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v2
        with:
          hugo-version: '0.121.0'
          extended: true
          
      - name: Build
        run: hugo --minify
        
      - name: Upload artifact
        uses: actions/upload-pages-artifact@v2
        with:
          path: ./public

  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v3
EOF

# Commit and push
git add .
git commit -m "Add cState status page"
git remote add origin https://github.com/yourusername/status-page.git
git push -u origin main

# Enable GitHub Pages in repository settings:
# Settings > Pages > Source: GitHub Actions

Deploy to Netlify

# Create netlify.toml
cat > netlify.toml << 'EOF'
[build]
  command = "hugo --minify"
  publish = "public"

[build.environment]
  HUGO_VERSION = "0.121.0"
  HUGO_ENV = "production"
  HUGO_ENABLEGITINFO = "true"

[[headers]]
  for = "/*"
  [headers.values]
    X-Frame-Options = "DENY"
    X-XSS-Protection = "1; mode=block"
    Content-Security-Policy = "default-src 'self'"

[context.production.environment]
  HUGO_BASEURL = "https://status.example.com"
EOF

# Push to GitHub, then:
# 1. Log in to netlify.com
# 2. New site from Git > GitHub > Select your repo
# 3. Build command: hugo --minify
# 4. Publish directory: public
# 5. Click Deploy Site

# Add custom domain in Netlify:
# Site settings > Domain management > Add domain alias

Troubleshooting

Hugo fails to build with "module not found":

# Clear module cache and re-download
hugo mod clean
hugo mod get github.com/cstate/cstate

# Check go.sum exists
ls go.sum

# Try a specific version
hugo mod get github.com/cstate/[email protected]

Incidents not appearing on the homepage:

# Check front matter date format (must be RFC3339/ISO 8601)
# Correct: date: 2024-01-15T14:30:00Z
# Wrong: date: 01/15/2024

# Verify the section field is set correctly
grep "^section:" content/issues/*.md
# Must be: section: issue

# Build with verbose output
hugo --verbose 2>&1 | grep -i warn

GitHub Pages shows "404 Not Found":

# Verify baseURL in config.yaml matches your GitHub Pages URL
# For username.github.io/repo-name: baseURL: "https://username.github.io/repo-name/"
# For custom domain: baseURL: "https://status.yourdomain.com/"

CSS/JS not loading after deploy:

# Ensure baseURL is set correctly with trailing slash
# Check if assets are in public/ after build
hugo --minify && ls public/css public/js

Conclusion

cState delivers a zero-runtime status page that deploys in minutes to GitHub Pages or Netlify with no infrastructure to maintain. Incidents are plain Markdown files that can be created and updated via Git, making it ideal for teams already using a Git-based workflow. The static approach means your status page remains accessible even when your infrastructure is down.