Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,35 @@ jobs:
- name: Import end to end
run: tests/e2e/import.sh

# A real Ghost-CLI production site (MySQL, systemd, nginx on port 80, an
# admin domain) moved to Docker on the same server, as docs/install.md says:
# a forced failure with nginx still running, its recovery, then the move.
# It changes the host, which a runner is for.
production-import-linux:
name: Production import on Linux
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: "22"

# Ghost-CLI installed globally: its systemd service runs it as the
# `ghost` user, which cannot reach npx's cache in the runner's home.
- name: Ghost-CLI, nginx and MySQL for the source
run: |
npm install --global ghost-cli@1.33.4
sudo apt-get update
sudo apt-get install --yes nginx
sudo systemctl start nginx mysql

- name: Production import end to end
env:
GD_TEST_HOST_CHANGES: "1"
run: tests/e2e/production-import.sh

# macOS's system bash is 3.2, which the launcher has to run on. GitHub's
# macOS runners have no Docker daemon, so the half of the test that runs the
# real image is skipped, explicitly, here alone; the half that checks the
Expand Down
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ Configuration to run Ghost and its services with Docker Compose.

> **This is the `next-docker` development branch.** It is being rebuilt around
> a manager image: a small CLI in a container, started by a bash launcher that
> uses Docker. It installs local and production sites, imports local Ghost-CLI
> sites, backs up and restores them, and updates image installations between
> beta releases. Production import and migration from the released `main` layout
> remain on the [roadmap](docs/ghost-cli-replacement.md). For a supported setup
> uses Docker. It installs local and production sites, imports local and production
> Ghost-CLI sites, backs up and restores them, and updates image installations
> between beta releases. Migration from the released `main` layout remains on
> the [roadmap](docs/ghost-cli-replacement.md). For a supported setup
> today, use the `main` branch.

## The launcher
Expand Down Expand Up @@ -93,6 +93,7 @@ tests/e2e/install.sh # real installations: pulls images, binds 80 and 44
tests/e2e/self-update.sh # release updates, failed-update write retention and recovery
tests/e2e/backup.sh # real backups and restores, including ActivityPub
tests/e2e/import.sh # real Ghost-CLI sites exported and imported
GD_TEST_HOST_CHANGES=1 tests/e2e/production-import.sh # a Ghost-CLI production site moved; changes the host
```

Shell changes also pass ShellCheck. Unit tests substitute `Io` at the Engine API,
Expand Down
6 changes: 5 additions & 1 deletion docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,11 @@ An import writes into a fresh site and records what it creates in an incomplete
marker. Until verified, `.env` selects no services, so ordinary Compose cannot
start a half-imported site. A failed import removes its work; the next import
clears interrupted work before retrying. A portable bundle's JSON and members CSV
are imported through Ghost Admin, as [install.md](install.md) describes.
are imported through Ghost Admin, as [install.md](install.md) describes. The
bundle's `sourceInstallType` selects the site mode; a production import is an
ordinary production install on the bundle's domains, refused before any write
when its URLs cannot be served as they are. Moving the source's traffic (stopping
it, its proxy, DNS) is documented, not automated.

## Verification and service access

Expand Down
18 changes: 11 additions & 7 deletions docs/bundle-v1.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
# Migration bundle v1 — encoding contract

Ghost-CLI exports a migration bundle; ghost-docker imports it. This document
owns its format and importer requirements. Use Ghost-CLI **1.33.3 or later**;
see the exporter's [migration bundle documentation](https://github.com/TryGhost/Ghost-CLI/blob/v1.33.3/docs/migration-bundle.md)
owns its format and importer requirements. Use Ghost-CLI **1.33.4 or later**;
see the exporter's [migration bundle documentation](https://github.com/TryGhost/Ghost-CLI/blob/v1.33.4/docs/migration-bundle.md)
and [operator import steps](install.md#importing-a-ghost-cli-site).

The strict schema in [`manager/src/bundle/manifest.ts`](../manager/src/bundle/manifest.ts)
depends only on zod so the exporter can share it; importer policy stays outside
it. Bundle v1 is not frozen: exporter, importer, documentation and fixtures
change together, without draft-format adapters.

Local `mysql-dump`, `mysql-data` and `portable` bundles are supported. For a
portable bundle the manager installs the site and content; JSON and members CSV
are imported through Ghost Admin. Production import remains [S5e roadmap
work](ghost-cli-replacement.md#s5e--production-import-and-cutover).
Local `mysql-dump`, `mysql-data` and `portable` bundles are supported, and
production `mysql-dump` and `mysql-data` ones. For a portable bundle the manager
installs the site and content; JSON and members CSV are imported through Ghost
Admin. A portable bundle of a production site is refused. `sourceInstallType`
selects the site mode; a production site is served on the hosts of `url` and
`adminUrl` unless the operator names others (on another domain, `adminUrl` is
not carried), and a URL with plain `http`, a
port or a path is refused rather than served at another address.

## Bundle kinds

Expand Down Expand Up @@ -286,7 +290,7 @@ integrations; reconnect/reconcile Stripe using a supported importer.
relationships without these losses; external services and storage still need
separate configuration.

See the exporter's [fidelity and recovery documentation](https://github.com/TryGhost/Ghost-CLI/blob/v1.33.3/docs/migration-bundle.md).
See the exporter's [fidelity and recovery documentation](https://github.com/TryGhost/Ghost-CLI/blob/v1.33.4/docs/migration-bundle.md).
The manager places a portable bundle's content and leaves its content JSON and
members CSV to Ghost Admin; their fidelity is that of Ghost Admin's own import.

Expand Down
2 changes: 1 addition & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ minimum and exact source-version requirement.

Do not use `git pull` to move a released `main` installation to this layout.
That migration is still [roadmap work](ghost-cli-replacement.md#s6b--migration-from-the-released-main-layout).
Moving a Ghost-CLI site is a separate, supported local import described in
Moving a Ghost-CLI site is a separate, supported import described in
[install.md](install.md#importing-a-ghost-cli-site).

## Installed image pins
Expand Down
38 changes: 16 additions & 22 deletions docs/ghost-cli-replacement.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,28 +25,22 @@ outside the planned scope.

### S5e — Production import and cutover

Repo: ghost-docker. Depends on the existing local importer and [bundle
contract](bundle-v1.md), including its minimum source version and exact-version import.
Support `sourceInstallType: production`, separate admin URLs, and the same-server case
with an existing proxy on 80/443.

Document cutover: stop the source before its final export (or explicitly use
`--leave-stopped`), import into a fresh destination, then point DNS at the new host or
switch the proxy on the same server. Keep the source stopped and intact until the
destination is accepted. Never stop an existing proxy automatically; it may serve other
applications. A rehearsal with copied configuration must not send real mail, newsletters
or webhooks.

Retain staging/path validation and database-user isolation. Bound expansion and check
space for extracted content, database restore and recovery copies; compressed archive
size times 1.5 is insufficient. Verify the source version's image on every supported
architecture before provisioning. Preserve supported URL path/port semantics or reject
them clearly. Do not guess ownership as uid 1000 under rootless/user namespaces.

Acceptance: same-server migration with an existing proxy on 80/443 and cross-host
migration following the documented cutover; exact source version, staff sign-in,
records, active theme, assets, redirects and configuration preserved. This replaces
`main`'s `scripts/migrate.sh`; S12 must not merge `next-docker` into `main` before these
Repo: ghost-docker. `install --import` takes production bundles and the cutover is
documented in [install.md](install.md#moving-a-production-site). Remaining:

Bound expansion and check space for extracted content and the database restore;
compressed archive size times 1.5 is insufficient. Do not guess ownership as uid
1000 under rootless/user namespaces.

Acceptance, on Linux with rootful Docker Engine and a real Ghost-CLI production
install (MySQL, systemd, nginx): same-server and cross-host moves following the
documented steps; a forced import failure leaving the directory as it was, with the
documented recovery bringing back the source and nginx; a separate admin domain
carried from the bundle; exact source version, staff sign-in, records, active theme,
assets, redirects and configuration preserved.
`tests/e2e/production-import.sh` covers the same-server move, the forced failure and
its recovery, and the admin domain in CI; the cross-host move is run by hand. This replaces `main`'s
`scripts/migrate.sh`; S12 must not merge `next-docker` into `main` before these
scenarios pass.

### S6b — Migration from the released main layout
Expand Down
Loading
Loading