Skip to content

Changed devcontainer dev stack to match Admin + Portal default#29106

Draft
9larsons wants to merge 10 commits into
mainfrom
slars/devcontainer-ghost-portal-default
Draft

Changed devcontainer dev stack to match Admin + Portal default#29106
9larsons wants to merge 10 commits into
mainfrom
slars/devcontainer-ghost-portal-default

Conversation

@9larsons

@9larsons 9larsons commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

no ref

Summary

  • Stacks on top of Changed public app dev defaults #29105, which narrows root pnpm dev's default frontend fan-out to Admin + Portal only.
  • Updates .devcontainer/start-dev-stack.sh, which previously hardcoded its own full frontend project list independently of root pnpm dev, so it wasn't picking up the memory savings from Changed public app dev defaults #29105.
  • Public UMD app watchers (Comments UI, Signup Form, Sodo Search, Announcement Bar, Admin Toolbar) are still available on demand via an explicit nx run-many command, printed in the script's startup message.
  • Removed dead *_DEV_SERVER proxy targets for Portal/Comments UI/Signup Form/Sodo Search/Announcement Bar/Admin Toolbar from docker/dev-gateway/Dockerfile, the devcontainer's compose override, and forwarded ports in devcontainer.json. Unread since Removed public-app vite preview servers in favor of Caddy file_server #28970 switched public apps to Caddy file_server; confirmed via grep the Caddyfile never references them. Fixing the shared Dockerfile removes the need to re-declare dead vars in the devcontainer overlay, and stops Codespaces showing five phantom forwarded ports nothing ever binds.
  • Fixed Admin never finishing startup in the devcontainer (502 on /ghost/ indefinitely). apps/admin's dev target dependsOn: ["ghost-monorepo:docker:up", ...] (added in Changed dev target orchestration #29101 for the host flow, where pnpm dev is a single Nx invocation and dedupes docker:up to one harmless run). The devcontainer's start-dev-stack.sh invokes Admin's dev target via a separate nx run-many call from the backend's pnpm --filter ghost dev, so docker:up actually re-executes — and its docker compose ... up -d --force-recreate --wait, run from inside the ghost-dev container via the mounted host docker socket, recreates the very container issuing the command. Portal has no such dependency, which is why it always loaded fine while Admin hung. Guarded the recreate behind CODESPACES/REMOTE_CONTAINERS (set inside the container by both Codespaces and VS Code Dev Containers) — redundant there anyway since the devcontainer's own compose lifecycle already brings services up before start-dev-stack.sh runs.

Test plan

  • bash -n passes on the modified script
  • docker compose -f compose.dev.yaml -f .devcontainer/compose.devcontainer.yaml config merges cleanly with only the four live gateway env vars
  • node -e "JSON.parse(...)" on package.json after the docker:up guard; verified the shell conditional takes the correct branch with/without CODESPACES set
  • Open a Codespace from this branch and verify: only Admin + Portal watchers start by default, the Ports panel shows only the 8 real ports, and /ghost/ (Admin) loads instead of 502ing indefinitely
  • Verify the printed opt-in command successfully starts the public apps when run manually

@cursor

cursor Bot commented Jul 4, 2026

Copy link
Copy Markdown

Bugbot is not enabled for this team, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR updates devcontainer and dev-gateway setup so public apps are served from built umd/ output via Caddy file_server instead of per-app dev servers. It removes the related environment variables, forwarded ports, and routing entries, narrows the default dev watcher startup to Admin and Portal, skips docker compose actions inside the devcontainer, and removes the extra post-create package install step.

Possibly related PRs

  • TryGhost/Ghost#28849: Adjusts ghost-dev storage and volume setup in the same container path.
  • TryGhost/Ghost#28968: Changes the same public-app asset flow toward disk-served UMD output.
  • TryGhost/Ghost#28969: Adjusts the @tryghost/parse-email-address dev/build flow in a related container setup path.

Suggested reviewers: acburdine

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: updating the devcontainer dev stack to align with the Admin + Portal default.
Description check ✅ Passed The description is clearly related to the changeset and accurately summarizes the devcontainer and gateway updates.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch slars/devcontainer-ghost-portal-default

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@nx-cloud

nx-cloud Bot commented Jul 4, 2026

Copy link
Copy Markdown

🤖 Nx Cloud AI Fix

Ensure the fix-ci command is configured to always run in your CI pipeline to get automatic fixes in future runs. For more information, please see https://nx.dev/ci/features/self-healing-ci


View your CI Pipeline Execution ↗ for commit f70d9b5

Command Status Duration Result
nx run @tryghost/admin-x-settings:test:acceptance ✅ Succeeded 9m 53s View ↗
nx run ghost:test:integration ✅ Succeeded 2m 45s View ↗
nx run ghost:test:ci:integration ✅ Succeeded 3s View ↗
nx run ghost:test:legacy ✅ Succeeded 2m 55s View ↗
nx run ghost:test:e2e ✅ Succeeded 2m 26s View ↗
nx run-many --target=build --projects=tag:publi... ✅ Succeeded <1s View ↗
nx run @tryghost/comments-ui:test:acceptance ✅ Succeeded 46s View ↗
nx run @tryghost/activitypub:test:acceptance ✅ Succeeded 45s View ↗
Additional runs (7) ✅ Succeeded ... View ↗

💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗


☁️ Nx Cloud last updated this comment at 2026-07-05 00:37:35 UTC

@9larsons 9larsons force-pushed the codex/public-dev-opt-ins-main branch 3 times, most recently from 84a1525 to 7f788ce Compare July 4, 2026 20:43
@cursor

cursor Bot commented Jul 4, 2026

Copy link
Copy Markdown

Bugbot is not enabled for this team, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

Base automatically changed from codex/public-dev-opt-ins-main to main July 4, 2026 21:05
9larsons added 2 commits July 4, 2026 16:07
no ref

pnpm dev's default frontend fan-out was narrowed to Admin + Portal only
(#29104/#29105), since most sessions never touch the public UMD apps and
those watchers are the heaviest processes in the stack. The devcontainer's
start-dev-stack.sh hardcoded the old full project list independently of
root pnpm dev, so it needed the same trim to actually get the memory
savings inside Codespaces/devcontainers. Public apps remain available
via an explicit nx run-many invocation, called out in the script's output.
no ref

#28970 switched public apps (Portal, Comments UI, Signup Form, Sodo
Search, Announcement Bar, Admin Toolbar) from a proxied vite preview
server to Caddy serving their umd/ build output directly via
file_server, but left the now-unread *_DEV_SERVER env vars in the
gateway Dockerfile and the devcontainer's compose override, and left
their ports forwarded in devcontainer.json. Confirmed via grep that the
Caddyfile only ever reads GHOST_BACKEND, ADMIN_DEV_SERVER,
ADMIN_LIVE_RELOAD_SERVER, LEXICAL_DEV_SERVER, ANALYTICS_PROXY_TARGET,
and ACTIVITYPUB_PROXY_TARGET. Fixing at the Dockerfile (shared by host
and devcontainer builds) removes the need to keep re-declaring dead
vars in the devcontainer overlay, and stops Codespaces from showing
five phantom ports nothing ever binds.
@9larsons 9larsons force-pushed the slars/devcontainer-ghost-portal-default branch from 32009eb to f49dfd3 Compare July 4, 2026 21:07
@cursor

cursor Bot commented Jul 4, 2026

Copy link
Copy Markdown

Bugbot is not enabled for this team, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

no ref

apps/admin's dev target dependsOn ghost-monorepo:docker:up (added by
#29101 so host pnpm dev doesn't race Vite against Docker startup). On
host that's a harmless no-op re-run, since pnpm dev is a single nx
invocation that already deduped docker:up to one execution. Inside the
devcontainer, start-dev-stack.sh calls nx run-many for Admin/Portal as
a separate invocation from the backend's pnpm --filter ghost dev, so
docker:up actually re-executes there. --force-recreate, run from inside
the ghost-dev container via the mounted host docker socket, recreates
the very container issuing the command -- so Admin's Vite server got
stuck behind a docker compose command tearing down its own host, and
/ghost/ 502'd indefinitely while Portal (no such dependency) loaded
fine. Guarded the actual recreate on CODESPACES/REMOTE_CONTAINERS,
which Codespaces and VS Code Dev Containers both set inside the
container -- the devcontainer's own compose lifecycle already brings
these services up before start-dev-stack.sh ever runs, so the recreate
is redundant there regardless of the invocation-count issue.
@cursor

cursor Bot commented Jul 4, 2026

Copy link
Copy Markdown

Bugbot is not enabled for this team, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@codecov

codecov Bot commented Jul 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 74.30%. Comparing base (2776308) to head (f70d9b5).

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #29106      +/-   ##
==========================================
+ Coverage   74.27%   74.30%   +0.02%     
==========================================
  Files        1565     1565              
  Lines      135716   135716              
  Branches    16453    16458       +5     
==========================================
+ Hits       100804   100840      +36     
+ Misses      33883    33876       -7     
+ Partials     1029     1000      -29     
Flag Coverage Δ
e2e-tests 76.45% <ø> (+0.03%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

no ref

onCreateCommand and postCreateCommand both ran a full pnpm install
--prefer-offline over the same fully-mounted workspace, back to back,
with nothing but a submodule update between them. Checked .gitmodules
-- both submodules are theme content (Casper, Source), not workspace
packages, so there's no dependency-order reason postCreateCommand's
install needed the submodules in place first. Dropped the redundant
one; onCreateCommand's already covers it.
@cursor

cursor Bot commented Jul 4, 2026

Copy link
Copy Markdown

Bugbot is not enabled for this team, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

…m store

no ref

.github/workflows/devcontainer-build.yml has published
ghcr.io/tryghost/ghost-devcontainer:latest with GHA layer caching on
every relevant main push, but nothing consumed it -- the devcontainer's
ghost-dev service only had a build: block, so every fresh
codespace/container rebuilt the image from scratch (apt-get,
backend-only pnpm install) regardless.

Considered baking the full-workspace pnpm install into a layered image
on top of that base, but compose.devcontainer.yaml bind-mounts the
entire repo over /workspaces/Ghost, which fully shadows anything an
image bakes in at that path with the host's (node_modules-less)
checkout -- the same reason onCreateCommand/postCreateCommand have to
run pnpm install live in the first place. A per-workspace-package
volume mount could work around that but means ~19 entries to maintain
as packages come and go.

Instead: added image: pointing at the published tag (with build.cache_from
so a local rebuild, e.g. after a Dockerfile edit, still reuses those
layers instead of starting cold) and an initializeCommand to pre-pull it
into the local image cache before the container is built or pulled.
Separately, cached pnpm's content-addressable store as a named volume
at /pnpm-store (outside /workspaces/Ghost, so the bind mount can't
shadow it) via npm_config_store_dir. The live pnpm install
onCreateCommand/postCreateCommand still run every time, but against a
warm store they're linking already-fetched content instead of
re-downloading and recompiling native deps (better-sqlite3, sharp,
etc.) from scratch.
@cursor

cursor Bot commented Jul 4, 2026

Copy link
Copy Markdown

Bugbot is not enabled for this team, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.devcontainer/compose.devcontainer.yaml:
- Around line 34-35: The devcontainer environment is using the wrong store-path
variable for pnpm, so the cache volume will be ignored. In the devcontainer
compose config, update the environment entry under the devcontainer service from
npm_config_store_dir to pnpm_config_store_dir so pnpm@11.8.0 in the
packageManager field can read it correctly. Keep the value pointing to
/pnpm-store and ensure the setting is applied in the same environment block.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a1de04bd-7d32-4953-93ee-6ec3336fffc5

📥 Commits

Reviewing files that changed from the base of the PR and between c755ca9 and 18a2a92.

📒 Files selected for processing (2)
  • .devcontainer/compose.devcontainer.yaml
  • .devcontainer/devcontainer.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • .devcontainer/devcontainer.json

Comment on lines +34 to +35
environment:
npm_config_store_dir: /pnpm-store

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== package.json packageManager ==\n'
if [ -f package.json ]; then
  grep -n '"packageManager"' package.json || true
fi

printf '\n== repo files likely relevant ==\n'
git ls-files | rg '(^|/)(package.json|pnpm-lock\.yaml|pnpm-workspace\.yaml|\.devcontainer/compose\.devcontainer\.yaml)$' || true

printf '\n== inspect package.json if present ==\n'
if [ -f package.json ]; then
  cat -n package.json | sed -n '1,120p'
fi

printf '\n== inspect devcontainer file ==\n'
cat -n .devcontainer/compose.devcontainer.yaml | sed -n '1,120p'

Repository: TryGhost/Ghost

Length of output: 13418


🌐 Web query:

pnpm 11.8.0 environment variable config prefixes npm_config_store_dir pnpm_config_store_dir store-dir docs

💡 Result:

In pnpm 11.8.0, configuration is managed through environment variables prefixed with pnpm_config_ or PNPM_CONFIG_ [1][2]. The documentation explicitly states that pnpm no longer reads npm_config_* environment variables [2]. Users are advised to transition to using the pnpm_config_ prefix for all configuration settings [2]. For setting the package store directory, you should use the store-dir configuration setting [3]. You can configure this using the pnpm_config_store_dir environment variable [1][2]. Summary of Key Points: - Environment Variable Prefix: Use pnpm_config_ (e.g., pnpm_config_store_dir) [1][2]. The legacy npm_config_ prefix is no longer supported for pnpm configuration [2]. - Configuration Setting: The setting for the package store directory is store-dir [3]. - Setting via CLI: You can also set this configuration persistently using the command: pnpm config set store-dir /path/to/.pnpm-store [3]. - Behavior: If no store-dir is configured, pnpm will automatically create a store on the same drive and filesystem where the installation is taking place [3][4]. For optimal performance and to enable hard linking, the store must reside on the same drive as the project [4][5]. If the store is on a different drive, pnpm will copy files instead of linking them [4][5].

Citations:


Use pnpm_config_store_dir for the devcontainer store path

packageManager pins pnpm@11.8.0, which reads pnpm_config_*/PNPM_CONFIG_* only. npm_config_store_dir will be ignored, so the cache volume won’t take effect. Switch it to pnpm_config_store_dir: /pnpm-store.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.devcontainer/compose.devcontainer.yaml around lines 34 - 35, The
devcontainer environment is using the wrong store-path variable for pnpm, so the
cache volume will be ignored. In the devcontainer compose config, update the
environment entry under the devcontainer service from npm_config_store_dir to
pnpm_config_store_dir so pnpm@11.8.0 in the packageManager field can read it
correctly. Keep the value pointing to /pnpm-store and ensure the setting is
applied in the same environment block.

no ref

The docker:up guard from the previous commit only covered docker:up's
own command -- its dependsOn: [docker:build] still ran unconditionally,
rebuilding ghost-dev-gateway's xcaddy-compiled Caddy image and
ghost-dev's own image from inside the container on every Admin dev
startup (Admin depends on docker:up, which depends on docker:build).
That's real, wasted work in the devcontainer, where the images are
already built/pulled by the devcontainer's own compose lifecycle before
start-dev-stack.sh ever runs, and likely explains Admin's Vite still not
coming up in testing after the docker:up fix alone. Applied the same
CODESPACES/REMOTE_CONTAINERS guard.
@cursor

cursor Bot commented Jul 4, 2026

Copy link
Copy Markdown

Bugbot is not enabled for this team, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
package.json (1)

129-129: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Guard logic correct; consider extracting shared devcontainer-detection logic.

The docker:build guard correctly mirrors the docker:up guard at Line 114, and the $CODESPACES$REMOTE_CONTAINERS non-empty check will correctly detect either a Codespaces or a VS Code Dev Containers environment (the extension sets REMOTE_CONTAINERS=true inside the container). No functional issue here.

Since this inline conditional is now duplicated across two nx targets, consider extracting it into a small shared script (e.g. .devcontainer/skip-if-devcontainer.sh) to avoid repeating the same guard string if a third target needs it later.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@package.json` at line 129, The devcontainer guard string is duplicated
between the `docker:build` and `docker:up` nx targets, so extract the shared
`$CODESPACES$REMOTE_CONTAINERS` detection and skip behavior into a small
reusable script or helper (for example a shared devcontainer guard script) and
have both targets call it. Update the existing command strings in the package
configuration to use that shared logic instead of embedding the same inline
conditional twice, so any future target can reuse the same check consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@package.json`:
- Line 129: The devcontainer guard string is duplicated between the
`docker:build` and `docker:up` nx targets, so extract the shared
`$CODESPACES$REMOTE_CONTAINERS` detection and skip behavior into a small
reusable script or helper (for example a shared devcontainer guard script) and
have both targets call it. Update the existing command strings in the package
configuration to use that shared logic instead of embedding the same inline
conditional twice, so any future target can reuse the same check consistently.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d0da9dd6-65a3-4caa-86fd-cbb2a951b5c7

📥 Commits

Reviewing files that changed from the base of the PR and between 18a2a92 and e71426f.

📒 Files selected for processing (1)
  • package.json

no ref

Ghost's session CSRF protection (cookieCsrfProtection in
ghost/core/core/server/services/auth/session/session-service.js)
compares the browser's Origin header against urlUtils.getAdminUrl(),
which comes from Ghost's configured `url` setting -- defaulted to
http://localhost:2368 (config.development.json). Codespaces serves
everything through a forwarded https://<name>-2368.<domain> origin
instead, so that check failed on every authenticated request and
bounced the session back to login, in a loop -- not a restart wiping
sessions (they're DB-backed via SessionStore, confirmed by reading
express-session.js).

url is a top-level nconf key, so a bare `url` env var overrides it.
Set it dynamically from Codespaces' own CODESPACE_NAME +
GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN env vars, guarded so local
(non-Codespaces) VS Code Dev Containers -- which really do forward to
localhost, no mismatch -- are unaffected.
@cursor

cursor Bot commented Jul 4, 2026

Copy link
Copy Markdown

Bugbot is not enabled for this team, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

no ref

gh codespace ssh/logs need an SSH server in the container -- without
one, diagnosing an issue means guessing from HTTP probes through
gh codespace ports forward, which can't show CPU/memory pressure, load
average, or which process is actually consuming resources. Adding
ghcr.io/devcontainers/features/sshd:1 so a suspected VM resource
problem can be checked directly instead of inferred.
@cursor

cursor Bot commented Jul 4, 2026

Copy link
Copy Markdown

Bugbot is not enabled for this team, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

no ref

SSH'd into a live devcontainer (added sshd feature in the previous
commit specifically to get real data instead of guessing) and found
two concrete resource issues via docker stats/ps aux under actual
usage:

- ember (ghost/admin's dev server, JOBS=4) was at 243% CPU / 2.5GB RSS
  continuously, well after its one-time build finished (frontend log
  confirmed a single 'Build successful', not a rebuild loop) -- i.e.
  idle watch mode itself was the cost. watchman wasn't installed in
  the image, so ember-cli's Watcher falls back to its much less
  efficient default Node-based watcher for a tree this large. Since
  VS Code Server's terminal/extension host run in the same container
  as ember, that sustained CPU hogging was directly stealing cycles
  from the terminal -- explaining the reported typing lag, not network
  latency. Installed watchman (confirmed available via apt on
  node:22.18.0-bullseye-slim: 4.9.0-5+b1); ember-cli auto-detects and
  prefers it over the Node watcher, no config needed. Only affects
  ghost-dev's own container -- the host-hybrid flow runs ember-cli on
  the developer's machine, not this image.

- ghost-dev-mysql was at 439-459MiB of its 512MiB mem_limit (85-90%)
  in two separate live snapshots, not just at boot. That cap was set
  for a 2-core/8GB Codespace budget but applies unconditionally
  regardless of the selected machine tier. Raised to 1g (matching
  host-hybrid's unconstrained default) for real headroom above the
  actual ~450MiB working set; innodb-buffer-pool-size stays at 256M,
  so behavior on the minimum tier is unchanged, just less pinned.
@cursor

cursor Bot commented Jul 4, 2026

Copy link
Copy Markdown

Bugbot is not enabled for this team, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

no ref

The url override from the previous commit fixed the browser-facing
CSRF/origin login loop, but broke apps/admin's own vite dev server:
its bootstrap fetch (resolveGhostSiteUrl in
apps/admin/vite-backend-proxy.ts) hits GHOST_URL +
ghost/api/admin/site/ directly at http://localhost:2368, bypassing
Caddy. Once Ghost's url is HTTPS, its url-redirects middleware
(getAdminRedirectUrl) 301s any request it sees as insecure to that
HTTPS url -- real browser traffic through Caddy is fine (Caddy sets
X-Forwarded-Proto: https, so Express's req.secure is true), but vite's
direct fetch has no such header, gets redirected to the public,
GitHub-auth-gated tunnel URL, and crashes trying to parse the login
page HTML as JSON. That crash cascades: Nx tears down the whole
run-many continuous-task group when one task exits non-zero, taking
Ember/Portal/shade/etc. down with it -- confirmed via SSH (added
sshd specifically to get this kind of ground truth instead of
guessing): a live snapshot caught ember as a defunct zombie following
this exact crash trace in the frontend log.

Fixed by routing GHOST_URL through the gateway container instead
(http://ghost-dev-gateway:80/) -- confirmed via direct curl that this
returns a clean 200 with the correct site JSON. Stays on the internal
Docker network (no GitHub auth wall) while still picking up
X-Forwarded-Proto: https from Caddy, so no redirect either.
@cursor

cursor Bot commented Jul 5, 2026

Copy link
Copy Markdown

Bugbot is not enabled for this team, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@9larsons 9larsons marked this pull request as draft July 7, 2026 14:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant