GridPreviewPrototypeDocumentation
Skip to article
Browse documentation

Documentation Developers

Docker deployment

Pull the private x86-64 image and deploy the app, worker and database on your server.

On this page

What gets deployed

The private repository is bcsutar/gridpreview. GitHub Actions builds an x86-64 (linux/amd64) image and publishes it to the private ghcr.io/bcsutar/gridpreview package. Each successful publication produces a latest tag and an immutable commit-SHA tag. The workflow verifies that the registry package is private.

compose.production.yml runs four services:

ServiceResponsibility
postgresPostgreSQL 17 with a persistent named volume; no published database port
initializeOne-shot schema migrations and safe default configuration seeding
webProduction Next.js server, bound to the host’s loopback interface
workerDurable research execution using the same application image

The application containers run as a non-root user. Web and worker start only after initialization succeeds. Provider credentials and session secrets are supplied at runtime, never during the image build.

Prepare the x86 server

Install Docker Engine and the Docker Compose v2 plugin. Use an authorized SSH key or other private-repository credential to obtain the deployment files:

git clone [email protected]:bcsutar/gridpreview.git
cd gridpreview
cp .env.production.example .env
chmod 600 .env

Edit .env. Generate four independent values for POSTGRES_PASSWORD, AUTH_COOKIE_SECRET, RESEARCH_ACCESS_TOKEN and LOCAL_ADMIN_TOKEN:

openssl rand -hex 32

Use hexadecimal for the database password because it is embedded in the PostgreSQL connection URL. Set the provider key required by your published model configuration. The seeded default uses OpenCode Go Muse Spark Contributor; verify its workload and data-sharing permissions or publish a different supported provider/model before using it.

Keep grid-source access disabled until reuse permission is established. Do not copy a development database or local credentials unless you explicitly intend to migrate them.

Authenticate to the private registry

Use a GitHub credential with read:packages access to this private package. A classic personal access token with that scope is supported; repository access alone is not necessarily registry access. Store the credential through Docker’s credential handling, not in Compose or a committed file.

docker login ghcr.io --username bcsutar

Enter the package-read token at the password prompt. Select an immutable published image tag in .env for predictable deployments:

GRIDPREVIEW_IMAGE=ghcr.io/bcsutar/gridpreview:<published-commit-sha>
APP_PORT=3000

The placeholder is not a real image tag. Copy the commit tag from a successful Private container workflow run. latest is available for convenience but changes when a new image is published.

Start and inspect

docker compose -f compose.production.yml config --quiet
docker compose -f compose.production.yml pull
docker compose -f compose.production.yml up -d --wait
docker compose -f compose.production.yml ps -a
docker compose -f compose.production.yml logs --tail=100 initialize web worker

initialize should exit successfully. PostgreSQL and web have health checks; a running worker container does not by itself prove that every external provider is configured or available. Container startup does not create a research run or validate a model-backed report.

Do not share unredacted environment/configuration dumps. docker compose config without --quiet can print interpolated credentials.

Put HTTPS in front

The web port binds to 127.0.0.1:3000 by default. Put your existing HTTPS reverse proxy in front; do not expose PostgreSQL. An Nginx upstream location should preserve the public host and avoid buffering research events:

location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_buffering off;
    proxy_read_timeout 360s;
}

This location snippet assumes an existing TLS virtual host and certificate. Production owner cookies are Secure; use HTTPS for browser research sessions. Do not remove authentication to work around a proxy or cookie issue.

Establish access

Public product and documentation pages do not authorize research. On the HTTPS site, use POST /api/session with your RESEARCH_ACCESS_TOKEN to issue a signed owner cookie; keep that cookie for subsequent requests. See API reference for the request format. Admin API access separately requires LOCAL_ADMIN_TOKEN as a bearer credential.

Access is a private capability-based prototype, not a public signup system. Do not publish access tokens, add them to URLs or assume that two independently issued sessions share an owner.

Back up before updates

Keep database backups outside the application repository and copy them off the server. Back up .env securely as well, especially the cookie-signing secret.

mkdir -p backups
chmod 700 backups
docker compose -f compose.production.yml exec -T postgres \
  pg_dump -U grid -d gridpreview -Fc > backups/gridpreview.dump
chmod 600 backups/gridpreview.dump

A backup is not verified until restored. To test restoration, use a separate fresh deployment with an empty database, start only its PostgreSQL service, and restore before running initialization:

docker compose -f compose.production.yml up -d --wait postgres
docker compose -f compose.production.yml exec -T postgres \
  pg_restore -U grid -d gridpreview --no-owner < backups/gridpreview.dump

Do not run this restore against an existing live database. Keep a matching application image tag with the backup.

Pull an update

Obtain the updated Compose files when needed and change GRIDPREVIEW_IMAGE to the new immutable tag. During a maintenance window:

docker compose -f compose.production.yml pull
docker compose -f compose.production.yml stop web worker
docker compose -f compose.production.yml run --rm initialize
docker compose -f compose.production.yml up -d --wait

The worker handles termination by finishing its current job and then exiting without claiming another. Compose allows 330 seconds for this, longer than the default 300-second run budget. Increasing the run budget requires a correspondingly longer shutdown grace period.

Never use docker compose down -v for an update: it removes the database volume. Application rollback does not automatically reverse database migrations; assess compatibility or restore a matching backup before rolling back a migrated deployment.

GridPreview is a prototype. Documentation describes the implementation, not a guarantee of source availability or a professional assessment.