Route every Strapi plugin path to the CMS, not just /admin

Strapi mounts each plugin's admin API at its own top-level path
(/content-manager, /upload, /i18n, ...), not nested under /admin as
previously assumed. That broke the dashboard widgets: recent/count
documents calls landed on the frontend instead of Strapi. List every
prefix actually used by the installed plugins (core-bundled ones plus
users-permissions and cloud from cms/package.json) explicitly in the
Caddyfile.
This commit is contained in:
2026-08-25 20:06:40 +02:00
parent e927396505
commit 8021ea7254
3 changed files with 26 additions and 16 deletions
+8 -5
View File
@@ -16,13 +16,16 @@ sitemap e `robots.txt` dinamici, ricerca, e i test (nessun framework ancora conf
## Architettura
```text
Browser → Caddy ─┬─ /admin, /uploads → Strapi 5 → PostgreSQL
└─ tutto il resto → Nuxt 4 (SSR) → REST Strapi
Browser → Caddy ─┬─ /admin e i path dei plugin Strapi → Strapi 5 → PostgreSQL
└─ tutto il resto → Nuxt 4 (SSR) → REST Strapi
```
Caddy instrada per **path**, non per sottodominio: `PUBLIC_DOMAIN` serve sia il sito che,
sotto `/admin` e `/uploads`, il pannello Strapi (Strapi 5 annida l'intera admin UI e la sua
API sotto `/admin`, senza toccare `/api`). Un solo dominio, un solo certificato TLS.
Caddy instrada per **path**, non per sottodominio: `PUBLIC_DOMAIN` serve sia il sito che il
pannello Strapi. Ogni plugin Strapi monta la propria API admin sul proprio path di primo
livello, non tutto sotto `/admin` (es. `/content-manager`, `/upload`, `/i18n`...): l'elenco
completo dei prefissi da instradare a Strapi vive nel `Caddyfile`. Se aggiungi un plugin
Strapi, aggiungi il suo prefisso lì. Niente di questo tocca `/api`, riservato agli endpoint
Nitro del frontend. Un solo dominio, un solo certificato TLS.
- Strapi è la **sola** fonte di verità editoriale. Niente altro backend (no Express/Nest/Fastify):
se serve logica server, sta in Nitro (`frontend/server/`) o in un controller Strapi.
+6 -6
View File
@@ -4,8 +4,8 @@ Blog platform: a public website built with Nuxt, and a private Strapi CMS where
articles are written. Everything runs behind Caddy via Docker Compose.
```text
Browser → Caddy ─┬─ /admin, /uploads → Strapi (CMS) → PostgreSQL
└─ everything else → Nuxt (website)
Browser → Caddy ─┬─ /admin and Strapi's plugin paths → Strapi (CMS) → PostgreSQL
└─ everything else → Nuxt (website)
```
There are no front-end accounts: sign-up is disabled and only administrators write
@@ -94,7 +94,7 @@ reachable inside the Docker network — do not publish their ports.
| `PUBLIC_DOMAIN` | `example.com` |
| `ACME_EMAIL` | a mailbox you read — Let's Encrypt sends expiry warnings there |
| `PUBLIC_SITE_URL` | `https://example.com` |
| `PUBLIC_STRAPI_URL` | `https://example.com` — same origin, Caddy proxies `/admin` and `/uploads` to Strapi |
| `PUBLIC_STRAPI_URL` | `https://example.com` — same origin, Caddy proxies `/admin` and Strapi's other plugin paths there (see `caddy/Caddyfile`) |
| `STRAPI_URL` | leave it as `http://cms:1337` — internal address, never public |
Then generate **fresh** secrets on that machine with the same loop as in development —
@@ -111,9 +111,9 @@ already ignored.
docker compose up -d --build
```
This time Caddy is included: it serves both the website and, under `/admin` and
`/uploads`, the CMS on `PUBLIC_DOMAIN`, obtains and renews the TLS certificate on its own,
and adds HSTS and the other security headers.
This time Caddy is included: it serves both the website and, under `/admin` and Strapi's
other plugin paths, the CMS on `PUBLIC_DOMAIN`, obtains and renews the TLS certificate on
its own, and adds HSTS and the other security headers.
**5. Create the administrator account** at `https://example.com/admin`, immediately,
before anyone else finds the URL — the first visitor to that form is the one who gets the
+12 -5
View File
@@ -16,11 +16,18 @@
import security_headers
encode zstd gzip
# /admin and /uploads go to Strapi; everything else to the frontend.
# Strapi 5 nests the whole admin panel (UI + its own API) under /admin,
# so this single prefix is enough - it never touches /api, which stays
# reserved for the frontend's own Nitro endpoints.
@cms path /admin* /uploads*
# Strapi mounts each of its (and its plugins') admin APIs at its own
# top-level path, not all under /admin - the admin panel's dashboard
# widgets, media library, i18n, etc each call their own plugin prefix.
# This list is every @strapi/* package in cms/package.json plus the
# core-bundled plugins (content-manager, content-type-builder, upload,
# i18n, email, content-releases, review-workflows). Adding a new Strapi
# plugin later means adding its prefix here too.
# None of this touches /api, reserved for the frontend's own Nitro
# endpoints.
@cms path /admin* /content-manager* /content-type-builder* /upload*\
/i18n* /email* /content-releases* /review-workflows*\
/users-permissions* /cloud*
handle @cms {
# Uploaded media can be large; Strapi's own limit still applies.
request_body {