Cachet Status Page Installation

Cachet is an open-source status page system that lets you communicate service health, incidents, and scheduled maintenance to your users. This guide covers installing Cachet on Linux using Docker, managing components, reporting incidents, configuring subscriber notifications, and using the Cachet API.

Prerequisites

  • Ubuntu 20.04/22.04 or CentOS 8/Rocky Linux 8+
  • Docker and Docker Compose (for Docker install)
  • PHP 8.0+, Composer, and MySQL/PostgreSQL (for bare metal install)
  • Nginx or Apache web server
  • Domain name and SSL certificate (recommended)

Install Cachet with Docker

Docker is the fastest way to get Cachet running:

# Create a project directory
mkdir -p /opt/cachet && cd /opt/cachet

# Create the docker-compose.yml
cat > docker-compose.yml << 'EOF'
version: '3.7'
services:
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword
      MYSQL_DATABASE: cachet
      MYSQL_USER: cachet
      MYSQL_PASSWORD: cachetpassword
    volumes:
      - db_data:/var/lib/mysql
    restart: unless-stopped

  cachet:
    image: cachethq/docker:latest
    ports:
      - "8000:8000"
    environment:
      - DB_DRIVER=mysql
      - DB_HOST=db
      - DB_DATABASE=cachet
      - DB_USERNAME=cachet
      - DB_PASSWORD=cachetpassword
      - APP_KEY=base64:YourSecretKeyHere32CharsMinimum==
      - APP_ENV=production
      - APP_DEBUG=false
      - CACHE_DRIVER=file
      - SESSION_DRIVER=file
      - QUEUE_DRIVER=sync
      - MAIL_DRIVER=smtp
      - MAIL_HOST=smtp.example.com
      - MAIL_PORT=587
      - [email protected]
      - MAIL_PASSWORD=mailpassword
    depends_on:
      - db
    restart: unless-stopped

volumes:
  db_data:
EOF

# Generate a random APP_KEY
openssl rand -base64 32

# Start the services
docker-compose up -d

# Run the installation wizard
docker-compose exec cachet php artisan cachet:install

Install Cachet on Bare Metal

For a native installation on Ubuntu:

# Install dependencies
sudo apt update
sudo apt install -y php8.1 php8.1-fpm php8.1-mysql php8.1-mbstring \
  php8.1-xml php8.1-curl php8.1-zip php8.1-bcmath \
  mysql-server nginx git composer unzip

# Secure MySQL and create the database
sudo mysql_secure_installation
sudo mysql -u root -p << 'SQL'
CREATE DATABASE cachet CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'cachet'@'localhost' IDENTIFIED BY 'strongpassword';
GRANT ALL PRIVILEGES ON cachet.* TO 'cachet'@'localhost';
FLUSH PRIVILEGES;
SQL

# Clone Cachet
cd /var/www
sudo git clone https://github.com/cachethq/cachet.git
sudo chown -R www-data:www-data /var/www/cachet
cd /var/www/cachet

# Install PHP dependencies
sudo -u www-data composer install --no-dev --prefer-dist

# Configure environment
sudo cp .env.example .env
sudo nano .env
# Set: DB_HOST, DB_DATABASE, DB_USERNAME, DB_PASSWORD, APP_KEY, MAIL_* settings

# Generate app key and run migrations
sudo -u www-data php artisan key:generate
sudo -u www-data php artisan migrate --force
sudo -u www-data php artisan db:seed --force
sudo -u www-data php artisan cachet:install

Configure Nginx:

cat > /etc/nginx/sites-available/cachet << 'EOF'
server {
    listen 80;
    server_name status.example.com;
    root /var/www/cachet/public;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php8.1-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }
}
EOF

sudo ln -s /etc/nginx/sites-available/cachet /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Component Management

Components represent your services (API, website, database, etc.):

  1. Log in to the Cachet dashboard at http://your-server:8000
  2. Go to Dashboard > Components
  3. Click Add Component

Via the API:

# Set your API URL and token
API_URL="http://status.example.com/api/v1"
API_TOKEN="your-api-token"  # Found in Dashboard > Team

# Create a component
curl -X POST "${API_URL}/components" \
  -H "X-Cachet-Token: ${API_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "API Server",
    "description": "Main REST API endpoint",
    "status": 1,
    "order": 1,
    "group_id": 0,
    "enabled": true
  }'
# Status: 1=Operational, 2=Performance Issues, 3=Partial Outage, 4=Major Outage

# Create a component group
curl -X POST "${API_URL}/component_groups" \
  -H "X-Cachet-Token: ${API_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"name": "Core Services", "order": 1, "collapsed": 0}'

# Update component status (e.g., to degraded performance)
curl -X PUT "${API_URL}/components/1" \
  -H "X-Cachet-Token: ${API_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"status": 2}'

Incident Reporting

# Create an incident via API
curl -X POST "${API_URL}/incidents" \
  -H "X-Cachet-Token: ${API_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "API Response Times Elevated",
    "message": "We are investigating elevated response times on the API. Our team is looking into the root cause.",
    "status": 1,
    "visible": 1,
    "component_id": 1,
    "component_status": 2
  }'
# Incident status: 1=Investigating, 2=Identified, 3=Watching, 4=Fixed

# Add an update to an existing incident (ID=1)
curl -X POST "${API_URL}/incidents/1/updates" \
  -H "X-Cachet-Token: ${API_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "status": 2,
    "message": "Root cause identified: database connection pool exhaustion. Fix in progress."
  }'

# Resolve the incident
curl -X PUT "${API_URL}/incidents/1" \
  -H "X-Cachet-Token: ${API_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"status": 4, "component_status": 1}'

Subscriber Notifications

Cachet supports email and webhook subscriptions:

# Configure mail in .env
MAIL_DRIVER=smtp
MAIL_HOST=smtp.sendgrid.net
MAIL_PORT=587
MAIL_USERNAME=apikey
MAIL_PASSWORD=your-sendgrid-api-key
[email protected]
MAIL_FROM_NAME="Status Page"

# Test mail configuration
docker-compose exec cachet php artisan cachet:test-mail

# Subscribers can sign up at the public status page
# Or add via API
curl -X POST "${API_URL}/subscribers" \
  -H "X-Cachet-Token: ${API_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"email": "[email protected]", "verify": 1}'

Metrics Configuration

Track custom metrics on your status page:

# Create a metric (e.g., API response time)
curl -X POST "${API_URL}/metrics" \
  -H "X-Cachet-Token: ${API_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "API Response Time",
    "suffix": "ms",
    "description": "Average API response time",
    "default_value": 0,
    "calc_type": 1
  }'
# calc_type: 1=Average, 2=Sum

# Add a metric data point (metric ID=1)
curl -X POST "${API_URL}/metrics/1/points" \
  -H "X-Cachet-Token: ${API_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"value": 245, "timestamp": '$(date +%s)'}'

# Automate metric collection with a cron job
# Add to crontab every minute:
# * * * * * /usr/local/bin/collect-metrics.sh
cat > /usr/local/bin/collect-metrics.sh << 'SCRIPT'
#!/bin/bash
RESPONSE_TIME=$(curl -o /dev/null -s -w "%{time_total}" https://api.example.com/health)
MS=$(echo "$RESPONSE_TIME * 1000" | bc | cut -d. -f1)
curl -s -X POST "http://localhost:8000/api/v1/metrics/1/points" \
  -H "X-Cachet-Token: your-token" \
  -H "Content-Type: application/json" \
  -d "{\"value\": $MS, \"timestamp\": $(date +%s)}"
SCRIPT
chmod +x /usr/local/bin/collect-metrics.sh

API Usage

# Get all components
curl "${API_URL}/components" | python3 -m json.tool

# Get current incidents
curl "${API_URL}/incidents?status=1" | python3 -m json.tool

# Get ping (health check)
curl "${API_URL}/ping"

# Get version info
curl "${API_URL}/version"

# Automate status updates from a monitoring script
check_service() {
  local name="$1"
  local url="$2"
  local component_id="$3"
  local status=$(curl -s -o /dev/null -w "%{http_code}" "$url")
  
  if [ "$status" = "200" ]; then
    component_status=1  # Operational
  else
    component_status=4  # Major Outage
  fi
  
  curl -s -X PUT "${API_URL}/components/${component_id}" \
    -H "X-Cachet-Token: your-token" \
    -H "Content-Type: application/json" \
    -d "{\"status\": $component_status}"
}

Customization

Customize Cachet's appearance in Dashboard > Settings > Appearance:

# Override CSS (place in public/css/custom.css or via Settings UI)
# Change stylesheet via environment variable
APP_URL=https://status.example.com

# Set a custom stylesheet URL in dashboard settings
# Dashboard > Settings > Stylesheet > paste custom CSS

# Custom domain via nginx reverse proxy already covered above
# Add SSL with Certbot
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d status.example.com

Troubleshooting

Blank page or 500 error:

# Check application logs
docker-compose logs cachet --tail 50
tail -n 50 /var/www/cachet/storage/logs/laravel.log

# Fix storage permissions
sudo chown -R www-data:www-data /var/www/cachet/storage
sudo chmod -R 775 /var/www/cachet/storage

Emails not sending:

# Test mail from CLI
php artisan cachet:test-mail

# Check queue (if using async queue driver)
php artisan queue:work --once

Database migration errors:

# Re-run migrations
php artisan migrate --force

# Check database connection
php artisan tinker
# >>> DB::connection()->getPdo();

Conclusion

Cachet provides a polished, self-hosted status page with full API control over components, incidents, and metrics. Deploy it with Docker for the fastest setup, integrate metric collection scripts via cron, and use the REST API to automate status updates from your monitoring stack. With subscriber notifications and a clean public interface, Cachet keeps your users informed during outages.