Stop Paying $299/Month for a Status Page: Atlassian Statuspage vs Instatus vs cstate

Every service goes down. How you communicate that downtime is what separates a trusted product from a support ticket avalanche. A status page is not optional infrastructure — it’s table stakes. And yet most teams either don’t have one, run some hacked-together Google Doc, or are quietly bleeding $299/month to Atlassian for the privilege of showing a green circle.

Let’s fix that.

This article breaks down the three most common paths teams take: Atlassian Statuspage (the entrenched enterprise choice), Instatus (the modern SaaS challenger), and cstate (the self-hosted, zero-recurring-cost option that most people sleep on). By the end you’ll have a clear decision matrix — and if you go the self-hosted route, a full working Docker deployment you can ship today.


The Three Contenders at a Glance

Before going deep, here’s the honest one-liner for each:

  • Atlassian Statuspage — mature, deeply integrated with the Atlassian ecosystem, priced like it knows you’re already locked in.
  • Instatus — Statuspage’s spiritual successor built for the modern web, genuinely good UX, aggressive free tier.
  • cstate — a Hugo-based static site you own completely; no subscriptions, no vendor lock-in, minimal attack surface.

Official repos and links you’ll need:


Atlassian Statuspage

Statuspage (acquired by Atlassian in 2016) is the category inventor. Practically every company you use daily runs on it — GitHub, Cloudflare, Stripe. That ubiquity is both its strength and its trap.

What it does well:

Statuspage has the richest feature set. Subscriber notifications via email, SMS, Slack, webhooks. Metric charts pulled from your monitoring stack. Custom domain with HTTPS out of the box. Full API for automated incident updates. Deep Jira and Opsgenie integrations that trigger incident creation automatically when an alert fires.

If you’re an Atlassian shop running Jira, Confluence, and Opsgenie, this integration story is genuinely compelling — incident fires, Opsgenie triggers, Statuspage auto-creates the incident, engineers get pages. That’s a tight loop.

The pricing problem:

The free tier allows one status page with 100 subscribers. Hit 101 subscribers and you’re on the $29/month Starter plan. Need more components, team seats, or metrics? You’re looking at $99/month (Startup), $199/month (Business), or $299/month (Enterprise). For a startup burning runway, this is absurd — you’re paying Atlassian almost $3,600/year to host a mostly-static webpage.

Gotcha #1: Atlassian raised Statuspage prices twice since 2022. If you’re on a legacy plan grandfathered at a lower rate, read your next billing email carefully. Several teams found their bill quietly doubled after a plan migration.

Gotcha #2: The Statuspage embed widget (the floating badge on your app) is only available on Startup and above. So if you want the little "All Systems Operational" badge in your dashboard — the most user-facing feature — the free tier is useless.

Verdict on Statuspage: Worth it if you’re deep in the Atlassian ecosystem and the automation chain pays for itself in reduced MTTR. For everyone else, you’re paying a brand premium.


Instatus

Instatus launched around 2020 as a direct Statuspage competitor with better design, faster performance (static pages via CDN), and pricing that doesn’t feel adversarial.

What it does well:

The UI is excellent — probably the best-looking status page builder available. Setup is genuinely 10 minutes: pick a subdomain, add components, connect your monitoring tool, done. They support Slack, Discord, MS Teams, email, SMS, and webhooks for notifications. The page itself loads fast because it’s statically generated and served from a CDN, not a slow server-rendered SaaS app.

Instatus has native integrations with PagerDuty, Opsgenie, Datadog, Better Uptime, UptimeRobot, and a dozen others. You configure the integration once and incidents get created and resolved automatically based on your monitor state. This is the killer feature for small teams — zero manual incident management.

The free tier is legitimately useful: one status page, unlimited team members, unlimited components, unlimited incidents. The subscriber limit (100 email subscribers) is the main gate.

Pricing reality:

$29/month for the Starter plan unlocks unlimited subscribers and a custom domain. That’s it — most teams stop there. Compare that to Statuspage where $29/month is the bare minimum and you’re still missing key features.

Gotcha #1: Instatus is a smaller company. Statuspage has Atlassian’s infrastructure and SLA behind it. If Instatus has an incident, your status page is down during the incident you’re trying to communicate. The irony is real and has happened.

Gotcha #2: Data portability is limited. If you want to leave Instatus, you’re exporting incidents manually. There’s no pg_dump you can take with you.

Gotcha #3: Custom domain setup requires pointing a CNAME, which means your status page DNS depends on Instatus’s infrastructure. If they have a DNS issue, status.yourcompany.com is unreachable.

Verdict on Instatus: The best SaaS option for most teams in 2026. Clean UX, honest pricing, solid integrations. Use it unless you have a specific reason not to hand a third party your status page availability.


cstate — The Self-Hosted Path

cstate is a Hugo-based static site generator designed specifically for status pages. Your entire status page is a Git repository — incidents are Markdown files, configuration is YAML, and deployment is just pushing HTML to wherever you want.

This model has profound operational advantages: no database, no runtime, no session management, no auth surface, nothing to patch. The page that goes live is pre-rendered HTML that a CDN serves directly. It can stay up even when every other piece of your infrastructure is on fire.

Architecture options:

  1. Netlify/Vercel — push to main, CI builds Hugo, deploys to CDN. Free tier covers most usage. Downside: your status page availability still depends on Netlify/Vercel.
  2. GitHub Pages — same model, fully free, slower build pipeline.
  3. Self-hosted with Docker + Nginx — you own everything, including uptime. This is what the rest of this guide covers.

Setting Up cstate with Docker

The recommended production pattern is: Hugo builds the static site in a CI step, and Nginx serves the output. For local development and teams without CI, the simplest path is a two-container setup that rebuilds on change.

First, scaffold your cstate repo:

# Install Hugo (extended version required for cstate)
# On Debian/Ubuntu:
wget https://github.com/gohugoio/hugo/releases/download/v0.147.0/hugo_extended_0.147.0_linux-amd64.deb
sudo dpkg -i hugo_extended_0.147.0_linux-amd64.deb

# Initialize a new cstate site
hugo new site mystatus
cd mystatus

# Add cstate as a Hugo module (modern approach)
hugo mod init github.com/yourorg/mystatus

Your config.yaml is the heart of the setup. Here’s a production-ready example:

# config.yaml
baseURL: "https://status.yourcompany.com/"
languageCode: "en-us"
title: "YourCompany Status"
theme: cstate

# cstate-specific params
params:
  # The logo shown in the header (place file in static/)
  logo: "logo.png"

  # Incident categories — map to your actual infrastructure
  # These appear as component names on the page
  systems:
    - name: API
      description: REST and GraphQL endpoints
    - name: Web App
      description: Dashboard and frontend
    - name: Database
      description: Primary PostgreSQL cluster
    - name: CDN
      description: Asset delivery and edge caching
    - name: Webhooks
      description: Outbound event delivery

  # How many days of history to show
  alwaysShowAllIncidents: false
  incidentHistoryDays: 7

  # Appearance
  dateFormat: "January 2, 2006 at 15:04 UTC"
  dateFormatShort: "Jan 2"

  # Enable RSS feed for subscribers
  enableRSS: true

  # Color theme: "green" | "yellow" | "red" | "blue"
  defaultColor: "green"

  # Show "Powered by cstate" footer — set false if you want clean branding
  footerText: ""

markup:
  goldmark:
    renderer:
      unsafe: true  # Required for cstate's incident shortcodes

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

Now the Docker setup. The pattern here is a build container that runs Hugo and an Nginx container that serves the output. A shared volume connects them:

# docker-compose.yml
version: "3.9"

services:
  # Hugo builder — rebuilds the site when source files change
  hugo-builder:
    image: klakegg/hugo:ext-alpine
    working_dir: /src
    volumes:
      - ./:/src              # Your cstate repo
      - hugo-public:/public  # Shared output volume
    command: >
      sh -c "hugo mod download &&
             hugo --destination /public --minify --gc"
    # Remove this service after first build in production;
    # replace with your CI/CD pipeline (GitHub Actions, etc.)

  # Nginx — serves the pre-built static files
  nginx:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - hugo-public:/usr/share/nginx/html:ro
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - hugo-builder
    restart: unless-stopped

volumes:
  hugo-public:

The Nginx config needs one non-obvious setting — cstate generates clean URLs (no .html extensions), so you need try_files to handle that:

# nginx.conf
server {
    listen 80;
    server_name _;

    root /usr/share/nginx/html;
    index index.html;

    # Handle clean URLs generated by Hugo
    location / {
        try_files $uri $uri/ $uri.html =404;
    }

    # Cache static assets aggressively
    location ~* \.(css|js|png|jpg|ico|woff2)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    # Security headers
    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-Content-Type-Options "nosniff";
    add_header Referrer-Policy "strict-origin-when-cross-origin";
}

Creating Incidents

This is where cstate’s model shines. An incident is just a Markdown file:

# Create a new incident manually
hugo new incidents/2026-05-24-api-degraded.md
---
# content/incidents/2026-05-24-api-degraded.md
title: "API response times elevated"
date: 2026-05-24T14:32:00Z
# resolved | investigating | identified | monitoring
status: "investigating"
# affects: list of systems from config.yaml
affected:
  - API
  - Webhooks
severity: "degraded"  # disrupted | degraded | notice
---

We are investigating elevated response times on the API. P95 latency
is currently 2.3s against a normal baseline of 180ms. The database
cluster is healthy. Engineers are investigating the application layer.

<!-- Update blocks — newest first -->

**14:45 UTC** — Root cause identified: a deployed background job is
holding a connection pool hostage. Rolling back the deployment now.

**14:32 UTC** — Investigating.

Commit that file, push to your repo, and your CI pipeline rebuilds the static site. The incident goes live in under a minute with zero database writes, zero API calls, zero runtime risk.

To resolve: change status: "resolved" and add a resolvedWhen timestamp. Commit and push.

Production Deployment with Automatic Rebuilds

In real production, you don’t want the Hugo builder container running 24/7 — that’s wasteful. The correct pattern is a GitHub Actions (or GitLab CI) pipeline that builds on push:

# .github/workflows/deploy.yml
name: Build and Deploy Status Page

on:
  push:
    branches: [main]

jobs:
  build-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
          fetch-depth: 0

      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v3
        with:
          hugo-version: "0.147.0"
          extended: true

      - name: Build
        run: hugo --minify --gc

      - name: Deploy to server
        uses: appleboy/[email protected]
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SERVER_KEY }}
          source: "public/"
          target: "/var/www/status/"
          strip_components: 1

On the server side, Nginx simply serves /var/www/status/ — no Docker needed, no runtime, just files on disk.


Head-to-Head Comparison

Feature Atlassian Statuspage Instatus cstate (self-hosted)
Monthly cost $0–$299 $0–$29 (most teams) $0 (your infra cost)
Custom domain Startup+ ($99/mo) Starter ($29/mo) Free
Subscriber notifications Yes (paid) Yes (paid) Via RSS / manual
Auto-incident from monitors Yes Yes Via CI scripts
Data ownership No No Full
Uptime depends on vendor Yes Yes No
Setup time 15 min 10 min 30–60 min
Incident history Unlimited Unlimited Git history
API Full REST API Full REST API Git + CI
Jira/Opsgenie integration Native Via webhook Manual

Gotchas Specific to cstate

Gotcha #1 — Hugo module caching in CI. Hugo module downloads hit the internet on every cold build. Cache $HUGO_CACHEDIR in your CI pipeline or your builds will be slow and fragile when the module registry has hiccups.

# In GitHub Actions
- uses: actions/cache@v4
  with:
    path: /tmp/hugo_cache
    key: ${{ runner.os }}-hugo-${{ hashFiles('**/go.sum') }}

Gotcha #2 — The "status page down" problem. If your server is down, your status page is down. This is the single hardest problem with self-hosting. The mitigations, roughly in order of effort: host on Netlify/Vercel (free tier, separate infrastructure), use Cloudflare Pages, or push the static output to an S3-compatible bucket served from a CDN. Don’t host the status page on the same server as your product.

Gotcha #3 — No built-in subscriber email. cstate doesn’t send email notifications out of the box. You get an RSS feed. Real subscriber management requires a separate tool — Mailchimp, Listmonk (self-hosted), or a webhook to your email provider. For most teams, RSS + a Slack integration covers 90% of the use case.

Gotcha #4 — Clock discipline on incidents. Incident timestamps are whatever you type in the Markdown frontmatter. On a team with multiple engineers, you’ll get inconsistent formats and timezones. Standardize on ISO 8601 UTC in your contribution docs before the first incident.


Production-Ready Recommendations

For a startup under 10 people with no Atlassian stack: Use Instatus free tier. When you hit 100 subscribers, pay the $29. This isn’t a decision worth 3 hours of engineering time.

For a startup that’s infrastructure-conscious or has GDPR/data residency requirements: cstate on Cloudflare Pages. Zero cost, global CDN, your data stays in your Git repo, deploys in 45 seconds on push. This is the sweet spot.

For an enterprise using Jira + Opsgenie: Atlassian Statuspage, but negotiate the contract. The auto-incident-creation-from-Opsgenie feature is the only thing that justifies the price. If you’re not using that loop, you’re paying for nothing a $29 Instatus plan doesn’t give you.

For any self-hosted path: Separate the status page infrastructure from your product infrastructure. This is non-negotiable. Your status page must survive your product going down. That’s its entire purpose.

One more thing: automate incident creation. Whether you use Statuspage’s API, Instatus’s integrations, or a GitHub Actions workflow that commits a new Markdown file — manual incident creation during an outage is when things go wrong. Engineers are stressed, pages are firing, nobody remembers the status page until a customer tweets about it. Wire it up to your alerting tool before you need it.


The Verdict

cstate wins on pure cost and ownership. If your team can handle a one-time 30-60 minute setup and the Git-based incident workflow fits how you work, self-hosted cstate is difficult to beat. No recurring cost, no vendor risk, trivially auditable, version-controlled incident history.

Instatus wins on convenience. If you want to be done in 10 minutes and never think about it again, Instatus is the honest recommendation. The free tier is legitimate, the paid tier is cheap, and the UX is excellent.

Atlassian Statuspage wins in one specific scenario: you’re already all-in on the Atlassian suite and you want automated incident management wired directly into Opsgenie. That’s a real use case. But if you’re not in that scenario, you’re subsidizing Atlassian’s acquisition.

The status page is the part of your infrastructure customers see precisely when everything is broken. Make sure it’s not the thing that breaks too.

Leave a comment

👁 Views: 2,290 · Unique visitors: 1,647