Skip to content

Deploy an instance

The monitor is one static binary in a small container image, configured with environment variables. One instance follows one network, mainnet or testnet, and keeps all its state in one SQLite file.

Requirements

  • A container runtime, such as Docker with Compose.
  • A database volume that can grow with the logs of the busiest hub in the network.
  • A reverse proxy that terminates TLS, such as Caddy.
  • A subdomain for the instance alone. The monitor serves its pages, assets and hub routes from the root of its host, so it cannot run under a sub-path.
  • Outbound HTTPS. See Egress.

Quick start

  1. Create compose.yaml:

    compose.yaml
    services:
      iscc-monitor:
        image: ghcr.io/iscc/iscc-monitor:v0.1.0
        environment:
          ISCC_MONITOR_DB: /data/monitor.db
          ISCC_MONITOR_REALM: https://raw.githubusercontent.com/iscc/iscc-hub/refs/heads/main/hubs/mainnet.yaml
          ISCC_MONITOR_INSTANCE: monitor.example.com
        volumes:
          - monitor-data:/data
        stop_grace_period: 60s
        # No ports: the reverse proxy reaches the monitor on port 9464 over the internal network.
    
    volumes:
      monitor-data:
        name: monitor-data
    

    For testnet, use .../hubs/testnet.yaml. Configuration lists every setting.

  2. Before the first start, give the volume to uid 65532. Then start the instance:

    docker run --rm -v monitor-data:/data alpine chown -R 65532:65532 /data
    docker compose up -d
    

    The image runs as the unprivileged uid 65532, but a new Docker volume belongs to root. Without this step, the monitor cannot create its database. name: monitor-data makes Compose mount this volume, not one prefixed with the project name. A bind-mounted host directory owned by uid 65532 also works.

  3. Check that the instance is up. The first poll finishes within seconds.

    curl https://monitor.example.com/healthz
    curl https://monitor.example.com/version
    
  4. Open the start page. It lists every hub of the network with its status.

Image and tags

The image is ghcr.io/iscc/iscc-monitor.

Tag Use
:vX.Y.Z A release, described in the changelog. Pin production instances to it
:latest The newest release. It moves, so do not pin to it
:develop The latest build of the develop branch, for continuous testnet deployments
:sha-<short> One exact build of a release or of develop. It never moves. Use it or :vX.Y.Z to roll back

A released version is never re-tagged. GET /version shows the running build. A release image shows the release and its commit, such as {"version":"v0.1.0+ac65974"}. A develop image shows the full commit.

The image is based on distroless static-debian12:nonroot. It has the CA certificates for outbound HTTPS and loads nothing from a CDN at runtime. Its license terms are in /usr/share/doc/iscc-monitor/.

Reverse proxy

The monitor serves plain HTTP on :9464 and sets no connection timeouts, so it must not face the internet directly. Do not publish the port on the host, because Docker's published ports bypass the host firewall. Let the reverse proxy reach the container over the internal network and terminate TLS.

All routes share one listener, so the proxy must keep them apart. Everything is public by design except /metrics, which is your decision; see Monitoring. No route carries a secret, because the monitor holds no signing key.

With Caddy:

Caddyfile
monitor.example.com {
    respond /metrics 403
    reverse_proxy iscc-monitor:9464
}

Egress

The monitor sends outbound HTTPS requests to:

  • Every hub in the Hub-List: its log at https://<hub>/log/... and its did:web document at https://<hub>/.well-known/did.json.
  • The Hub-List, once an hour, when ISCC_MONITOR_REALM is a URL.
  • The OpenTimestamps calendar https://alice.btc.calendar.opentimestamps.org, at startup and then every ISCC_MONITOR_OTS_INTERVAL (default one hour).

Hubs join and leave the network, so there is no fixed address list. An egress allow-list must permit HTTPS to the hub domains and the calendar.

Resources

Estimates, not benchmarks:

  • Memory: tens of megabytes. The peak is the tiles in flight during a poll.
  • CPU: close to idle between polls, with short bursts for signature checks and Merkle root rebuilds.
  • Disk: the value to watch. The database holds the full log of every hub and grows with their activity. Set a disk-usage alert on the volume and size it with headroom.

Shutdown

On SIGTERM, which docker stop sends, the monitor finishes the current poll, closes the database and exits cleanly. Set stop_grace_period long enough for this, as in the quick start. Otherwise the runtime kills the monitor mid-poll.

Next steps