====== Pleroma 使用 Cloudflare Worker 搭建代理 ======
如果没有 Cloudflare 账户的话,可以到 [[https://dash.cloudflare.com/login|dash.cloudflare.com]] 注册账户,套餐全部选择 Free 即可。
===== 创建 Worker =====
进入 [[https://dash.cloudflare.com/|Cloudflare 管理界面]] ,您会看到:
{{ ::cloudflare:cf-panel.png?nolink | Cloudflare Panel}}
点击右下角的这个 Worker 按钮进入 Worker 面板:
{{ :cloudflare:cf-worker-icon.png?nolink |}}
点击 Create a Worker,创建 Worker。
{{ :cloudflare:cf-create-worker.png?nolink |Create Worker}}
此时,如果您点击 Save and Deploy 按钮,您会看到您的代理的域名,您需要记下这个域名。(当然记不得的话,您也可以在很多其它地方重新找到这个域名。)
确认后,您可以点击 Send 按钮,您会看到 200 OK 的响应。
===== 更改 Worker 代码 =====
将左侧的代码编辑窗口的代码全部删除干净,粘贴入下面的代码:
// 你要镜像的网站.
const upstream = 'pleroma.example.com'
const upstream_path = '/'
const upstream_mobile = upstream
const blocked_region = ['KP', 'SY', 'PK', 'CU']
const blocked_ip_address = ['0.0.0.0', '127.0.0.1']
const https = true
const replace_dict = {
'$upstream': '$custom_domain',
}
addEventListener('fetch', event => {
event.respondWith(fetchAndApply(event.request));
})
async function fetchAndApply(request) {
const region = request.headers.get('cf-ipcountry').toUpperCase();
const ip_address = request.headers.get('cf-connecting-ip');
const user_agent = request.headers.get('user-agent');
let response = null;
let url = new URL(request.url);
let url_hostname = url.hostname;
if (https == true) {
url.protocol = 'https:';
} else {
url.protocol = 'http:';
}
if (await device_status(user_agent)) {
var upstream_domain = upstream;
} else {
var upstream_domain = upstream_mobile;
}
url.host = upstream_domain;
if (url.pathname == '/') {
url.pathname = upstream_path;
} else {
url.pathname = upstream_path + url.pathname;
}
if (blocked_region.includes(region)) {
response = new Response('Access denied: WorkersProxy is not available in your region yet.', {
status: 403
});
} else if (blocked_ip_address.includes(ip_address)) {
response = new Response('Access denied: Your IP address is blocked by WorkersProxy.', {
status: 403
});
} else {
let method = request.method;
let request_headers = request.headers;
let new_request_headers = new Headers(request_headers);
new_request_headers.set('Host', url.hostname);
new_request_headers.set('Referer', url.hostname);
let request_body = null;
if(url.href.includes('/api/v1/media')) {
request_body = request.body
} else if(method === 'POST' || method === 'PATCH' || method === 'PUT') {
request_body = '';
request_body = await request.text();
if(request_body) {
let re = new RegExp(url_hostname, 'g')
request_body = request_body.replace(re, upstream);
}
}
let original_response = await fetch(url.href, {
method: method,
headers: new_request_headers,
body: request_body
})
let original_response_clone = original_response.clone();
let original_text = null;
let response_headers = original_response.headers;
let new_response_headers = new Headers(response_headers);
let status = original_response.status;
new_response_headers.set('access-control-allow-origin', '*');
new_response_headers.set('access-control-allow-credentials', true);
new_response_headers.delete('content-security-policy');
new_response_headers.delete('content-security-policy-report-only');
new_response_headers.delete('clear-site-data');
const content_type = new_response_headers.get('content-type');
if (content_type.includes('text/html') && content_type.includes('UTF-8')) {
original_text = await replace_response_text(original_response_clone, upstream_domain, url_hostname);
} else {
original_text = original_response_clone.body
}
response = new Response(original_text, {
status,
headers: new_response_headers
})
}
return response;
}
async function replace_response_text(response, upstream_domain, host_name) {
let text = await response.text()
var i, j;
for (i in replace_dict) {
j = replace_dict[i]
if (i == '$upstream') {
i = upstream_domain
} else if (i == '$custom_domain') {
i = host_name
}
if (j == '$upstream') {
j = upstream_domain
} else if (j == '$custom_domain') {
j = host_name
}
let re = new RegExp(i, 'g')
text = text.replace(re, j);
}
return text;
}
async function device_status(user_agent_info) {
var agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
var flag = true;
for (var v = 0; v < agents.length; v++) {
if (user_agent_info.indexOf(agents[v]) > 0) {
flag = false;
break;
}
}
return flag;
}
代码改自 https://umrhe.com/cloudflare-workers-to-google.html 。
粘贴完后,把”你要镜像的网站“处的 ''const upstream = 'pleroma.example.com' '' 改成 const upstream = '您的Pleroma域名'
改完后点击 Save and Deploy 即可。此时您访问代理域名就可以正常使用 Pleroma 了。
如果认为域名太长太难记,您也可以查询另外绑定域名的教程,此处不详述。
==== 安全提醒 ====
安全提醒
反代这种事情是谁都可以做的,并不需要官方的授权。所以很可能被人用于钓鱼攻击。
使用替代域名登录实例之前,请一定要确认这个替代域名是官方建立的。
引自 [[https://blog.bgme.me/posts/nginx-reverser-proxy-for-mastodon/#id3|影子屋]]