# SPDX-FileCopyrightText: 2026 Progmasoft # 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. server { listen 80 default_server; listen [::]:80 default_server; server_name tala-unmatched.invalid; server_tokens off; return 444; } server { listen 443 ssl default_server; listen [::]:443 ssl default_server; server_name _; server_tokens off; ssl_reject_handshake on; } server { listen 80; listen [::]:80; server_name tala.run www.tala.run talac.tala.run tazel.tala.run talafmt.tala.run talalint.tala.run; server_tokens off; 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; 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/. 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/. 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; 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/talafmt/robots.txt =404; } location = /sitemap.xml { try_files /hosts/talafmt/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/. 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 talalint.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/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/. 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 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 Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; # The two pages of the old site have their own pages on tazel.net; any # other page of its docs goes to the docs, everything else to the same path. location ~ "^/docs/(commands|project-file)/?$" { return 308 https://tazel.net/docs/reference/$1$is_args$args; } location /docs/ { return 308 https://tazel.net/docs; } location / { return 308 https://tazel.net$request_uri; } } 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; } # The former domain. Every path keeps working and lands on the same path of # tala.run. server { listen 80; listen [::]:80; server_name xsharp-lang.xyz www.xsharp-lang.xyz docs.xsharp-lang.xyz spec.xsharp-lang.xyz; server_tokens off; location ^~ /.well-known/acme-challenge/ { root /var/lib/letsencrypt; default_type text/plain; } location / { return 308 https://tala.run$request_uri; } } server { listen 443 ssl; listen [::]:443 ssl; http2 on; server_name xsharp-lang.xyz www.xsharp-lang.xyz docs.xsharp-lang.xyz spec.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://tala.run$request_uri; } # The registry moved to Progmasoft before the rename; its former address keeps # pointing there. tala.run has no ViGet host of its own. 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; 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; }