Setup & operations

Production setup and upgrades

Configure and operate the single-host Docker package while preserving authored content and media.

GroCMS 0.1.0 · Reviewed 15 September 2026

Download this guide

Choose the supported deployment profile

The supported package runs on one Docker Linux host with PostgreSQL, a Next.js web service, a separate worker and persistent private media. An operations image supplies migration, setup and maintenance commands. This guide is for the person responsible for that host and its configuration. A successful local Docker rehearsal demonstrates the package, not that a domain, certificates, external mail delivery, backups and monitoring have been commissioned for a public service.

Normal production Compose binds web to 127.0.0.1:3000. The standard developer server uses localhost:3100. Use the port and origin actually configured for the target installation. Keep the existing Compose project name, database volume and media volume when upgrading. A different project name creates a different installation rather than magically finding the old website's data.

Sources: Production services and environment; Standalone and operations images; Deployment and operational policy.

Create private configuration once

powershell
node scripts/ops/init-production-env.mjs --url https://cms.example.org

Replace the example origin with the intended website origin. The generator creates .env.production.local and refuses to overwrite an existing file. Edit it privately to configure PUBLIC_URL, an immutable release tag, the bind address and port, site timezone, SMTP settings and the worker's paused state. Generated secrets are distinct for database administration, migration, runtime access and authentication. Do not place real values in these guides or pass them in command-line arguments.

The database has no published host port in this profile. The initialization role creates a schema-owning migration role and a restricted runtime role. Web and worker use runtime credentials; migrations use the owner. Runtime access cannot update or delete immutable revision history. Changing a password in an environment file does not change the password of an existing PostgreSQL role. Coordinate real credential rotation with the database and application rather than regenerating the environment.

Next.js distinguishes server configuration from NEXT_PUBLIC_ values exposed to browser bundles. Keep credentials in server-only configuration. GroCMS's Docker context excludes private environment files and runtime media, and the containers receive deployment settings at startup. The supplied nginx example is a starting point for a real TLS hostname; configure it for the actual host before directing internet traffic to the application.

Sources: Production environment generator; Production services and environment; Initial production database roles; Self-hosting Next.js.

Prepare and bootstrap a new installation first

For an empty installation, build the images, start the database and run migrations before account setup. The initial site must exist before the worker can record its health heartbeat. Starting the deployment helper before bootstrap therefore fails worker readiness on a fresh database. Existing installations should skip bootstrap and follow the controlled upgrade section below. Use the same environment, project and release tag throughout.

powershell
docker compose --env-file .env.production.local --project-name gcms --file compose.yaml build web worker
docker compose --env-file .env.production.local --project-name gcms --file compose.yaml up --detach --wait --wait-timeout 120 db
docker compose --env-file .env.production.local --project-name gcms --file compose.yaml run --rm --no-deps migrate

Prepare an ignored .env.bootstrap.local containing GCMS_BOOTSTRAP_EMAIL, GCMS_BOOTSTRAP_NAME and a unique GCMS_BOOTSTRAP_PASSWORD of at least twelve characters. These are application account credentials, not the database administrator password. The setup helper reads the private file and passes values through the child process environment. Production setup requires a supplied password and refuses to create another initial administrator once any account exists.

powershell
node scripts/ops/setup.mjs --env-file .env.production.local --credentials-file .env.bootstrap.local --project gcms

Ordinary setup publishes one Hello world! Post, one Welcome homepage, official GroCMS branding with its bundled logo, Inter and approved colours, a basic content template and settings. There are no sample images, authors, taxonomy terms or marketing layouts. Invite additional people through the administration afterward. For a deliberate fresh demonstration site, add --demo true to the initial setup helper invocation as shown below; it prepares unpublished design drafts before seeding. The demo refuses to replace an initialized minimal site or authored content. Repeating ordinary setup preserves existing content. Store the bootstrap credential securely and remove its temporary file under the host's secret-handling procedure.

powershell
node scripts/ops/setup.mjs --env-file .env.production.local --credentials-file .env.bootstrap.local --project gcms --demo true

Sources: Private production bootstrap helper; First administrator and minimal starter site; Demo seed protection; Deployment lock and migrations; Production services and environment.

Start the initialized site and control later upgrades

After bootstrap, run the deployment helper to start and check the complete installation. For an existing installation, first take and verify a database-and-media backup, prevent concurrent deployments or maintenance writers, and review the release's migrations. Keep the existing private environment and project. Do not bootstrap or seed during an upgrade.

powershell
node scripts/ops/deploy.mjs --env-file .env.production.local --project gcms

Before any build or service change, the helper resolves Compose configuration and checks the whole project inventory. Duplicate service slots, retained recovery containers, uncertain identities or unhealthy running services require separate operator maintenance; the helper does not restart Docker, discard legacy objects or rotate credentials. After this read-only gate passes, it builds web and operations images, starts and waits for PostgreSQL, stops this project's web and worker, runs migrations, then starts and verifies the application services. The migration runner holds its deployment lock across application integrity setup and queue migration. A failed migration leaves application services stopped so incompatible code is not casually placed back in service. Diagnose that failure against the preserved database; do not remove its volume to obtain a green startup.

Migrations 0004 and 0005 rebuild derived public metadata and search indexes. The generated search column can rewrite the projection, and transactional index creation can block reads and publication writes. Rehearse large installations on a disposable copy with a verified backup, a maintenance window and sufficient temporary disk and database log space. Retain the prior compatible application image; do not drop derived tables or reverse schema changes during an uncertain migration.

Sources: Controlled deployment helper; Deployment lock and migrations; Production services and environment.

Verify the running site before routing traffic

powershell
docker compose --env-file .env.production.local --project-name gcms ps
docker compose --env-file .env.production.local --project-name gcms logs --tail 100 web worker

Container health is the first check. The web liveness endpoint is /api/health; /api/ready also checks database/schema access and the configured media location. Test real login, public pages and a permitted media request at the target origin. Check that the worker is ready rather than intentionally paused. Verify one controlled scheduled publication and actual SMTP delivery through the configured provider. Captured development mail is not evidence of production delivery.

Before enabling a proxy cache or CDN, test withdrawal, preview isolation, cookies and response headers through that exact path. The supplied profile does not rely on shared page-response caching. Keep backups, compatible release images and protected recovery configuration together operationally, even though secrets are stored separately from the archive. Record who owns alerts, upgrades and recovery. The verified local package is a sound starting point; these host-specific responsibilities establish whether the public installation is ready to operate.

Sources: Production services and environment; Readiness endpoint; Worker readiness and paused mode; Verified production installation; Deployment and operational policy.

Enable only the public features this installation needs

GCMS_PUBLIC_DOCS_ENABLED and GCMS_ENQUIRIES_ENABLED both default to false. Set a switch to true only for the installation that should expose that feature. Public documentation uses /docs, with public guide search and downloads. Enabling it is refused when existing content, an archive or a redirect already claims /docs or a descendant URL; move those claims deliberately before enabling the feature. Signed-in workspace documentation remains available separately.

Enquiries also require GCMS_ENQUIRIES_TO to contain one valid recipient address. Publish a Contact form component on the intended Page and configure SMTP for the installation. The form saves a fixed demo or quote request; the separate worker handles notification. Test captured mail locally and verify real delivery with the chosen provider before public launch. A visitor cannot change the configured recipient.

Separate local installations need separate databases, media, authentication secrets and origins. Different localhost ports share browser cookie scope, so give an additional installation its own GCMS_AUTH_COOKIE_PREFIX. Leaving this optional prefix unset preserves existing cookies. These switches are deployment configuration; they are not editable through Pages and do not enable open registration.

Sources: Validated installation feature switches; Public documentation route protection; Private enquiry processing.