openstatus Docker & Self-Hosted Deployment

GitHub

Status page with uptime monitoring & API monitoring as code ๐Ÿซ–

RAW Compose
1. Pull Image (DOCKERHUB) docker pull openstatus/db-migrate
2. Docker Run (1-Click Launch) docker run -d --name openstatus -p 8080:8080 --restart always openstatus/db-migrate:latest
3. Podman Run podman run -d --name openstatus -p 8080:8080 --restart always openstatus/db-migrate:latest
4. Skopeo Inspect (Zero-Pull Manifest) skopeo inspect docker://docker.io/openstatus/db-migrate:latest
5. ORAS Pull (OCI Artifact) oras pull openstatus/db-migrate:latest
6. Compose Deployment docker compose up -d
docker-compose.yaml
Download .yml
networks:
    openstatus:
        driver: bridge
        name: openstatus

volumes:
    libsql-data:
        name: openstatus-libsql-data
    workflows-data:
        name: openstatus-workflows-data
    tinybird-clickhouse-data:
        name: openstatus-tinybird-clickhouse-data
    tinybird-redis-data:
        name: openstatus-tinybird-redis-data

services:
    # External services
    libsql:
        container_name: openstatus-libsql
        image: ghcr.io/tursodatabase/libsql-server:latest
        networks:
            - openstatus
        ports:
            - "8080:8080"
            - "5001:5001"
        volumes:
            - libsql-data:/var/lib/sqld
        environment:
            - SQLD_NODE=primary
            # Increase limits to handle multiple services without connection pooling
            - SQLD_MAX_CONCURRENT_CONNECTIONS=512
            - SQLD_MAX_CONCURRENT_REQUESTS=1024
        healthcheck:
            test:
                [
                    "CMD-SHELL",
                    'perl -e ''use IO::Socket::INET; exit(IO::Socket::INET->new(PeerAddr=>"127.0.0.1:8080",Timeout=>1) ? 0 : 1);''',
                ]
            interval: 10s
            timeout: 5s
            retries: 5
            start_period: 10s
        restart: unless-stopped
        memswap_limit: 512M
        deploy:
            resources:
                limits:
                    memory: 512M
                reservations:
                    memory: 256M

    tinybird-local:
        container_name: openstatus-tinybird
        image: tinybirdco/tinybird-local:latest
        networks:
            - openstatus
        ports:
            - "7181:7181"
        environment:
            - COMPATIBILITY_MODE=1
        volumes:
            - tinybird-clickhouse-data:/var/lib/clickhouse
            - tinybird-redis-data:/redis-data
        healthcheck:
            test: ["CMD", "curl", "-f", "-sS", "-o", "/dev/null", "http://localhost:7181/tokens"]
            interval: 15s
            timeout: 5s
            retries: 5
            start_period: 20s
        restart: unless-stopped

    # Internal Services
    # Idempotent: drizzle skips already-applied migrations on every up
    db-migrate:
        container_name: openstatus-db-migrate
        build:
            context: .
            dockerfile: packages/db/Dockerfile
        image: openstatus/db-migrate:latest
        # rebuild on every up so a stale image never skips new migrations
        pull_policy: build
        networks:
            - openstatus
        env_file:
            - .env.docker
        environment:
            - DATABASE_URL=http://libsql:8080
        depends_on:
            libsql:
                condition: service_healthy
        # retries absorb transient DB races; still settles to failure for the gates
        restart: on-failure:3

    workflows:
        container_name: openstatus-workflows
        build:
            context: .
            dockerfile: apps/workflows/Dockerfile
        image: openstatus/workflows:latest
        networks:
            - openstatus
        ports:
            - "3000:3000"
        volumes:
            - workflows-data:/app/data
        env_file:
            - .env.docker
        environment:
            - DATABASE_URL=http://libsql:8080
            - PORT=3000
        depends_on:
            db-migrate:
                condition: service_completed_successfully
            libsql:
                condition: service_healthy
        healthcheck:
            test: ["CMD", "curl", "-f", "http://localhost:3000/ping"]
            interval: 15s
            timeout: 10s
            retries: 3
            start_period: 30s
        restart: unless-stopped
        memswap_limit: 512M
        deploy:
            resources:
                limits:
                    memory: 512M
                reservations:
                    memory: 256M

    server:
        container_name: openstatus-server
        build:
            context: .
            dockerfile: apps/server/Dockerfile
        image: openstatus/server:latest
        networks:
            - openstatus
        ports:
            - "3001:3000"
        env_file:
            - .env.docker
        environment:
            - DATABASE_URL=http://libsql:8080
            - PORT=3000
        depends_on:
            db-migrate:
                condition: service_completed_successfully
            workflows:
                condition: service_healthy
            libsql:
                condition: service_healthy
        healthcheck:
            test: ["CMD", "curl", "-f", "http://localhost:3000/ping"]
            interval: 15s
            timeout: 10s
            retries: 3
            start_period: 30s
        restart: unless-stopped
        memswap_limit: 512M
        deploy:
            resources:
                limits:
                    memory: 512M
                reservations:
                    memory: 256M

    private-location:
        container_name: openstatus-private-location
        build:
            context: apps/private-location
            dockerfile: Dockerfile
        image: openstatus/private-location:latest
        networks:
            - openstatus
        ports:
            - "8081:8080"
        env_file:
            - .env.docker
        environment:
            - DB_URL=http://libsql:8080
            - TINYBIRD_URL=http://tinybird-local:7181
            - WORKFLOWS_URL=http://workflows:3000
            - GIN_MODE=release
            - PORT=8080
        depends_on:
            server:
                condition: service_healthy
        healthcheck:
            test:
                [
                    "CMD",
                    "wget",
                    "--spider",
                    "-q",
                    "http://localhost:8080/health",
                ]
            interval: 15s
            timeout: 10s
            retries: 3
            start_period: 30s
        restart: unless-stopped
        memswap_limit: 256M
        deploy:
            resources:
                limits:
                    memory: 256M
                reservations:
                    memory: 128M

    dashboard:
        container_name: openstatus-dashboard
        build:
            context: .
            dockerfile: apps/dashboard/Dockerfile
        image: openstatus/dashboard:latest
        networks:
            - openstatus
        ports:
            - "3002:3000"
        env_file:
            - .env.docker
        environment:
            - DATABASE_URL=http://libsql:8080
            - PORT=3000
            - HOSTNAME=0.0.0.0
            - AUTH_TRUST_HOST=true
        depends_on:
            db-migrate:
                condition: service_completed_successfully
            workflows:
                condition: service_healthy
            libsql:
                condition: service_healthy
            server:
                condition: service_healthy
        healthcheck:
            test: ["CMD-SHELL", "curl -f http://localhost:3000/ || exit 1"]
            interval: 15s
            timeout: 10s
            retries: 3
            start_period: 45s
        restart: unless-stopped
        memswap_limit: 512M
        deploy:
            resources:
                limits:
                    memory: 512M
                reservations:
                    memory: 256M

    status-page:
        container_name: openstatus-status-page
        build:
            context: .
            dockerfile: apps/status-page/Dockerfile
        image: openstatus/status-page:latest
        networks:
            - openstatus
        ports:
            - "3003:3000"
        env_file:
            - .env.docker
        environment:
            - DATABASE_URL=http://libsql:8080
            - PORT=3000
            - HOSTNAME=0.0.0.0
            - AUTH_TRUST_HOST=true
            - OPENSTATUS_API_URL=${OPENSTATUS_API_URL:-http://server:3000}
        depends_on:
            db-migrate:
                condition: service_completed_successfully
            workflows:
                condition: service_healthy
            libsql:
                condition: service_healthy
            server:
                condition: service_healthy
        healthcheck:
            test: ["CMD-SHELL", "curl -f http://localhost:3000/ || exit 1"]
            interval: 15s
            timeout: 10s
            retries: 3
            start_period: 45s
        restart: unless-stopped
        memswap_limit: 512M
        deploy:
            resources:
                limits:
                    memory: 512M
                reservations:
                    memory: 256M