Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions deploy/nginx/check-config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,34 @@ answered GET /coupler 301 https://github.com/OpenIPC/coupler/
answered GET /wiki/some/deep/path 301 https://github.com/OpenIPC/wiki nginx
answered GET /binaries 410 - nginx
answered POST /binaries.json 410 - nginx
# An old `?locale=ru|zh` address goes to the page in that language, with the
# rest of its query (conf.d/openipc-locale-param.conf). Not when the address
# already names a language, not for English, not for a file, not for a write.
answered GET "/donate?locale=ru" 301 "$O/ru/donate" static
answered HEAD "/donate/?locale=zh" 301 "$O/zh/donate/" static
answered GET "/?locale=ru" 301 "$O/ru" static
answered GET "/?utm_source=x&locale=zh" 301 "$O/zh?utm_source=x" static
answered GET "/donate?locale=ru&utm_source=x" 301 "$O/ru/donate?utm_source=x" static
answered GET "/donate?a=1&locale=ru&b=2" 301 "$O/ru/donate?a=1&b=2" static
answered GET "/ru/donate?locale=ru" 200 - static
answered GET "/zh/donate?locale=ru" 404 - static
answered GET "/donate?locale=en" 200 - static
answered GET "/donate?locale=de" 200 - static
answered GET "/donate?locale=RU" 200 - static
answered GET "/favicon.png?locale=ru" 200 - static
# The route map answers its own addresses first, and the next hop localises.
answered GET "/community?locale=zh" 301 "$O/zh/community" static
# The addresses the engines actually hold, which the stub bundle does not:
# the redirect turns on the route map, not on the files.
answered GET "/cameras/vendors/sigmastar/socs/ssc30kq?locale=ru" 301 "$O/ru/cameras/vendors/sigmastar/socs/ssc30kq" static
answered GET "/cameras/vendors/goke?locale=zh" 301 "$O/zh/cameras/vendors/goke" static
answered GET "/tools/high-resolution-timer?locale=ru" 301 "$O/ru/tools/high-resolution-timer" static
answered GET "/low-latency?locale=ru" 301 "$O/ru/low-latency" static
answered GET "/cameras/boards?locale=ru" 301 "$O/ru/cameras/boards" static
answered POST "/donate?locale=ru" 405 - static
# Percent-encoded paths and repeated locales are left as they were (Qodo on #409).
answered GET "/%72u/donate?locale=zh" 200 - static
answered GET "/donate?locale=ru&locale=zh" 200 - static
answered GET /telemetry/anything 410 - nginx
answered GET /zh/merchandise 410 - nginx
answered GET /admin/snapshots 410 - nginx
Expand Down
70 changes: 70 additions & 0 deletions deploy/nginx/conf.d/openipc-locale-param.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# `?locale=ru` and `?locale=zh` on a page, sent to the page in that language.
#
# The Rails site named the language in a parameter, and the search engines
# still hold those addresses: on 2026-10-08 Google had 110 of openipc.org's
# 671 URLs with impressions carrying a query string, and
# /cameras/vendors/sigmastar/socs/ssc30kq?locale=ru alone earned 35 clicks in
# four weeks. The bundle ignores the parameter, so every one of those readers
# got the English page, and its canonical told the engine the English page
# was the one to keep. The home page's script has always turned `/?locale=ru`
# into `/ru` (frontend/apps/site/src/pages/index.astro); this does the same
# for every page, before a byte of the wrong language is sent.
#
# Only a read, only a language the site publishes, only an address without a
# language of its own, and only a page: a name with a dot is a file. Anything
# else on the query string goes along. Behind openipc.ru the Location is
# rewritten by the mirror like every other redirect, so a reader there stays
# there.
#
# Built from $request_uri and $args, never $uri: $uri is decoded, and a
# decoded %0d%0a in a Location header is a header of the requester's choosing.
#
# The Open Wall's own `?locale=` is conf.d/openipc-wall-shell.conf's, in
# locations of its own; this is applied in the seam's `location /` only.

# The path to localise: "/" for the home page, the path for any other page,
# and empty for an address that already names its language, is a file, or is
# percent-encoded. The route map classifies the decoded $uri, and /%72u/donate
# is /ru/donate to it; a raw path like that left alone is answered as it was.
# Regexes are tried in order, so the home page is decided first.
map $request_uri $openipc_lp_path {
default "";
"~^/(?:\?.*)?$" "/";
"~^/(?:ru|zh)(?:[/?]|$)" "";
"~^[^?]*\." "";
"~^[^?]*%" "";
"~^(?<openipc_lp_p>/[^?]*)" $openipc_lp_p;
Comment thread
qodo-free-for-open-source-projects[bot] marked this conversation as resolved.
}

# The query string without `locale`, with its `?`, or nothing at all.
map $args $openipc_lp_args {
default "?$args";
"" "";
"~^locale=[^&]*$" "";
"~^locale=[^&]*&(?<openipc_lp_rest>.+)$" "?$openipc_lp_rest";
"~^(?<openipc_lp_pre>.*?)&locale=[^&]*(?<openipc_lp_post>&.*)?$" "?$openipc_lp_pre$openipc_lp_post";
Comment thread
qodo-free-for-open-source-projects[bot] marked this conversation as resolved.
}

# Only where the route map (conf.d/openipc-redirects.conf) has nothing of its
# own to say: a page, or an address nothing claims. An address it redirects or
# retires is answered by it first, and a `?locale=` the redirect carries along
# is honoured on the next request -- /about?locale=zh goes to
# /community?locale=zh and from there to /zh/community.
map $openipc_route_action $openipc_lp_routable {
default "";
page 1;
catchall 1;
}

# One `locale` only. $arg_locale is the first of several, and the others would
# ride along on the localised address with nothing left to remove them.
map $args $openipc_lp_once {
default 1;
"~(?:^|&)locale=[^&]*&(?:.*&)?locale=" "";
}

map "$request_method:$openipc_lp_routable$openipc_lp_once:$arg_locale:$openipc_lp_path" $openipc_locale_param_target {
default "";
"~^(?:GET|HEAD):11:(?<openipc_lp_l>ru|zh):/$" "/$openipc_lp_l$openipc_lp_args";
"~^(?:GET|HEAD):11:(?<openipc_lp_l>ru|zh):(?<openipc_lp_q>/.+)$" "/$openipc_lp_l$openipc_lp_q$openipc_lp_args";
}
4 changes: 4 additions & 0 deletions deploy/nginx/sites-available/org.openipc
Original file line number Diff line number Diff line change
Expand Up @@ -1046,6 +1046,10 @@ server {
limit_conn site_conc 10;
limit_conn_status 429;

# An old `?locale=ru|zh` address goes to the page in that language
# (conf.d/openipc-locale-param.conf).
if ($openipc_locale_param_target) { return 301 $openipc_locale_param_target; }

root /srv/www/static/prod/current;
try_files $uri $uri/index.html @fallback;

Expand Down
4 changes: 4 additions & 0 deletions deploy/nginx/sites-available/org.openipc.dev
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,10 @@ server {
}

location / {
# An old `?locale=ru|zh` address goes to the page in that language
# (conf.d/openipc-locale-param.conf).
if ($openipc_locale_param_target) { return 301 $openipc_locale_param_target; }

root /srv/www/static/dev/current;
try_files $uri $uri/index.html @fallback;

Expand Down
Loading