fix(i18n,404,nginx): broken-windows batch B2 from the external review
Deploy / build (push) Successful in 3m59s
Deploy / build (push) Successful in 3m59s
All items measured before/after with curl, on the origin and through Cloudflare: - /posts/zh/ answered 403 (directory with no index) -> nginx 301 to the new archive - /zh/posts/ 404'd -> new src/pages/zh/posts/index.astro (build 163 -> 165 pages) - ZH nav pointed "关于" at /zh/ and "文章" at /zh/ -> /zh/about/ and /zh/posts/ - og:locale was "en" on every Chinese page -> zh_CN, plus og:locale:alternate on both languages (EN pages now advertise zh_CN as well) - hreflang "zh" -> "zh-Hans"; <html lang> on ZH pages -> zh-Hans - no 404 page existed -> src/pages/404.astro, served by nginx with a 404 status so crawlers skip it, offering search + archive + the 3 newest posts - JSON-LD Person gained worksFor (Hoelee Enterprise); image still omitted until the author photo exists rather than pointing at a placeholder nginx: config moved from the stock image file to a host bind mount (/mnt/user/docker/nginx-hoelee-blog/conf.d/default.conf, Portainer stack 247 on endpoint 3), validated with nginx -t in a throwaway container before the redeploy. It also sets /_astro/* to immutable 1-year (hashed names) and HTML to must-revalidate; unhashed /og/*.png and /banners/*.png keep the default TTL on purpose. Note: the public HSTS and 16-day asset TTL come from Cloudflare zone settings, not from this nginx. Docs: ops-runbook.md (the nginx layer + why each rule), project-state.md (B2 entry and the two open Cloudflare items my token cannot write).
This commit is contained in:
1 parent
831d440661
commit
874c434576
6 files changed
+160
-6
No files matched your search
@@ -45,7 +45,7 @@ const ogImageUrl = new URL(ogImage, SITE.url).href;
|
||||
const hreflang = altLocaleUrl
|
||||
? [
|
||||
{ hreflang: 'en', href: lang === 'en' ? canonical : altLocaleUrl },
|
||||
{ hreflang: 'zh', href: lang === 'zh' ? canonical : altLocaleUrl },
|
||||
{ hreflang: 'zh-Hans', href: lang === 'zh' ? canonical : altLocaleUrl },
|
||||
{ hreflang: 'x-default', href: lang === 'en' ? canonical : altLocaleUrl },
|
||||
]
|
||||
: [];
|
||||
@@ -63,7 +63,7 @@ const nav = isZh
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
<html lang={lang} data-theme="dark">
|
||||
<html lang={isZh ? 'zh-Hans' : lang} data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
@@ -87,8 +87,8 @@ const nav = isZh
|
||||
<meta property="og:image" content={ogImageUrl} />
|
||||
<meta property="og:image:width" content="1200" />
|
||||
<meta property="og:image:height" content="630" />
|
||||
<meta property="og:locale" content={SITE.locale} />
|
||||
{lang === 'zh' && <meta property="og:locale:alternate" content="en_US" />}
|
||||
<meta property="og:locale" content={isZh ? 'zh_CN' : SITE.locale} />
|
||||
<meta property="og:locale:alternate" content={isZh ? 'en_US' : 'zh_CN'} />
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
@@ -128,6 +128,15 @@ const nav = isZh
|
||||
email: SITE.email,
|
||||
sameAs: [SITE.linkedin, SITE.github, SITE.gitea, SITE.website].filter(Boolean),
|
||||
jobTitle: 'Full-stack Developer & DevOps Engineer',
|
||||
// The consultancy that does the client work — ties the blog's author node to
|
||||
// the business entity (and gives the hiring side a company reference).
|
||||
worksFor: {
|
||||
'@type': 'Organization',
|
||||
name: 'Hoelee Enterprise',
|
||||
url: SITE.website,
|
||||
},
|
||||
// TODO(image): `image` stays absent until the author photo exists — see
|
||||
// project-state §2 B4. A placeholder URL would be worse than no image.
|
||||
knowsAbout: [
|
||||
'Full-stack engineering', 'DevOps', 'Self-hosting',
|
||||
'Docker', 'WordPress', 'AI automation', 'Web3',
|
||||
@@ -163,9 +172,9 @@ const nav = isZh
|
||||
<header class="site-header">
|
||||
<nav class="nav" aria-label="Main">
|
||||
<a class="brand" href="/">Mr<span class="dot"> Hoelee</span></a>
|
||||
<a href={isZh ? '/zh/' : '/posts/'}>{nav.posts}</a>
|
||||
<a href={isZh ? '/zh/posts/' : '/posts/'}>{nav.posts}</a>
|
||||
<a href={isZh ? '/zh/categories/' : '/categories/'}>{nav.categories}</a>
|
||||
<a href={isZh ? '/zh/' : '/about/'}>{nav.about}</a>
|
||||
<a href={isZh ? '/zh/about/' : '/about/'}>{nav.about}</a>
|
||||
<a href="/rss.xml" title={nav.rss}>{nav.rss}</a>
|
||||
<button class="search-toggle" id="search-toggle" aria-label={isZh ? '搜索' : 'Search'}>⌕</button>
|
||||
<a class="lang-switch" href={resolvedSwitchHref} aria-label={isZh ? 'Switch to English' : '切换到中文'}>{switchLabel}</a>
|
||||
|
||||
Reference in new issue
Block a user