Back to Ghost

Testing development URLs and devices

docs/contributing/testing-development-urls.md

6.58.04.8 KB
Original Source

Testing development URLs and devices

Ghost supports configurations that differ from the normal http://localhost:2368 setup. Test the configuration that matters to your change rather than rebuilding the whole development environment for every URL edge case.

Test on another device

Use an HTTPS tunnel when you need to open the site or Admin on a phone, tablet, or another computer. This avoids maintaining local DNS, assigning a static IP, and installing a local certificate authority on every test device.

With pnpm dev running, install and authenticate the ngrok agent, then run:

bash
ngrok http 2368

Open the HTTPS forwarding URL on the other device. Ghost Admin is available at /ghost/ on the same URL.

The development Caddy gateway trusts the forwarded protocol supplied by ngrok, Tailscale Funnel, and similar HTTPS tunnel agents. Tunnel the gateway on port 2368, not an individual Admin or public-app development server, so requests continue through the same routing used by the normal development environment.

Tunnel URLs are normally temporary. The site can be inspected without changing Ghost's configured URL, but links generated by Ghost will still use http://localhost:2368. When the behaviour under test depends on absolute URLs, create ghost/core/config.local.json with the forwarding URL and restart the development environment:

json
{
    "url": "https://your-forwarding-domain.example"
}

Do not commit config.local.json. Remove the override when the test is finished.

Treat a public tunnel URL as temporary public access to the local site. Do not use production data or credentials, and stop the tunnel after testing.

Test HTTPS, subdirectories, and a separate Admin URL

Use the manual environment below when you need to inspect all three behaviours in a browser. It runs a local TLS proxy in front of Ghost Core and uses .localhost hostnames, which resolve to the loopback address without editing /etc/hosts or running a DNS server.

Install Caddy if it is not already available. Create ghost/core/config.local.json:

json
{
    "url": "https://site.localhost:8443/blog/",
    "admin": {
        "url": "https://admin.localhost:8443/blog/"
    }
}

The site URL supplies the /blog/ subdirectory. The separate Admin URL uses the same subdirectory because Ghost's Admin and API routes remain underneath the configured site path.

Start the Docker services with the URL-testing Compose override:

bash
DEV_COMPOSE_FILES="-f docker/dev-url-testing/compose.yaml" \
    pnpm nx run ghost-monorepo:docker:up

The override exposes Ghost Core directly on port 2369. This is intentional: the extra Caddy process must connect directly to Ghost so Express can trust its forwarded HTTPS header.

In another terminal, start the local TLS proxy:

bash
caddy run --adapter caddyfile \
    --config docker/dev-url-testing/Caddyfile

Caddy may ask for the system password the first time so it can install its local certificate authority. Open:

  • Site: https://site.localhost:8443/blog/
  • Admin: https://admin.localhost:8443/blog/ghost/

Check the behaviour affected by the change, including redirects, generated links, API requests, cookies, and assets. A request to the site hostname's /blog/ghost/ path should redirect to the Admin hostname.

This configuration serves the Admin assets available from Ghost Core. It does not use the normal Admin Vite/HMR route because that development server's startup probe assumes the default root URL. Use the automated tests below for focused development, then use this manual environment for final browser verification.

Press Ctrl+C to stop Caddy. Stop the Docker services with the same override:

bash
DEV_COMPOSE_FILES="-f docker/dev-url-testing/compose.yaml" pnpm docker:down

Delete ghost/core/config.local.json before returning to pnpm dev; otherwise Ghost will continue using the alternate URLs. The file is ignored by Git.

Add automated URL-configuration coverage

Ghost Core keeps its advanced URL configuration coverage in ghost/core/test/e2e-frontend/advanced-url-config.test.js. It currently covers subdirectory routing and redirects to a separate Admin origin, and is the default place to add HTTP-level coverage for behaviour that depends on:

  • an HTTPS site URL;
  • a site installed in a subdirectory; or
  • Admin and the site using different origins.

Run the file from ghost/core:

bash
pnpm test:single test/e2e-frontend/advanced-url-config.test.js

Add a focused case there when the behaviour can be verified through Ghost's HTTP responses, redirects, generated URLs, or routing. Tests elsewhere in ghost/core/test/ also set url and admin:url through the shared test config helpers when a lower-level test is sufficient.