diff options
| author | Leitwolf11 | 2026-11-10 03:15:05 +0300 |
|---|---|---|
| committer | Leitwolf11 | 2026-11-10 03:15:05 +0300 |
| commit | 5b1cb02c51b0b9cc65371d6f557343292aeb2326 (patch) | |
| tree | 0d74d23266dcd3def8c191e0721239c38731da88 | |
| parent | cc6ca15df51dea156cac1ea697fb620e9b6f08ca (diff) | |
| download | website-ops/tala-run-unavailable.tar.gz | |
Close tala.run: every page leads to the maintenance noticeops/tala-run-unavailable
The Tala language and its tools are no longer developed as of 2026-11-10;
Progmasoft puts its work into Tazel, now a build system for C, C++,
Objective-C, Objective-C++ and Zig. tala.run is prepared for OpenTala, a
kernel, and TalaOS.
- ops/nginx/tala.conf and forum.conf: every page of tala.run, www.tala.run,
talac.tala.run, talafmt.tala.run, talalint.tala.run and forum.tala.run
answers 302 to https://tala.run/unavailable?reason=maintenance. 302, not
308, so neither browsers nor Cloudflare keep the redirect once the domain
serves other pages.
- /unavailable answers 503 with Retry-After, X-Robots-Tag noindex and a
strict policy; its body is ops/maintenance/unavailable.html, a static page
in English, German, Russian and Hebrew that names OpenTala and TalaOS.
- ACME on port 80, tazel.tala.run (to tazel.net), the former domain's
redirects and viget.xsharp-lang.xyz (to viget.progmasoft.com) keep
working. ops/nginx/tala-maintenance.conf, the 503 vhost it replaces, is
removed.
- README and Documents/OPERATIONS.md say so; the site tests check the
redirects, the notice and its four languages instead of the served routes.
Installed on the first server before this PR (previous files in
/root/tala-run-before-unavailable); every host checked from outside.
| -rw-r--r-- | Documents/OPERATIONS.md | 52 | ||||
| -rw-r--r-- | README.md | 12 | ||||
| -rw-r--r-- | frontend/tests/site-integrity.test.mjs | 117 | ||||
| -rw-r--r-- | ops/maintenance/unavailable.html | 89 | ||||
| -rw-r--r-- | ops/nginx/forum.conf | 14 | ||||
| -rw-r--r-- | ops/nginx/tala-maintenance.conf | 72 | ||||
| -rw-r--r-- | ops/nginx/tala.conf | 274 |
7 files changed, 202 insertions, 428 deletions
diff --git a/Documents/OPERATIONS.md b/Documents/OPERATIONS.md index cf4db71..1a17a90 100644 --- a/Documents/OPERATIONS.md +++ b/Documents/OPERATIONS.md @@ -26,9 +26,10 @@ compatibility, but it does not make package functions part of this website. tala.run has no ViGet host; the registry lives at `viget.progmasoft.com`. -The sites are served with `ops/nginx/tala.conf`. While it is switched to -`ops/nginx/tala-maintenance.conf`, the routes of the three sites answer 503 and -`/api/v1/site` is not exposed. One certificate, `/etc/letsencrypt/live/tala.run/`, +The sites are closed (2026-11-10): `ops/nginx/tala.conf` and `ops/nginx/forum.conf` answer every page of +tala.run, www.tala.run, talac.tala.run, talafmt.tala.run, talalint.tala.run and forum.tala.run with a 302 to +`https://tala.run/unavailable?reason=maintenance`, which answers 503 with `ops/maintenance/unavailable.html` +(see Maintenance mode). `/api/v1/site` is not exposed. One certificate, `/etc/letsencrypt/live/tala.run/`, covers tala.run, www.tala.run, talac.tala.run, tazel.tala.run and forum.tala.run; the former domain keeps its own certificates for its redirects. @@ -179,35 +180,22 @@ on the server itself before concluding that a release failed. ## Maintenance mode -`ops/nginx/tala-maintenance.conf` answers the three sites with 503 and keeps -the legacy redirect working. `ops/nginx/tala.conf` serves them. Keep the -two mutually exclusive in the live Nginx include directory. Building the Vue -bundle or deploying the forum does not by itself authorize switching between -them. - -Before switching the main site from maintenance to public: - -1. Review the copy in every published language against the public language - Spec and current compiler behavior. -2. Confirm the homepage actually answers why the language exists and does - not describe planned compiler work as a finished feature. -3. Verify the three route bodies, both themes, keyboard focus, and responsive - widths in a real browser. -4. Confirm all GitHub destinations and the forum link respond correctly. -5. Run both build/test sets shown above. -6. Install the Vue `dist/` contents at the static root named in the Nginx - config, preserving file permissions and SELinux labels. -7. Test the published API on loopback with the shared ASP.NET Core 10 runtime - before replacing the running API service. -8. Confirm the old service's unrelated status function has moved to the - correct owner before retiring the old process. -9. Make one explicit Nginx configuration switch, run `nginx -t`, and reload. -10. Check the public routes and headers again from outside the server. - -The API service is not required for the static homepage render. If it is -not ready, do not pretend it is ready by rewriting the API path. Delay the -rollout or explicitly publish static pages without the API after reviewing -the impact of that decision. +tala.run is closed while the domain is prepared for OpenTala, a kernel, and TalaOS; the Tala language and its tools +are no longer developed (2026-11-10). + +- Every page of tala.run, www.tala.run, talac.tala.run, talafmt.tala.run, talalint.tala.run and forum.tala.run + answers `302` to `https://tala.run/unavailable?reason=maintenance`. The redirect is temporary on purpose, so that + neither browsers nor Cloudflare keep it once the domain serves other pages. +- `https://tala.run/unavailable` answers `503` with `Retry-After`, `noindex` and a strict policy, its body being + `ops/maintenance/unavailable.html`, installed as `/usr/share/nginx/html/maintenance/tala-unavailable.html` + (`restorecon` after copying). +- ACME challenges on port 80 still answer, so the `tala.run` certificate renews. +- `tazel.tala.run` keeps leading to tazel.net, and the former domain keeps redirecting to tala.run, from where it + reaches the notice. + +The frontend release under `/srv/xsharp/website/current` and the `tala-site-api` service stay on the server but are +not reachable. Opening a site on the domain again replaces `ops/nginx/tala.conf` and `ops/nginx/forum.conf`; run +`nginx -t`, reload, and check every host from outside. ## Legacy redirect during maintenance @@ -5,6 +5,13 @@ SPDX-License-Identifier: AGPL-3.0-or-later WITH AdditionRef-Progmasoft-Patent-Gr # Tala website +> [!IMPORTANT] +> The Tala language and its tools (Talac, talafmt, talalint, tala-analyzer) are no longer developed as of 2026-11-10. +> Progmasoft puts its work into [Tazel](https://tazel.net), now a build system for C, C++, Objective-C, +> Objective-C++ and Zig. tala.run is closed for maintenance: every page and subdomain leads to +> `https://tala.run/unavailable?reason=maintenance` while the domain is prepared for OpenTala, a kernel, and TalaOS. +> The site below is kept for reference. + This repository owns the public language website at [tala.run](https://tala.run) and the documentation of the compiler at [talac.tala.run](https://talac.tala.run). The build system has its own site, [tazel.net](https://tazel.net). It does not own @@ -27,9 +34,8 @@ One frontend build serves three sites and picks its pages from the host name: Every path of the former domain, `xsharp-lang.xyz`, redirects permanently to the same path of `tala.run`. tala.run has no ViGet host; the registry lives at `viget.progmasoft.com`. -The sites are public and served with `ops/nginx/tala.conf`. `ops/nginx/tala-maintenance.conf` remains in the -repository as the configuration to fall back to when the main domain has to be taken offline. The forum page is -deployed independently of the main site. See the [operations runbook](Documents/OPERATIONS.md) for the route and +The sites are closed: `ops/nginx/tala.conf` and `ops/nginx/forum.conf` send every page to +`https://tala.run/unavailable?reason=maintenance`, a page of its own (`ops/maintenance/unavailable.html`). See the [operations runbook](Documents/OPERATIONS.md) for the route and release boundaries. ## Documentation diff --git a/frontend/tests/site-integrity.test.mjs b/frontend/tests/site-integrity.test.mjs index ba131f0..68fedf1 100644 --- a/frontend/tests/site-integrity.test.mjs +++ b/frontend/tests/site-integrity.test.mjs @@ -62,13 +62,9 @@ test("every site publishes exactly its own pages in its sitemap", () => { test("the forum placeholder is explicitly non-indexable and not an account service", () => { const forum = readFileSync(join(websiteRoot, "forum/index.html"), "utf8"); - const nginx = readFileSync(join(websiteRoot, "ops/nginx/forum.conf"), "utf8"); assert.match(forum, /name="robots" content="noindex, nofollow"/); assert.match(forum, /There are no accounts,/); assert.match(forum, /posts, or discussion service/); - assert.match(nginx, /X-Robots-Tag "noindex, nofollow"/); - assert.match(nginx, /script-src 'self'; style-src 'self'/); - assert.doesNotMatch(nginx, /unsafe-inline/); assert.match(forum, /src="\/site\.js[?"]/); assert.match(forum, /href="\/site\.css[?"]/); const normalizedForum = forum.toLowerCase(); @@ -155,52 +151,60 @@ test("the site examples are copied from the compiler repository when available", assert.ok(guide.includes(program("HelloWorld")), "the guide diverged from the compiler example"); }); -test("maintenance mode preserves the legacy redirect without opening the language site", () => { - const maintenance = readFileSync(join(websiteRoot, "ops/nginx/tala-maintenance.conf"), "utf8"); - const live = readFileSync(join(websiteRoot, "ops/nginx/tala.conf"), "utf8"); +test("every page of tala.run and its subdomains leads to the notice", () => { + const live = readFileSync(join(websiteRoot, "ops/nginx/tala.conf"), "utf8").replaceAll( + "\r\n", + "\n", + ); + const forum = readFileSync(join(websiteRoot, "ops/nginx/forum.conf"), "utf8").replaceAll( + "\r\n", + "\n", + ); + const notice = "https://tala.run/unavailable?reason=maintenance"; + const target = notice.replaceAll(".", "\\.").replaceAll("?", "\\?").replaceAll("/", "\\/"); + // tala.run answers the notice itself with 503 and sends every other path to it, temporarily. + assert.match(live, /server_name tala\.run;[^]*?location = \/unavailable \{\s*return 503;/); + assert.match(live, /error_page 503 \/tala-unavailable\.html;/); + assert.match(live, /alias \/usr\/share\/nginx\/html\/maintenance\/tala-unavailable\.html;/); + assert.match(live, /add_header Retry-After "\d+" always;/); + assert.match(live, /add_header X-Robots-Tag "noindex, nofollow" always;/); + assert.match(live, new RegExp(`location / \\{\\s*return 302 ${target};`)); assert.match( - maintenance, - /server_name tala\.run www\.tala\.run talac\.tala\.run tazel\.tala\.run;/, + live, + new RegExp( + `server_name www\\.tala\\.run talac\\.tala\\.run talafmt\\.tala\\.run talalint\\.tala\\.run;[^}]*return 302 ${target};`, + ), + ); + assert.match( + forum, + new RegExp( + `server_name forum\\.tala\\.run;\\n server_tokens off;[^}]*return 302 ${target};`, + ), + ); + assert.doesNotMatch(live + forum, /return 30[178] https:\/\/tala\.run\/unavailable/); + // The pages of the closed site are no longer served from these hosts. + assert.doesNotMatch(live + forum, /root \/srv\/xsharp\/website\/current/); + // The registry's former address keeps its redirect. + assert.match( + live, + /server_name viget\.xsharp-lang\.xyz;[^}]*return 308 https:\/\/viget\.progmasoft\.com\$request_uri;/, + ); + // ACME still answers on port 80, so the certificate renews. + assert.match( + live, + /location \^~ \/\.well-known\/acme-challenge\/ \{\s*root \/var\/lib\/letsencrypt;/, ); - assert.match(maintenance, /location \/ \{ return 503; \}/); - assert.match(maintenance, /server_name viget\.xsharp-lang\.xyz/); - assert.match(maintenance, /return 308 https:\/\/viget\.progmasoft\.com\$request_uri/); - assert.match(live, /server_name viget\.xsharp-lang\.xyz/); - assert.match(live, /location = \/api\/v1\/site/); - assert.match(live, /location \^~ \/api\/ \{\s*return 404;/); }); -test("only the routes of the application get the app shell; other paths answer 404", () => { - const live = readFileSync(join(websiteRoot, "ops/nginx/tala.conf"), "utf8"); - assert.doesNotMatch(live, /try_files \$uri \$uri\/ \/index\.html;/); - assert.equal(live.match(/try_files \$uri \$uri\/ @application;/g)?.length, 4); - assert.equal(live.match(/error_page 404 \/index\.html;/g)?.length, 4); - const patterns = [...live.matchAll(/if \(\$uri !~ "([^"]+)"\)/g)].map((match) => match[1]); - assert.equal(new Set(patterns).size, 1, "every site must accept the same routes"); - const route = new RegExp(patterns[0]); - const pages = [ - "public/sitemap.xml", - "public/hosts/talac/sitemap.xml", - "public/hosts/talafmt/sitemap.xml", - "public/hosts/talalint/sitemap.xml", - ] - .flatMap(locations) - .map((url) => new URL(url).pathname); - assert.ok(pages.length > 3); - for (const path of pages) { - assert.match(path, route, `${path} is in a sitemap but would answer 404`); - } - for (const path of [ - "/wp-login.php", - "/wp-admin/install.php", - "/docs", - "/docs/", - "/docs/a/b", - "/.env", - "/a", - ]) { - assert.doesNotMatch(path, route, `${path} would be served as a page`); +test("the notice is a page of its own that names what comes to tala.run", () => { + const page = readFileSync(join(websiteRoot, "ops/maintenance/unavailable.html"), "utf8"); + assert.match(page, /<meta name="robots" content="noindex, nofollow" \/>/); + assert.doesNotMatch(page, /<script\b/); + for (const language of ["en", "de", "ru", "he"]) { + assert.match(page, new RegExp(`<section lang="${language}"`)); } + assert.equal(page.split("OpenTala").length - 1, 4, "every language names OpenTala"); + assert.equal(page.split("TalaOS").length - 1, 4, "every language names TalaOS"); }); test("the former domain lands on the same path of tala.run and tala.run has no ViGet host", () => { @@ -211,18 +215,10 @@ test("the former domain lands on the same path of tala.run and tala.run has no V /server_name xsharp-lang\.xyz www\.xsharp-lang\.xyz docs\.xsharp-lang\.xyz spec\.xsharp-lang\.xyz;[^}]*return 308 https:\/\/tala\.run\$request_uri;/s, ); assert.match( - live, - /server_name www\.tala\.run;[^}]*return 308 https:\/\/tala\.run\$request_uri;/s, - ); - assert.match( forum, /server_name forum\.xsharp-lang\.xyz;[^}]*return 308 https:\/\/forum\.tala\.run\$request_uri;/s, ); assert.doesNotMatch(live + forum, /viget\.tala\.run/); - for (const host of ["talac", "talafmt", "talalint"]) { - assert.match(live, new RegExp(`try_files /hosts/${host}/robots\\.txt =404;`)); - assert.match(live, new RegExp(`try_files /hosts/${host}/sitemap\\.xml =404;`)); - } }); test("tazel.tala.run only redirects to tazel.net, its two pages to their own", () => { @@ -303,17 +299,8 @@ test("the production API binds to loopback and matches its Nginx proxy port", () assert.ok(service.includes("Environment=PORT=5086")); assert.ok(service.includes("ExecStart=/usr/bin/dotnet ")); assert.doesNotMatch(service, /java/i); - assert.ok(nginx.includes("proxy_pass http://127.0.0.1:5086/api/v1/site;")); -}); - -test("the forum assets are allowed by its restrictive Nginx policy", () => { - const config = readFileSync(join(websiteRoot, "ops/nginx/forum.conf"), "utf8"); - const forum = readFileSync(join(websiteRoot, "forum/index.html"), "utf8"); - for (const filename of ["site.css", "site.js", "tala-mark.svg"]) { - assert.ok(existsSync(join(websiteRoot, "forum", filename)), `${filename} missing`); - assert.ok(config.includes(`location = /${filename}`), `${filename} blocked by Nginx`); - assert.ok(forum.includes(`/${filename}`), `${filename} not referenced by forum`); - } + // tala.run is closed, so Nginx does not expose the API. + assert.doesNotMatch(nginx, /proxy_pass/); }); test("navigation, router, and sitemap agree on the public language pages", () => { @@ -376,7 +363,7 @@ test("the former domain is left to the server: the page carries no notice about }); test("every tala.run host behaves as if HSTS were preloaded for its top-level domain", () => { - for (const file of ["tala.conf", "forum.conf", "tala-maintenance.conf"]) { + for (const file of ["tala.conf", "forum.conf"]) { const config = readFileSync(join(websiteRoot, "ops/nginx", file), "utf8"); const blocks = config.split(/\nserver \{/).slice(1); for (const block of blocks) { diff --git a/ops/maintenance/unavailable.html b/ops/maintenance/unavailable.html new file mode 100644 index 0000000..35c138a --- /dev/null +++ b/ops/maintenance/unavailable.html @@ -0,0 +1,89 @@ +<!doctype html> +<!-- SPDX-FileCopyrightText: 2026 Progmasoft <support@progmasoft.com> --> +<!-- SPDX-License-Identifier: AGPL-3.0-or-later WITH AdditionRef-Progmasoft-Patent-Grant-1.1 --> +<!-- Installed as /usr/share/nginx/html/maintenance/tala-unavailable.html; see ops/nginx/tala.conf. --> +<html lang="en"> + <head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1" /> + <meta name="robots" content="noindex, nofollow" /> + <title>tala.run is unavailable</title> + <style> + :root { + color-scheme: light dark; + --background: #f6f8f9; + --surface: #ffffff; + --ink: #13222a; + --muted: #4d5f68; + --line: #d9e1e5; + } + @media (prefers-color-scheme: dark) { + :root { + --background: #0c171d; + --surface: #13222a; + --ink: #e6eef1; + --muted: #9db0b8; + --line: #24363f; + } + } + * { + box-sizing: border-box; + } + body { + margin: 0; + min-height: 100vh; + display: grid; + place-items: center; + padding: 24px 16px; + background: var(--background); + color: var(--ink); + font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; + line-height: 1.55; + } + main { + width: 100%; + max-width: 640px; + display: grid; + gap: 16px; + } + section { + padding: 20px 24px; + border: 1px solid var(--line); + border-radius: 12px; + background: var(--surface); + } + h1 { + margin: 0 0 6px; + font-size: 1.25rem; + } + p { + margin: 0; + color: var(--muted); + } + a { + color: inherit; + } + </style> + </head> + <body> + <main> + <section lang="en"> + <h1>tala.run is unavailable</h1> + <p>The site is closed for maintenance. It is being prepared for OpenTala, a kernel, and TalaOS; its pages lead here until then.</p> + </section> + <section lang="de"> + <h1>tala.run ist nicht erreichbar</h1> + <p>Die Website ist wegen Wartung geschlossen. Sie wird für OpenTala, einen Kernel, und TalaOS vorbereitet; bis dahin führen ihre Seiten hierher.</p> + </section> + <section lang="ru"> + <h1>tala.run недоступен</h1> + <p>Сайт закрыт на обслуживание. Он готовится для OpenTala — ядра — и TalaOS; до тех пор его страницы ведут сюда.</p> + </section> + <section lang="he" dir="rtl"> + <h1>tala.run אינו זמין</h1> + <p>האתר סגור לתחזוקה. הוא מוכן עבור OpenTala, ליבת מערכת הפעלה, ועבור TalaOS; עד אז הדפים שלו מובילים לכאן.</p> + </section> + <p><a href="https://progmasoft.com/">Progmasoft</a></p> + </main> + </body> +</html> diff --git a/ops/nginx/forum.conf b/ops/nginx/forum.conf index 5ae383c..bae046b 100644 --- a/ops/nginx/forum.conf +++ b/ops/nginx/forum.conf @@ -19,8 +19,6 @@ server { listen [::]:443 ssl; http2 on; server_name forum.tala.run; - root /srv/xsharp/website/current/forum; - index index.html; server_tokens off; ssl_certificate /etc/letsencrypt/live/tala.run/fullchain.pem; @@ -28,18 +26,10 @@ server { include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; - add_header X-Robots-Tag "noindex, nofollow" always; add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; - add_header X-Content-Type-Options "nosniff" always; - add_header Referrer-Policy "strict-origin-when-cross-origin" always; - add_header Content-Security-Policy "default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; base-uri 'none'; frame-ancestors 'none'; form-action 'none'" always; - location = / { try_files /index.html =404; } - location = /tala.svg { try_files $uri =404; } - location = /tala-mark.svg { try_files $uri =404; } - location = /site.css { try_files $uri =404; } - location = /site.js { try_files $uri =404; } - location / { return 404; } + # tala.run is closed; see tala.conf. + return 302 https://tala.run/unavailable?reason=maintenance; } # The former address of the same page. diff --git a/ops/nginx/tala-maintenance.conf b/ops/nginx/tala-maintenance.conf deleted file mode 100644 index 35e78d9..0000000 --- a/ops/nginx/tala-maintenance.conf +++ /dev/null @@ -1,72 +0,0 @@ -# SPDX-FileCopyrightText: 2026 Progmasoft <support@progmasoft.com> -# SPDX-License-Identifier: AGPL-3.0-or-later WITH AdditionRef-Progmasoft-Patent-Grant-1.1 - -# The language pages stay closed while this file is active. Keep the retired -# ViGet hostname working as a redirect; it is not a website API or page. -server { - listen 80; - listen [::]:80; - server_name tala.run www.tala.run talac.tala.run tazel.tala.run; - - location ^~ /.well-known/acme-challenge/ { - root /var/lib/letsencrypt; - default_type text/plain; - } - location / { return 308 https://$host$request_uri; } -} - -server { - listen 443 ssl; - listen [::]:443 ssl; - http2 on; - server_name tala.run www.tala.run talac.tala.run tazel.tala.run; - server_tokens off; - - ssl_certificate /etc/letsencrypt/live/tala.run/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/tala.run/privkey.pem; - include /etc/letsencrypt/options-ssl-nginx.conf; - ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; - - add_header Retry-After "3600" always; - add_header Cache-Control "no-store" always; - add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; - add_header X-Content-Type-Options "nosniff" always; - add_header X-Frame-Options "DENY" always; - add_header Content-Security-Policy "default-src 'none'; style-src 'unsafe-inline'; base-uri 'none'; frame-ancestors 'none'" always; - - error_page 503 /maintenance.html; - location = /maintenance.html { - internal; - alias /usr/share/nginx/html/maintenance/xsharp.html; - } - location / { return 503; } -} - -server { - listen 80; - listen [::]:80; - server_name viget.xsharp-lang.xyz; - server_tokens off; - - location ^~ /.well-known/acme-challenge/ { - root /var/lib/letsencrypt; - default_type text/plain; - } - location / { return 308 https://viget.progmasoft.com$request_uri; } -} - -server { - listen 443 ssl; - listen [::]:443 ssl; - http2 on; - server_name viget.xsharp-lang.xyz; - server_tokens off; - - ssl_certificate /etc/letsencrypt/live/xsharp-lang.xyz/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/xsharp-lang.xyz/privkey.pem; - include /etc/letsencrypt/options-ssl-nginx.conf; - ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; - - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; - return 308 https://viget.progmasoft.com$request_uri; -} diff --git a/ops/nginx/tala.conf b/ops/nginx/tala.conf index a8164ff..f7aa02a 100644 --- a/ops/nginx/tala.conf +++ b/ops/nginx/tala.conf @@ -1,13 +1,15 @@ # SPDX-FileCopyrightText: 2026 Progmasoft <support@progmasoft.com> # SPDX-License-Identifier: AGPL-3.0-or-later WITH AdditionRef-Progmasoft-Patent-Grant-1.1 -# One frontend build serves four sites: tala.run for the language, -# talac.tala.run for the compiler, talafmt.tala.run for the formatter and -# talalint.tala.run for the linter. The page picks its content from the host -# name. xsharp-lang.xyz, the former domain, answers with a permanent redirect to -# the same path on tala.run. tazel.tala.run, where the build system was -# documented, answers with a permanent redirect to tazel.net, its own site. -# The policies allow Cloudflare Web Analytics, which Cloudflare adds to each page. +# tala.run is closed. Every page of tala.run, www.tala.run, talac.tala.run, +# talafmt.tala.run and talalint.tala.run (and forum.tala.run, in forum.conf) +# leads with a temporary redirect to https://tala.run/unavailable?reason=maintenance, +# which answers 503 with a page of its own. The redirect is 302, not 308: the +# domain will serve other pages later, so neither browsers nor Cloudflare may +# keep it. ACME challenges on port 80 still work, so the certificates renew. +# xsharp-lang.xyz, the former domain, still redirects to tala.run, and from +# there to the notice. tazel.tala.run keeps leading to tazel.net, the site of +# Tazel, which goes on. server { listen 80 default_server; @@ -48,146 +50,6 @@ server { listen [::]:443 ssl; http2 on; server_name tala.run; - - root /srv/xsharp/website/current/frontend; - index index.html; - server_tokens off; - - ssl_certificate /etc/letsencrypt/live/tala.run/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/tala.run/privkey.pem; - include /etc/letsencrypt/options-ssl-nginx.conf; - ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; - - add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://static.cloudflareinsights.com; connect-src 'self' https://cloudflareinsights.com; img-src 'self' data:; base-uri 'self'; form-action 'self'; frame-ancestors 'none'; object-src 'none'" always; - add_header Referrer-Policy "strict-origin-when-cross-origin" always; - add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; - add_header X-Content-Type-Options "nosniff" always; - add_header X-Frame-Options "DENY" always; - - # Keep retired registry paths closed on the language host. Accounts and - # packages belong to separate Progmasoft services, not this Vue artifact. - location = /repo { - return 404; - } - - location ^~ /repo/ { - return 404; - } - - # Only the language site's own public metadata crosses into the API. - # A catch-all /api proxy would accidentally expose legacy registry routes. - location = /api/v1/site { - proxy_pass http://127.0.0.1:5086/api/v1/site; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Real-IP $remote_addr; - proxy_connect_timeout 2s; - proxy_read_timeout 5s; - } - - location ^~ /api/ { - return 404; - } - - # The robots and sitemap files of the two documentation hosts. - location ^~ /hosts/ { - return 404; - } - - location / { - # Vue Router uses history URLs; real files still win before the app shell. - try_files $uri $uri/ @application; - } - - # The application has two kinds of routes: the landing page and - # /docs/<page>. Any other path that is not a file is answered with 404, so - # that unknown addresses, including the probes for /wp-login.php and - # friends, are not served as pages. The body of the 404 is still the - # application, whose router takes a visitor to the landing page. - location @application { - if ($uri !~ "^/(docs/[a-z0-9-]+/?)?$") { - return 404; - } - rewrite ^ /index.html break; - } - - error_page 404 /index.html; - - location ~ /\. { - deny all; - } -} - -# talac.tala.run, talafmt.tala.run and talalint.tala.run serve -# the same build; each answers for robots.txt and sitemap.xml with its own file. -server { - listen 443 ssl; - listen [::]:443 ssl; - http2 on; - server_name talac.tala.run; - - root /srv/xsharp/website/current/frontend; - index index.html; - server_tokens off; - - ssl_certificate /etc/letsencrypt/live/tala.run/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/tala.run/privkey.pem; - include /etc/letsencrypt/options-ssl-nginx.conf; - ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; - - add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://static.cloudflareinsights.com; connect-src 'self' https://cloudflareinsights.com; img-src 'self' data:; base-uri 'self'; form-action 'self'; frame-ancestors 'none'; object-src 'none'" always; - add_header Referrer-Policy "strict-origin-when-cross-origin" always; - add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; - add_header X-Content-Type-Options "nosniff" always; - add_header X-Frame-Options "DENY" always; - - location = /robots.txt { - try_files /hosts/talac/robots.txt =404; - } - - location = /sitemap.xml { - try_files /hosts/talac/sitemap.xml =404; - } - - location ^~ /hosts/ { - return 404; - } - - location ^~ /api/ { - return 404; - } - - location / { - try_files $uri $uri/ @application; - } - - # The application has two kinds of routes: the landing page and - # /docs/<page>. Any other path that is not a file is answered with 404, so - # that unknown addresses, including the probes for /wp-login.php and - # friends, are not served as pages. The body of the 404 is still the - # application, whose router takes a visitor to the landing page. - location @application { - if ($uri !~ "^/(docs/[a-z0-9-]+/?)?$") { - return 404; - } - rewrite ^ /index.html break; - } - - error_page 404 /index.html; - - location ~ /\. { - deny all; - } -} - -server { - listen 443 ssl; - listen [::]:443 ssl; - http2 on; - server_name talafmt.tala.run; - - root /srv/xsharp/website/current/frontend; - index index.html; server_tokens off; ssl_certificate /etc/letsencrypt/live/tala.run/fullchain.pem; @@ -195,48 +57,32 @@ server { include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; - add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://static.cloudflareinsights.com; connect-src 'self' https://cloudflareinsights.com; img-src 'self' data:; base-uri 'self'; form-action 'self'; frame-ancestors 'none'; object-src 'none'" always; - add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; add_header X-Content-Type-Options "nosniff" always; - add_header X-Frame-Options "DENY" always; - location = /robots.txt { - try_files /hosts/talafmt/robots.txt =404; + # The notice itself. 503 with Retry-After tells crawlers the closure is + # temporary and keeps the page out of their index. + location = /unavailable { + return 503; } - location = /sitemap.xml { - try_files /hosts/talafmt/sitemap.xml =404; - } - - location ^~ /hosts/ { - return 404; - } - - location ^~ /api/ { - return 404; + error_page 503 /tala-unavailable.html; + location = /tala-unavailable.html { + internal; + alias /usr/share/nginx/html/maintenance/tala-unavailable.html; + default_type text/html; + add_header Retry-After "86400" always; + add_header Cache-Control "no-store" always; + add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-Frame-Options "DENY" always; + add_header X-Robots-Tag "noindex, nofollow" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + add_header Content-Security-Policy "default-src 'none'; style-src 'unsafe-inline'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'" always; } location / { - try_files $uri $uri/ @application; - } - - # The application has two kinds of routes: the landing page and - # /docs/<page>. Any other path that is not a file is answered with 404, so - # that unknown addresses, including the probes for /wp-login.php and - # friends, are not served as pages. The body of the 404 is still the - # application, whose router takes a visitor to the landing page. - location @application { - if ($uri !~ "^/(docs/[a-z0-9-]+/?)?$") { - return 404; - } - rewrite ^ /index.html break; - } - - error_page 404 /index.html; - - location ~ /\. { - deny all; + return 302 https://tala.run/unavailable?reason=maintenance; } } @@ -244,10 +90,7 @@ server { listen 443 ssl; listen [::]:443 ssl; http2 on; - server_name talalint.tala.run; - - root /srv/xsharp/website/current/frontend; - index index.html; + server_name www.tala.run talac.tala.run talafmt.tala.run talalint.tala.run; server_tokens off; ssl_certificate /etc/letsencrypt/live/tala.run/fullchain.pem; @@ -255,49 +98,9 @@ server { include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; - add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://static.cloudflareinsights.com; connect-src 'self' https://cloudflareinsights.com; img-src 'self' data:; base-uri 'self'; form-action 'self'; frame-ancestors 'none'; object-src 'none'" always; - add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; - add_header X-Content-Type-Options "nosniff" always; - add_header X-Frame-Options "DENY" always; - - location = /robots.txt { - try_files /hosts/talalint/robots.txt =404; - } - - location = /sitemap.xml { - try_files /hosts/talalint/sitemap.xml =404; - } - - location ^~ /hosts/ { - return 404; - } - - location ^~ /api/ { - return 404; - } - - location / { - try_files $uri $uri/ @application; - } - - # The application has two kinds of routes: the landing page and - # /docs/<page>. Any other path that is not a file is answered with 404, so - # that unknown addresses, including the probes for /wp-login.php and - # friends, are not served as pages. The body of the 404 is still the - # application, whose router takes a visitor to the landing page. - location @application { - if ($uri !~ "^/(docs/[a-z0-9-]+/?)?$") { - return 404; - } - rewrite ^ /index.html break; - } - - error_page 404 /index.html; - location ~ /\. { - deny all; - } + return 302 https://tala.run/unavailable?reason=maintenance; } server { @@ -329,22 +132,6 @@ server { } } -server { - listen 443 ssl; - listen [::]:443 ssl; - http2 on; - server_name www.tala.run; - server_tokens off; - - ssl_certificate /etc/letsencrypt/live/tala.run/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/tala.run/privkey.pem; - include /etc/letsencrypt/options-ssl-nginx.conf; - ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; - - add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; - return 308 https://tala.run$request_uri; -} - |