Skip to content

Instantly share code, notes, and snippets.

@kLiHz
Last active May 11, 2024 03:08
Show Gist options
  • Save kLiHz/ac4d7f36c3c4172cd2440150af8499cb to your computer and use it in GitHub Desktop.
Save kLiHz/ac4d7f36c3c4172cd2440150af8499cb to your computer and use it in GitHub Desktop.
Reverse Proxying rustup.rs with Cloudflare Workers

Suppose your Worker's domain is $REVERSE_PROXIED_RUSTUP_DOMAIN (e.g. rustup.muc.moe).

Usage

Visit $REVERSE_PROXIED_RUSTUP_DOMAIN for the website rustup.rs.

And set these environment variables for rustup:

  • RUSTUP_DIST_SERVER: https://$REVERSE_PROXIED_RUSTUP_DOMAIN
  • RUSTUP_UPDATE_ROOT: https://$REVERSE_PROXIED_RUSTUP_DOMAIN/rustup

Bash:

REVERSE_PROXIED_RUSTUP_DOMAIN='rustup.muc.moe'
export RUSTUP_DIST_SERVER="https://$REVERSE_PROXIED_RUSTUP_DOMAIN"
export RUSTUP_UPDATE_ROOT="https://$REVERSE_PROXIED_RUSTUP_DOMAIN/rustup"

PowerShell:

$REVERSE_PROXIED_RUSTUP_DOMAIN='rustup.muc.moe'
$env:RUSTUP_DIST_SERVER="https://$REVERSE_PROXIED_RUSTUP_DOMAIN"
$env:RUSTUP_UPDATE_ROOT="https://$REVERSE_PROXIED_RUSTUP_DOMAIN/rustup"
/**
* Welcome to Cloudflare Workers! This is your first worker.
* Learn more at https://developers.cloudflare.com/workers/
*/
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
const method = request.method;
const headers = new Headers(request.headers);
const origin = url.origin;
const host = url.host;
headers.delete('Referrer');
headers.delete('Host');
const domainMapper = {
'https://sh.rustup.rs': '/sh',
'https://win.rustup.rs': '/win',
'https://rustup.rs': '/apex',
'https://www.rust-lang.org': '/org',
};
if (url.pathname == '/' || url.pathname == '/index.html') {
const pageResponse = await fetch('https://rustup.rs');
const html = await pageResponse.text();
const newBody = html
.replace(/(<\s*title[^>]*>)([^<]*)(<\/\s*title[^>]*>)/, '$1(A reverse proxied) $2 (Powered by Cloudflare Workers)$3')
.replaceAll(/https:\/\/(?:(?:sh\.|win\.)?rustup.rs|www\.rust-lang\.org)/g, (match) => origin + domainMapper[match])
.replaceAll(/((?:href|src)=")\/?(?!https:\/\/)([^"#]+)(")/g, '$1/apex/$2"')
;
const injectPos = newBody.indexOf('>', newBody.indexOf('<body'));
const headers = new Headers(pageResponse.headers);
const nonce = btoa(new TextDecoder('utf-16').decode(new Uint16Array(crypto.getRandomValues(new Uint8Array(32)))));
headers.set(
'Content-Security-Policy',
headers.get('Content-Security-Policy').replace('style-src', `style-src 'nonce-${nonce}'`)
);
return new Response(newBody.slice(0, injectPos + 1) + `
<div id="mirror-notes">
<style nonce="${nonce}">
#mirror-notes {font-size: medium; width: 80%; background-color: rgba(83, 153, 207, 0.5); padding: 30px;border-radius: 25px;}
#mirror-notes * {text-align: left;}
#mirror-notes pre {overflow: auto;}
</style>
<p><em>This is a (reverse proxied) mirror (powered by Cloudflare Workers) of the official <a href="https://rustup.rs">rustup.rs</a> while <a href="https://static.rust-lang.org" rel="nofollow">static.rust-lang.org</a> is also proxied.</em></p>
<p><em><strong>Usage</strong>: Visit this website, or configure these environment variables for <code>rustup</code> :</em></p>
<ul>
<li><code>RUSTUP_DIST_SERVER</code>: <code>https://${host}</code></li>
<li><code>RUSTUP_UPDATE_ROOT</code>: <code>https://${host}/rustup</code></li>
</ul>
<div><em>Bash:</em></div>
<div class="highlight highlight-source-shell">
<pre>CUSTOM_RUSTUP_DOMAIN='${host}'
export RUSTUP_DIST_SERVER="https://$CUSTOM_RUSTUP_DOMAIN"
export RUSTUP_UPDATE_ROOT="https://$CUSTOM_RUSTUP_DOMAIN/rustup"</pre></div>
<div><em>PowerShell:</em></div>
<div class="highlight highlight-source-powershell">
<pre>$CUSTOM_RUSTUP_DOMAIN='${host}'
$env:RUSTUP_DIST_SERVER="https://$CUSTOM_RUSTUP_DOMAIN"
$env:RUSTUP_UPDATE_ROOT="https://$CUSTOM_RUSTUP_DOMAIN/rustup"
</pre>
</div>
</div>`
+ newBody.slice(injectPos + 1), {headers});
}
if (url.pathname.startsWith('/sh')) {
const response = await fetch(new URL(url.pathname.slice(3), 'https://sh.rustup.rs'), {method, headers});
const content = await response.text();
return new Response(content.replaceAll('static.rust-lang.org', host), {headers: response.headers});
}
if (url.pathname.startsWith('/win')) {
return fetch(new URL(url.pathname.slice(4), 'https://win.rustup.rs'), {method, headers});
}
if (url.pathname.startsWith('/apex')) {
const response = await fetch(new URL(url.pathname.slice(5), 'https://rustup.rs'), {method, headers});
if (response.headers.get('content-type').startsWith('text/')) {
return new Response((await response.text())
.replaceAll(/https:\/\/(?:(?:sh\.|win\.)?rustup.rs|www\.rust-lang\.org)/g, (match) => origin + domainMapper[match])
, {
headers: response.headers,
});
}
return response;
}
if (url.pathname.startsWith('/org')) {
return fetch(new URL(url.pathname.slice(4), 'https://www.rust-lang.org'), {method, headers});
}
return fetch(new URL(url.pathname, 'https://static.rust-lang.org/'), {
method: request.method,
headers,
});
},
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment