# 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](https://ngrok.com/docs/getting-started/), 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](https://caddyserver.com/docs/install) 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.
