feat(website): mirror prod hostname pattern on dev (apex + www) (#20753)
## Summary Drops the `website.` subdomain on dev entirely and serves the marketing site from the bare zone + `www`, mirroring how prod is served at `twenty.com` + `www.twenty.com`. Also fixes a latent root-path substitution bug in the existing www→apex redirect that was masked on prod by a CF-level redirect. ## What changes - `wrangler.jsonc` env.dev routes: `twenty-main.com` (apex) + `www.twenty-main.com` (was `website.twenty-main.com`) - `next.config.ts`: extends host-based www→apex redirect to also cover `www.twenty-main.com`, and adds explicit `source: '/'` rules for both prod + dev before the catch-all `source: '/:path*'` (the `:path*` parameter doesn't substitute properly when it matches the empty root path against an absolute destination URL — Next.js leaves the literal `:path*` in the `Location` header) ## Live verification (after redeploy) | URL | Status | Notes | |---|---|---| | `https://twenty-main.com/` | 200 | `x-opennext: 1`, `x-nextjs-cache: HIT` | | `https://twenty-main.com/pricing` | 200 | Worker SSR | | `https://www.twenty-main.com/` | 308 → `https://twenty-main.com/` | Root-redirect fix applied | | `https://www.twenty-main.com/pricing` | 308 → `https://twenty-main.com/pricing` | Path preserved | | `https://twenty.com/` | 200 | Unchanged | | `https://www.twenty.com/` | 301 → `https://twenty.com/` | Still routed via CF-level redirect, now also covered by the new explicit Next rule as a defense-in-depth | | `https://website.twenty-main.com/` | 503 | DNS record removed by wrangler when route was deleted; hostname effectively retired | ## Companion infra PR https://github.com/twentyhq/twenty-infra/pull/__ — `cloudflare/website/dev.env` + `docs/4-environments.md` updated to the new URL; also bundles the CI fix that should have landed in #683 (was pushed too late).
This commit is contained in:
@@ -101,12 +101,33 @@ const nextConfig: LinariaConfig = {
|
||||
async redirects() {
|
||||
return [
|
||||
// Canonicalise www → apex. Host-based; fires before any locale logic.
|
||||
// The root-path rule must come before the :path* one — Next.js's
|
||||
// path-to-regexp leaves a literal `:path*` in the Location header
|
||||
// when the parameter matches empty against an absolute destination.
|
||||
{
|
||||
source: '/',
|
||||
has: [{ type: 'host', value: 'www.twenty.com' }],
|
||||
destination: 'https://twenty.com/',
|
||||
permanent: true,
|
||||
},
|
||||
{
|
||||
source: '/:path*',
|
||||
has: [{ type: 'host', value: 'www.twenty.com' }],
|
||||
destination: 'https://twenty.com/:path*',
|
||||
permanent: true,
|
||||
},
|
||||
{
|
||||
source: '/',
|
||||
has: [{ type: 'host', value: 'www.twenty-main.com' }],
|
||||
destination: 'https://twenty-main.com/',
|
||||
permanent: true,
|
||||
},
|
||||
{
|
||||
source: '/:path*',
|
||||
has: [{ type: 'host', value: 'www.twenty-main.com' }],
|
||||
destination: 'https://twenty-main.com/:path*',
|
||||
permanent: true,
|
||||
},
|
||||
// Strip the source-locale prefix: /en/foo → /foo (301). Mirrors proxy.ts Rule 1.
|
||||
{ source: '/en', destination: '/', statusCode: 301 },
|
||||
{ source: '/en/:path*', destination: '/:path*', statusCode: 301 },
|
||||
|
||||
@@ -16,7 +16,11 @@
|
||||
"name": "twenty-website-dev",
|
||||
"routes": [
|
||||
{
|
||||
"pattern": "website.twenty-main.com",
|
||||
"pattern": "twenty-main.com",
|
||||
"custom_domain": true,
|
||||
},
|
||||
{
|
||||
"pattern": "www.twenty-main.com",
|
||||
"custom_domain": true,
|
||||
},
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user