rclone迁移浪潮云对象存储
浪潮云的对象存储用的就是ucloud的技术,基于ucloud自研的US3协议,兼容s3,US3是通过设置和修改 Token 令牌的读写权限(ACL)设置来控制用户的对存储空间或文件的访问权限,令牌格式与s3的AK/SK有所差异,S3 的 A...
浪潮云的对象存储用的就是ucloud的技术,基于ucloud自研的US3协议,兼容s3,US3是通过设置和修改 Token 令牌的读写权限(ACL)设置来控制用户的对存储空间或文件的访问权限,令牌格式与s3的AK/SK有所差异,S3 的 A...
前言 资源发现与评估 (Resource Discovery and Assessment):是一个部署在Windows主机上的工具,用于评估上云驱动力和准备度,发现应用的基础设施,提供其迁移到华为云的推荐配置以及主机的一站式迁移能力。 安...
很奇怪,今天突然发现WordPress Redis Object Cache缓存插件报错无法连接到Redis了。
具体报错如下图:
以为是 Redis 容器挂了,到主机上 tcping 了下 127.0.0.1 的 6379 端口,发现是通着的,顿时陷入了沉思······
来吧,老样子,介绍下环境:
查了半天,PHP Redis插件、redis容器运行状态及日志、php日志、OpenResty日志,都没发现问题······
最终排查出可能是因为插件自动升级的原因,导致原来插件的配置文件被覆盖成默认了,默认Redis服务地址为:127.0.0.1,传统环境下是没问题的,但是我们的 PHP 是 docker 容器化部署的,这就有问题了,如果填写 127.0.0.1 的话,去尝试连接的则是 PHP 容器内的127地址,所以肯定无法连接,那么我们把此地址改为容器名即可正常与Redis容器内应用通信,详细操作方法如下:
位置在网站根目录下的:/wp-content/plugins/redis-cache/includes/object-cache.php
默认为:
protected function build_parameters() {
$parameters = [
'scheme' => 'tcp',
'host' => '127.0.0.1',
'port' => 6379,
'database' => 0,
'timeout' => 1,
'read_timeout' => 1,
'retry_interval' => null,
'persistent' => false,
];
修改为:
protected function build_parameters() {
$parameters = [
'scheme' => 'tcp',
'host' => '1Panel-redis-kKCk',
'port' => 6379,
'database' => 0,
'password' => 'password',
'timeout' => 1,
'read_timeout' => 1,
'retry_interval' => null,
'persistent' => false,
];
修改涉及两处:
位置在网站根目录下:/wp-config.php
在最下方添加如下代码:
/** Redis Object Cache */
define( 'WP_REDIS_HOST', '1Panel-redis-kKCk' );
define( 'WP_REDIS_PORT', 6379 );
define( 'WP_REDIS_PASSWORD', 'password' );/** Redis设置了密码时填写 */
保存。
之后回到 WordPress 控制台插件处刷新界面,开启即可。
因为可以理解为Docker默认内置了一个小型DNS服务器,记录了容器名和容器IP地址的对应的对应关系,所以可以直接通过主机名进行通信。
想看看?这样:
列出我们docker的网卡,找出容器在使用的,记录下来,比如:1panel-network
docker network ls
docker network inspect 1panel-network
可以看到,这里就记录着我们Docker容器名和容器IP的对应关系。
由于腾讯文档是在线应用,腾讯可能随时对应用进行更新,有的时候发现用着用着突然就变样子了,常用的功能突然找不到了,不知道被挪到哪里去了······
最新的位置在:插入-->行列-->行高列宽-->自动调整行高列宽
这么常用的功能不知为何被藏得这么深~
登录此地址:dash.cloudflare.com
登录后进入如下界面,如图:
Worker 每天每免费账号有次数限制,为10万次。每分钟为1000次。完全够用了。
因为Cloudflare workers的域名workers.dev DNS被污染了,国内无法访,所以我们要有自己的域名。
选择free即可
点击开始快速扫描
比如,我的域名是在阿里云购买的,就需要到阿里云控制台修改默认的阿里DNS服务器地址为Cloudflare的地址。
切换域名的DNS服务器可能需要等待一会儿,完成后我们会收到邮件,我先去尿个尿~
尿完回来已经完成了,我们继续~
自定义一个worker名称,这里叫docker-porxy,然后点击部署。
点击可以预览我们的项目,如下显示表示已经部署成功。
点击页面的编辑代码,输入如下js代码。(代码来源:cmliu/CF-Workers-docker.io: 这个项目是一个基于 Cloudflare Workers 的 Docker 镜像代理工具。它能够中转对 Docker 官方镜像仓库的请求,解决一些访问限制和加速访问的问题。 (github.com))
注意:代码中 “你的域名” 替换为刚才生成的域名:“docker-proxy.1943483088.workers.dev”
// _worker.js
// Docker镜像仓库主机地址
let hub_host = 'registry-1.docker.io'
// Docker认证服务器地址
const auth_url = 'https://auth.docker.io'
// 自定义的工作服务器地址
let workers_url = 'https://你的域名'
// 根据主机名选择对应的上游地址
function routeByHosts(host) {
// 定义路由表
const routes = {
// 生产环境
"quay": "quay.io",
"gcr": "gcr.io",
"k8s-gcr": "k8s.gcr.io",
"k8s": "registry.k8s.io",
"ghcr": "ghcr.io",
"cloudsmith": "docker.cloudsmith.io",
// 测试环境
"test": "registry-1.docker.io",
};
if (host in routes) return [ routes[host], false ];
else return [ hub_host, true ];
}
/** @type {RequestInit} */
const PREFLIGHT_INIT = {
// 预检请求配置
headers: new Headers({
'access-control-allow-origin': '*', // 允许所有来源
'access-control-allow-methods': 'GET,POST,PUT,PATCH,TRACE,DELETE,HEAD,OPTIONS', // 允许的HTTP方法
'access-control-max-age': '1728000', // 预检请求的缓存时间
}),
}
/**
* 构造响应
* @param {any} body 响应体
* @param {number} status 响应状态码
* @param {Object<string, string>} headers 响应头
*/
function makeRes(body, status = 200, headers = {}) {
headers['access-control-allow-origin'] = '*' // 允许所有来源
return new Response(body, { status, headers }) // 返回新构造的响应
}
/**
* 构造新的URL对象
* @param {string} urlStr URL字符串
*/
function newUrl(urlStr) {
try {
return new URL(urlStr) // 尝试构造新的URL对象
} catch (err) {
return null // 构造失败返回null
}
}
function isUUID(uuid) {
// 定义一个正则表达式来匹配 UUID 格式
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
// 使用正则表达式测试 UUID 字符串
return uuidRegex.test(uuid);
}
async function nginx() {
const text = `
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
`
return text ;
}
export default {
async fetch(request, env, ctx) {
const getReqHeader = (key) => request.headers.get(key); // 获取请求头
let url = new URL(request.url); // 解析请求URL
workers_url = `https://${url.hostname}`;
const pathname = url.pathname;
const hostname = url.searchParams.get('hubhost') || url.hostname;
const hostTop = hostname.split('.')[0];// 获取主机名的第一部分
const checkHost = routeByHosts(hostTop);
hub_host = checkHost[0]; // 获取上游地址
const fakePage = checkHost[1];
console.log(`域名头部: ${hostTop}\n反代地址: ${hub_host}\n伪装首页: ${fakePage}`);
const isUuid = isUUID(pathname.split('/')[1].split('/')[0]);
const conditions = [
isUuid,
pathname.includes('/_'),
pathname.includes('/r'),
pathname.includes('/v2/user'),
pathname.includes('/v2/orgs'),
pathname.includes('/v2/_catalog'),
pathname.includes('/v2/categories'),
pathname.includes('/v2/feature-flags'),
pathname.includes('search'),
pathname.includes('source'),
pathname === '/',
pathname === '/favicon.ico',
pathname === '/auth/profile',
];
if (conditions.some(condition => condition) && (fakePage === true || hostTop == 'docker')) {
if (env.URL302){
return Response.redirect(env.URL302, 302);
} else if (env.URL){
if (env.URL.toLowerCase() == 'nginx'){
//首页改成一个nginx伪装页
return new Response(await nginx(), {
headers: {
'Content-Type': 'text/html; charset=UTF-8',
},
});
} else return fetch(new Request(env.URL, request));
}
const newUrl = new URL("https://registry.hub.docker.com" + pathname + url.search);
// 复制原始请求的标头
const headers = new Headers(request.headers);
// 确保 Host 头部被替换为 hub.docker.com
headers.set('Host', 'registry.hub.docker.com');
const newRequest = new Request(newUrl, {
method: request.method,
headers: headers,
body: request.method !== 'GET' && request.method !== 'HEAD' ? await request.blob() : null,
redirect: 'follow'
});
return fetch(newRequest);
}
// 修改包含 %2F 和 %3A 的请求
if (!/%2F/.test(url.search) && /%3A/.test(url.toString())) {
let modifiedUrl = url.toString().replace(/%3A(?=.*?&)/, '%3Alibrary%2F');
url = new URL(modifiedUrl);
console.log(`handle_url: ${url}`)
}
// 处理token请求
if (url.pathname.includes('/token')) {
let token_parameter = {
headers: {
'Host': 'auth.docker.io',
'User-Agent': getReqHeader("User-Agent"),
'Accept': getReqHeader("Accept"),
'Accept-Language': getReqHeader("Accept-Language"),
'Accept-Encoding': getReqHeader("Accept-Encoding"),
'Connection': 'keep-alive',
'Cache-Control': 'max-age=0'
}
};
let token_url = auth_url + url.pathname + url.search
return fetch(new Request(token_url, request), token_parameter)
}
// 修改 /v2/ 请求路径
if (/^\/v2\/[^/]+\/[^/]+\/[^/]+$/.test(url.pathname) && !/^\/v2\/library/.test(url.pathname)) {
url.pathname = url.pathname.replace(/\/v2\//, '/v2/library/');
console.log(`modified_url: ${url.pathname}`)
}
// 更改请求的主机名
url.hostname = hub_host;
// 构造请求参数
let parameter = {
headers: {
'Host': hub_host,
'User-Agent': getReqHeader("User-Agent"),
'Accept': getReqHeader("Accept"),
'Accept-Language': getReqHeader("Accept-Language"),
'Accept-Encoding': getReqHeader("Accept-Encoding"),
'Connection': 'keep-alive',
'Cache-Control': 'max-age=0'
},
cacheTtl: 3600 // 缓存时间
};
// 添加Authorization头
if (request.headers.has("Authorization")) {
parameter.headers.Authorization = getReqHeader("Authorization");
}
// 发起请求并处理响应
let original_response = await fetch(new Request(url, request), parameter)
let original_response_clone = original_response.clone();
let original_text = original_response_clone.body;
let response_headers = original_response.headers;
let new_response_headers = new Headers(response_headers);
let status = original_response.status;
// 修改 Www-Authenticate 头
if (new_response_headers.get("Www-Authenticate")) {
let auth = new_response_headers.get("Www-Authenticate");
let re = new RegExp(auth_url, 'g');
new_response_headers.set("Www-Authenticate", response_headers.get("Www-Authenticate").replace(re, workers_url));
}
// 处理重定向
if (new_response_headers.get("Location")) {
return httpHandler(request, new_response_headers.get("Location"))
}
// 返回修改后的响应
let response = new Response(original_text, {
status,
headers: new_response_headers
})
return response;
}
};
/**
* 处理HTTP请求
* @param {Request} req 请求对象
* @param {string} pathname 请求路径
*/
function httpHandler(req, pathname) {
const reqHdrRaw = req.headers
// 处理预检请求
if (req.method === 'OPTIONS' &&
reqHdrRaw.has('access-control-request-headers')
) {
return new Response(null, PREFLIGHT_INIT)
}
let rawLen = ''
const reqHdrNew = new Headers(reqHdrRaw)
const refer = reqHdrNew.get('referer')
let urlStr = pathname
const urlObj = newUrl(urlStr)
/** @type {RequestInit} */
const reqInit = {
method: req.method,
headers: reqHdrNew,
redirect: 'follow',
body: req.body
}
return proxy(urlObj, reqInit, rawLen)
}
/**
* 代理请求
* @param {URL} urlObj URL对象
* @param {RequestInit} reqInit 请求初始化对象
* @param {string} rawLen 原始长度
*/
async function proxy(urlObj, reqInit, rawLen) {
const res = await fetch(urlObj.href, reqInit)
const resHdrOld = res.headers
const resHdrNew = new Headers(resHdrOld)
// 验证长度
if (rawLen) {
const newLen = resHdrOld.get('content-length') || ''
const badLen = (rawLen !== newLen)
if (badLen) {
return makeRes(res.body, 400, {
'--error': `bad len: ${newLen}, except: ${rawLen}`,
'access-control-expose-headers': '--error',
})
}
}
const status = res.status
resHdrNew.set('access-control-expose-headers', '*')
resHdrNew.set('access-control-allow-origin', '*')
resHdrNew.set('Cache-Control', 'max-age=1500')
// 删除不必要的头
resHdrNew.delete('content-security-policy')
resHdrNew.delete('content-security-policy-report-only')
resHdrNew.delete('clear-site-data')
return new Response(res.body, {
status,
headers: resHdrNew
})
}
点击保存并部署。
我们可以自定义一个二级域名,一级域名必须是我们托管在了Cloudflare的。如果域名已经托管至Cloudflare,会自动弹出预览DNS记录;点击添加自定义域。
#vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://docker.wanpeng.top"]
}
docker pull docker.wanpeng.top/library/alpine:latest # 拉取 library 镜像
docker pull docker.wanpeng.top/coredns/coredns:latest # 拉取 coredns 镜像
速度还不错,能跑百兆!成功!
如果自己有国外的服务器,可以搭建个私人的镜像仓库,也可以中转拉取镜像的流量,可以参考我写的另一篇文章:搭建自己的Docker镜像加速服务:使用1Panel部署Docker Registry缓存镜像 (wanpeng.life)
https://docker.wanpeng.top
#vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://docker.wanpeng.top"]
}
修改完成后重启Docker服务
systemctl restart docker
docker pull docker.wanpeng.top/library/alpine:latest # 拉取 library 镜像
docker pull docker.wanpeng.top/coredns/coredns:latest # 拉取 coredns 镜像
1. 搭建自己的Docker镜像加速服务:使用1Panel部署Docker Registry缓存镜像 (wanpeng.life)
2. Cloudflare Workers搭建docker镜像加速服务 将域名解析托管到Cloudflare实现自定义加速服务域名 无限流量 (wanpeng.life)
阿里云漏洞库 (aliyun.com)介绍了相关漏洞描述、影响范围、处理建议等。
ssh -V
OpenSSH_8.7p1, OpenSSL 3.0.7 1 Nov 2022
在影响范围:8.5p1 <= OpenSSH < 9.8p1之内
rpm -qa |grep openssh
sudo dnf --refresh upgrade openssh -y
rpm -qa | grep openssh
版本包版本已经升级到 xxxx.2.xxx版本,此版本已解决此漏洞。
完成!
官方修复文档:AlmaLinux OS - Forever-Free Enterprise-Grade Operating System
之前部署过一个开源的中文Linux命令查询工具,非常的好用:
然后为了从此工具界面把一些流量吸引到主站点上,所以想着修改下HTML代码,加上如上图的内容,index.html手动顺利添加上了,但是发现,每个命令的讲解界面都是单独的HTML文件,一共600多个,这要是手动修改人都改麻了,于是有了今天的内容,使用Python脚本批量修改,每行都写了注释,供大家参考和修改。
import os
# 定义目录路径
directory = '/path/to/your/html/files' # 替换为你的HTML文件目录路径
# 要添加的标题行
new_line = '<h2><a target="_blank" href="https://www.wanpeng.life/">更多技术类博文可访问博客:万万没想到</a></h2>\n'
# 要匹配的行
target_line = '<a target="_blank" href="https://github.com/jaywcjlove/linux-command/new/master/command">添加命令</a> |'
# 遍历目录下的所有HTML文件
for filename in os.listdir(directory):
# 检查文件是否为HTML文件
if filename.endswith('.html'):
# 获取文件的完整路径
filepath = os.path.join(directory, filename)
# 读取文件内容
with open(filepath, 'r', encoding='utf-8') as file:
lines = file.readlines() # 逐行读取文件内容
# 重新写入文件内容,并在匹配行上面添加新行
with open(filepath, 'w', encoding='utf-8') as file:
for line in lines:
# 如果匹配到目标行,则在其上面添加新行
if target_line in line:
file.write(new_line) # 在目标行上面添加新的标题行
# 无论是否匹配,都写入原文件内容
file.write(line)
print("批量修改完成!") # 打印完成信息
不到1s,600多个文件就都修改完了
经过测试,各个页面也都成功加上了链接,成功!