首页
关于我们
友链链接
壁纸下载
更多
统计中心
热点搜索
图床上传
推荐
剩余价值
磁链清理
IP定位
Search
1
[Win DD包] wes7-x86-cn-精简,安装后仅占用1.55G存储空间
25,950 阅读
2
v2rayN基础使用教程、配置说明、添加订阅、路由选择
18,332 阅读
3
鸿蒙Next也能科学上网?Clash Meta for harmorny next os
11,807 阅读
4
纯血鸿蒙系统如何安装电报、推特、Tiktok和油管APP
9,345 阅读
5
保姆级教程!甲骨文ARM DD成Debian10并升级内核成5.10
6,504 阅读
Linux学堂
网站建设
网络资源
主题插件
固件工具
主机评测
MV频道
登录
Search
标签搜索
vps
typecho
linux
bench
mysql
cloudflare
nginx
lnmp
empirecms
ssl
openwrt
google
centos
docker
qbittorrent
telegram
n1
301
free
serverstat
V+变量
累计撰写
304
篇文章
累计收到
256
条评论
首页
栏目
Linux学堂
网站建设
网络资源
主题插件
固件工具
主机评测
MV频道
页面
关于我们
友链链接
壁纸下载
统计中心
热点搜索
图床上传
推荐
剩余价值
磁链清理
IP定位
搜索到
107
篇与
的结果
2026-06-03
Discuz X3.5升级到Discuz X5及数据库迁移后出现的约束CONSTRAINT失败 + 主键重复Duplicate entry for key问题的解决
1 背景博主最近把手头上唯一的论坛从DISCUZX3.5升级到Discuz X5,另外把建站VPS提供商从netcup转到Hostdizre,原因是Netcup的月租价格从5.75O提到6.81O,本来网站就没什么流量,索性就以80元的价格忍痛出掉了VPS1000 G11翻倍款(2024年黑五),迁移过程中无论是mysql导入,还是phpmyadmin,都出现了约束CONSTRAINT失败 + 主键重复Duplicate entry for key问题,借助AI找到了解决办法,这里记录一下,方面以后自己查阅。2 升级教程升级比较简单,直接按官方教程就行了:从 X5.0 开始安装程序内置升级程序,升级前请关闭站点、关闭所有插件。请详细阅读下面的内容:1、确保您的旧版本 Discuz! 必须为 X3.5 版本,如不满足版本要求请先升级到此版本; 2、确保 UCenter 和 Discuz! 部署在一个数据库中; 3、确保您已备份了数据库和程序文件,将旧版本程序文件移动到其他目录下; 4、将旧版本的配置文件 config/config_global.php、config/config_ucenter.php 复制到当前新版本的 config/ 目录中; 5、点击“下一步”开始升级; 6、升级完成后可以将旧版本中 source/plugin/ 目录下的插件文件挑选后复制到新版本的对应目录下、将 template/ 目录下的模板文件挑选后复制到新版本的对应目录下(不要复制 template/default/ 目录); 7、升级完成后 data/attachment/ 目录以及 data/ 目录下其他目录请酌情复制;如旧版本应用涉及其他目录中的文件,请自行咨询相关开发者复制;3 数据迁移3.1 直接用mysql命令迁移在源服务器终端导出数据mysqldump -u root -p --databases database_name> database_name.sql在新服务器终端导入数据mysql -u root -p database_name --force < database_name.sql3.2 CONSTRAINT约束失败问题博主在导入数据时,出现如下错误:ERROR 4025 (23000) at line XXXX: CONSTRAINT `pre_common_member_profile.fields` failed for `database_name`.`pre_common_member_profile通过AI找到了解决办法:这个错误明确指出了在导入 SQL 文件的第 XXXX 行时,pre_common_member_profile 表的 fields 字段数据违反了 MariaDB 的 CHECK 约束。由于是在恢复数据库,最安全、最高效的做法是临时关闭约束检查,而不是去逐条修改备份文件中的数据(这既耗时又容易破坏备份完整性)。出现这个问题的原因:原因说明MySQL → MariaDB 迁移MySQL 8.0 之前对 CHECK 约束是“只解析不执行”的,旧数据可能包含空字符串或非法序列化值;MariaDB 会严格校验Discuz! 版本差异新版 Discuz! 建表脚本为 fields 添加了格式约束(如必须为合法 PHP 序列化数组),但您的备份来自旧版,存在 '' 等不合规值备份导出环境宽松原服务器可能禁用了约束检查或使用了更宽松的 sql_mode,导致脏数据被成功备份方法一:命令行导入时直接注入参数(最推荐)如果您使用命令行恢复,无需修改 SQL 文件,直接在命令中追加参数即可跳过该约束:mysql -u root -p database_name --init-command="SET SESSION check_constraint_checks=0;" < database_name.sql原理:--init-command 会在每次连接建立时自动执行,确保整个导入过程都在禁用约束检查的状态下进行。方法二:修改 SQL 备份文件头部如果您使用宝塔面板、Navicat 或其他工具导入,无法传递命令行参数,请用文本编辑器(如 Notepad++ / VSCode)打开 .sql 文件,在最顶部添加:SET SESSION check_constraint_checks = 0; SET FOREIGN_KEY_CHECKS = 0; SET UNIQUE_CHECKS = 0; SET sql_mode = '';保存后重新导入。导入完成后,这些设置会随会话结束自动失效,无需手动恢复。🛠️重要提醒不要尝试删除约束后再导入:删除/重建约束需要 ALTER TABLE,在大表上非常慢,且导入后还需重新添加,远不如临时禁用检查高效。不要手动编辑第 6868 行:SQL 备份文件通常有数百 MB 甚至 GB 级别,用普通编辑器打开极易卡死或损坏文件。即使定位到该行,后续可能还有成千上万条同样违规的数据。此操作仅影响当前导入会话:check_constraint_checks=0 是会话级变量,不会影响数据库中已有的约束定义,也不会影响其他连接或后续的正常使用。3.3 主键重复Duplicate entry for key博主在导入mysql数据库过程中还出现了主键重复问题:ERROR 1062 (23000) at line 19: Duplicate entry 'XXXXX' for key 'PRIMARY'这个错误 ERROR 1062 (23000): Duplicate entry 'XXXXX' for key 'PRIMARY' 表示在导入 SQL 备份时,目标数据库表中已经存在主键为 XXXXX 的记录,导致插入冲突。这通常发生在以下两种情况:非空库恢复:目标数据库不是全新的,里面已有旧数据或之前导入失败残留的数据。SQL 文件问题:备份文件中包含了 CREATE TABLE 但没有 DROP TABLE IF EXISTS,或者您正在重复导入同一个备份文件。Qwen3.7-Max这个错误 ERROR 1062 (23000): Duplicate entry '38472' for key 'PRIMARY' 表示在导入 SQL 备份时,目标数据库表中已经存在主键为 38472 的记录,导致插入冲突。这通常发生在以下两种情况:非空库恢复:目标数据库不是全新的,里面已有旧数据或之前导入失败残留的数据。SQL 文件问题:备份文件中包含了 CREATE TABLE 但没有 DROP TABLE IF EXISTS,或者您正在重复导入同一个备份文件。🛠️ 解决方案(按场景选择)方案1:全新恢复 / 覆盖现有数据(最常见)如果您确认目标数据库可以被完全覆盖,请在导入命令中添加 --force 参数,让 MySQL 忽略重复键错误并继续执行后续语句:mysql -u root -p database_name --force < database_name.sql⚠️ 注意:--force 会跳过所有报错行(包括重复键、约束失败等),但不会回滚已成功的部分。结合您之前的 #4025 错误,建议组合使用:mysql -u root -p database_name --force --init-command="SET SESSION check_constraint_checks=0;" < database_name.sql方案二:确保干净恢复(推荐用于生产环境)如果希望避免任何数据混淆,最稳妥的做法是先清空再导入:# 1. 删除并重建数据库(彻底清除旧数据) mysql -u root -p -e "DROP DATABASE IF EXISTS \`database_name\`; CREATE DATABASE \`database_name\` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" # 2. 重新授权(如需要) mysql -u root -p -e "GRANT ALL PRIVILEGES ON \`bbs-gvars-com\`.* TO 'your_user'@'localhost'; FLUSH PRIVILEGES;" # 3. 导入备份 mysql -u root -p database_name --init-command="SET SESSION check_constraint_checks=0;" < database_name.sql3.4 🛠️ 一键解决命令结合所有问题(约束失败 + 主键重复),使用以下组合命令一次性解决:mysql -u root -p database_name \ --force \ --init-command="SET SESSION check_constraint_checks=0; SET FOREIGN_KEY_CHECKS=0; SET UNIQUE_CHECKS=0; SET sql_mode='';" \ < database_name.sql参数说明:--force:跳过 Duplicate entry 等所有非致命错误,继续执行后续 SQLcheck_constraint_checks=0:解决当前 #4025 CONSTRAINT failed 及之前的 fields 约束错误FOREIGN_KEY_CHECKS=0:避免外键顺序导致的导入失败sql_mode='':解决 MODIFY COLUMN 语法兼容性问题所有设置均为 SESSION 级别,仅影响本次导入连接,不会污染数据库全局配置3.5🔍 为什么帖子内容也会触发约束?原因具体表现MySQL → MariaDB 迁移MySQL 5.7/8.0 对 CHECK 约束“只解析不执行”,旧帖内容可能含 \0、截断的 UTF-8 字符等;MariaDB 10.3+ 会严格校验Discuz! 版本升级X3.5 为 content 添加了长度/格式约束,但备份来自 X3.4 或更早版本,存在历史脏数据编辑器/插件残留第三方编辑器或采集插件写入的内容不符合原生 Discuz! 格式规范3.6⚠️ 导入后必须执行的验证与修复约束检查被临时禁用意味着脏数据会被原样写入。导入完成后,请务必执行以下检查和修复:-- 1. 检查 content 为空的异常帖子 SELECT pid, tid FROM pre_forum_post WHERE content = '' OR content IS NULL; -- 2. 检查包含非法字符或截断内容的帖子(可选) SELECT pid, tid FROM pre_forum_post WHERE content NOT REGEXP '^[\x09\x0A\x0D\x20-\x7E\x{4E00}-\x{9FFF}]*$'; -- 3. 统一修复空内容为 Discuz! 默认占位符 UPDATE pre_forum_post SET content = '[内容已丢失]' WHERE content = '' OR content IS NULL;3.7💡 关键提醒不要逐行定位 line 16:SQL 备份文件中可能有成千上万条违规帖子内容,逐条修复不现实。不要删除约束定义:ALTER TABLE ... DROP CONSTRAINT 在大表上极慢,且导入后还需重建,远不如临时禁用高效。--force 的副作用:它会跳过所有错误(包括真正的语法错误)。导入完成后务必通过行数对比验证数据完整性:SELECT COUNT(*) FROM pre_forum_post;-- 与备份源或导出时的记录数对比如果仍报其他 CONSTRAINT 错误:说明还有其他表存在同样问题,上述 --init-command 已经覆盖了所有常见约束类型,理论上不应再出现同类报错。
2026年06月03日
20 阅读
0 评论
0 点赞
2026-05-28
帝国CMS8.0文章页面设置TAGS关键字调用及TAGS静态化规则
1 前言博主最近把帝国cms7.5做的美食网站 5VAR美食谷 升版到8.0,主要是想体验更安全的PHP8,但是升版后发现TAG调用失效,经过多方排查,发现是升级后模板未修改,以及PHP8模式下数组需要增加单引号的强制要求导致,经过一番折腾终于处理好了,顺便记录下。2 操作步骤2.1帝国CMS TAG设置2.1.1 登录后台,单击【栏目】菜单【TAGS管理】【设置TAGS参数】子菜单,进入设置TAGS参数界面。2.1.2 进入设置TAGS参数界面, 前台开启TAGS:设置前台/e/tags/页面是否开启使用。默认使用的模板:选择tags的列表模板,这里建议选择和文章一样的列表模板; 每页显示信息:设置不指定line情况下默认的每页显示信息数。2.2 帝国CMS TAGS标签调用2.2.1 用帝国cms自带的自定义调用工具进行调用:showtags分类ID,显示数量,每行显示数量,显示排序,只显示推荐,推荐TAGS属性,显示间隔符,是否显示信息数,链接附加参数,链接使用变量/showtags具体参考:模板==》自动生成标签===》调用tags标签模板2.2.2 帝国cms使用灵动标签调用当前文章内容tag标签[e:loop={"SELECT infotags FROM {$dbtbpre}ecms_news WHERE id='$navinfor[id]' LIMIT 1",1,24,0}] <?php $tag = ''; $infotags = $bqr['infotags']; // 统一中文逗号为英文逗号,避免分隔失败 $str = str_replace(',', ',', $infotags); $t = explode(',', $str); foreach ($t as $tagName) { $tagName = trim($tagName); if ($tagName !== '') { // 对标签名进行URL编码和HTML实体转义 $encodedTag = urlencode($tagName); $safeTag = htmlspecialchars($tagName, ENT_QUOTES, 'UTF-8'); $tagslink = $public_r['newsurl'] . "e/tags/?tagname=" . $encodedTag; $tag .= '<a href="' . $tagslink . '" target="_blank" rel="tag">' . $safeTag . '</a> '; } } echo $tag; ?> [/e:loop]2.2.3 帝国CMS灵动标签调用TAGS[e:loop={"SELECT tagid, tagname FROM {$dbtbpre}enewstags ORDER BY num DESC LIMIT 10",0,24,0}] <li> <a href="<?=$public_r['newsurl']?>e/tags/?tagid=<?=$bqr['tagid']?>" target="_blank" rel="tag noopener noreferrer"> <?=htmlspecialchars($bqr['tagname'], ENT_QUOTES, 'UTF-8')?> </a> </li> [/e:loop]或是我们自己根据tagid来显示[e:loop={"SELECT tagid, tagname FROM {$dbtbpre}enewstags ORDER BY tagid ASC",0,24,0}] <li> <a href="<?=$public_r['newsurl']?>e/tags/?tagid=<?=$bqr['tagid']?>" target="_blank" rel="tag noopener noreferrer"> <?=htmlspecialchars($bqr['tagname'], ENT_QUOTES, 'UTF-8')?> </a> </li> [/e:loop]2.3 设置伪静态规则如果我们采用的伪静态,则需要在Nginx或Apache配置文件中添加伪静态规则。2.3.1 NGINX伪静态规则rewrite ^/tags-(.+?)-([0-9]+).html$ /e/tags/index.php?tagname=$1&page=$2 last;2.3.2 apache 伪静态规则#TAGS信息列表页 RewriteCond %{QUERY_STRING} ^(.*)$ RewriteRule ^tags-(.+?)-(.+?)\.html$ /e/tags/index.php?tagname=$1&page=$2
2026年05月28日
21 阅读
1 评论
0 点赞
2026-05-23
甲骨文云服务器丢失密钥和忘记密码无法登录SSH的终极方案
1 背景博主的ORACLE账号还是6年前注册的,这中间因为各种客观原因没有去折腾网站,电脑也换了,备份的资源都丢失了,里边应该包含ssh登录的一些信息。ssh登录Oracle Cloud Linux实例时,一直连接失败,通过oracle 后台的cloud shell切换root用户时,一直提示要输入密码,我试了有8次还是错误,实在想不起来,又怕继续尝试会被系统封号,只得作罢。必应和千问AI搜了一下,主要有如下方法: 1)分离引导卷; 2)创建定制映像; 3)重装系统(我试了几次没成功); 4)杀龟(对VPS上没有部署任何服务的小伙伴这样最省事,大不了再开1台)。思索和尝试后,最终选择使用分离引导卷来修复ssh无法登录问题。2 分离引导卷解决思路:通过将故障实例 A 的“硬盘”挂载到另一台救援实例 B 上,直接为实例A 添加root用户名和密码,修复故障实例A本地的ssh私钥、公钥损坏或密码以往问题,添加完再把硬盘挂载回实例A。话不多说,直接上干货2.1 停止故障实例1)登录到 OCI 控制台。2)导航到 计算 (Compute) -> 实例 (Instances)。3)选择您无法 SSH 连接的故障实例。4点击顶部的 停止 (Stop) 按钮。5)等待实例状态完全变为已停止,这需要一段时间莫急。2.2 识别并分离启动盘1)在故障实例的详情页,找到 存储(Storage)-> 引导卷 (Boot Volume)。2)点击启动卷的右端 ... 打开详情界面3)记下启动卷名称(类似 ocid1.bootvolume...)。4)点击 分离 (Detach) 按钮,确认分离操作。5)等待分离操作完成,状态变为分离 (Detached)。2.3 准备救援实例需要一个能正常工作、且位于相同可用性域 (Availability Domain, AD) 的 Linux 实例作为“救援实例”。如果没有救援实例,请在与故障实例相同的 AD 中创建一个新的小型 Linux 实例。确保可以正常 SSH 连接到这个“救援实例”。我这里救援实例选择的ubuntu系统,主要是支持资料多。2.4 将故障实例启动盘附加到救援实例1)导航到故障实例的详情页。2)滚动到 存储 (Storage) -> 启动卷 (Boot volume)。3)点击故障实例启动卷:instance-xxx (Boot volume)。4)在 instance-xxx (Boot volume) 窗口中,选择Attached instance 选项,选择半虚拟化最简单,附加到救援实例,点击 附加 (Attach),等待附加完成。3 救援实例挂载故障启动盘3.1 SSH 连接到救援实例;通过 SSH 连接到您的救援实例。注意是正常可以SSH登录的那台机器。3.2 识别故障盘通过lsblk或者 fdisk 其中之一sudo lsblk或sudo fdisk -l此时看到一个新磁盘(例如 /dev/sdb)。其系统分区通常是 /dev/sdb3。请根据您的实际输出确认正确的设备路径。3.3 创建挂载点:sudo mkdir /mnt/rescue3.4 挂载故障实例的根分区(请将 /dev/sdb3 替换为您上一步确认的正确路径):sudo mount /dev/sdb3 /mnt/rescue3.5 查看最终挂载情况df -h显示磁盘挂载情况,如已挂载可以开展下一步工作。4 修复故障实例盘这里有两种方法,修复密码和DD救援包,我选择的时第一种方法。4.1 Chroot 到故障环境并设置密码1)使用 chroot 命令切换到故障实例的操作系统环境:sudo chroot /mnt/rescue2)设置新密码passwd root终端提示您输入并确认新密码。请设置一个您能记住的密码3)设置完成后,退出 chroot 环境exit4)卸载修复后的故障实例盘sudo umount /mnt/rescue5)完成故障实例盘的密码设置:4.2 DD救援包修复故障盘正常按4.1的方法就能完成SSH登录,有余力的可以下载DD救援包。如果自己没有备份救援包的话,这里提供2个ARM救援包和2个AMD救援包供大家使用:4.2.1 DD救援包下载1)ARM镜像Debian10 ,DD 过程应小于 12 分钟。用户名root/密码10086.fitcd /root && wget -cO debian.sdb.gz https://github.com/MIKU-N/OracleBackup/raw/main/dabian.sdb.gz?download= gzip -dc /root/debian.sdb.gz | dd of=/dev/sdb2)Ubuntu 20.04 ARM 官方原版完整救援包(恢复数据约46G,耗时约1个多小时)wget --no-check-certificate https://github.com/honorcnboy/BlogDatas/releases/download/OracleRescueKit/Ubuntu20.04.arm.img.gz用户名:root, 密码:CNBoy.org。3)下载下方秘钥,载入SSH工具,无密码登录https://github.com/honorcnboy/BlogDatas/releases/download/OracleRescueKit/backup4)Ubuntu 20.04 AMD 官方原版完整救援包(恢复数据约46G,耗时约1个多小时)wget --no-check-certificate https://github.com/honorcnboy/BlogDatas/releases/download/OracleRescueKit/Ubuntu20.04.amd.img.gz用户名:root, 密码:CNBoy.org。下载下方秘钥,载入SSH工具,无密码登录https://github.com/honorcnboy/BlogDatas/releases/download/OracleRescueKit/backup5)debian10 ARM 网络精简救援包(恢复数据约3G,耗时约10多分钟)wget --no-check-certificate https://github.com/honorcnboy/BlogDatas/releases/download/OracleRescueKit/dabian10.arm.img.gz用户名:root, 密码:10086.fit6)救砖甲骨文 AMD 执行curl -Lo- "https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-nocloud-amd64.tar.xz" | tar -xJO | dd of=/dev/sdb bs=1M7)AMD如果需要 Debian 12 系统,则执行curl -Lo- "https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-nocloud-amd64.tar.xz" | tar -xJO | dd of=/dev/sdb bs=1M8) 救砖 甲骨文 ARM 执行curl -Lo- "https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-nocloud-arm64.tar.xz" | tar -xJO | dd of=/dev/sdb bs=1M9)ARM如果需要 Debian 12 系统,则执行curl -Lo- "https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-nocloud-arm64.tar.xz" | tar -xJO | dd of=/dev/sdb bs=1MDD 过程大约 25 分钟。4.2.2 恢复镜像到 /dev/sdb3 分区如果引导卷加载路径不同,请自行修改路径说明:为了防止在SSH连接在恢复数据中途中断导致失败,建议使用 srceen 后台窗口运行以下命令gzip -dc '救援包完整路径' | dd of='引导卷加载路径' 例: 使用 Ubuntu 20.04 ARM 官方原版完整救援包,命令如下: gzip -dc /root/Ubuntu20.04.arm.img.gz | dd of=/dev/sdb 使用 Ubuntu 20.04 AMD 官方原版完整救援包,命令如下: gzip -dc /root/Ubuntu20.04.amd.img.gz | dd of=/dev/sdb 使用 debian10 ARM 网络精简救援包,命令如下: gzip -dc /root/dabian10.arm.img.gz | dd of=/dev/sdb恢复过程中你可以新开一个SSH窗口,然后运行以下命令后不要关闭,切换回恢复命令的窗口查看进度watch -n 5 pkill -USR1 ^dd$5 故障实例盘物归原主5.1 卸载并分离故障实例盘1)回到 OCI 控制台 -> 救援实例详情页 -> 附加的块存储卷。2)找到附加的启动卷,点击操作菜单 (...),选择 分离 (Detach);3)等待分离完成;5.2将启动盘重新附加到原实例(故障实例)1)导航回到故障实例的详情页。2)找到到 存储 (Storage) -> 引导卷 (Boot Volume)。3)点击 附加 (Attach),选择分离的启动卷。4)等待附加完成。5.3 启动故障实例在故障实例的详情页,点击启动 (Start)。6 SSH登录到修复后的故障实例等待实例运行后,可以通过SSH终端或者OCI后台的cloud shell进行操作。
2026年05月23日
39 阅读
0 评论
0 点赞
2026-05-23
Debian等新系统利用mysql导入数据时提醒libtinfo.so.5依赖库不存在的问题解决
1.背景因Netcup今年5月份后开始涨价,原价5.75欧/月的VPS1000翻倍款涨到6.81欧,博主最近把手头上的VPS从netcup迁移到阿里巴巴香港轻量服务器。在导入mysql数据的时候,系统会报错:mysql: error while loading shared libraries: libncurses.so.5: cannot open shared object file: No such file or directory。mysql -u root -p <database-name> < <database-name>.sql博主建站环境为:操作系统:Debian 13 web服务器:Nginx 1.26.0 数据库 Mariadb 10.11.7-MariaDB-log - MariaDB Server PHP: 8.3.72.原因排查通过检索和AI查询,了解到这个报错非常典型,通常发生在使用较新的 Linux 系统(如Debian、Ubuntu 20.04+ 等)去运行一个较旧版本的 MySQL 时。简单来说, MySQL 程序启动时需要一个叫 libncurses.so.5 的老版本依赖库,但新系统里默认只安装了更新的 libncurses.so.6,导致 MySQL 找不到“老伙计”而无法启动。3.处理方案3.1 手动创建软链接通过“欺骗”的方式,给系统里现有的新版本库创建一个旧名字的快捷方式(软链接),让 MySQL 以为找到了它需要的文件。3.1.1 建立软连接ln -s /usr/lib/x86_64-linux-gnu/libncurses.so.6 /usr/lib/x86_64-linux-gnu/libncurses.so.5 ln -s /lib/x86_64-linux-gnu/libtinfo.so.6 /lib/x86_64-linux-gnu/libtinfo.so.5注:如果提示找不到源文件,可以先用 find /usr -name "libtinfo.so.6" 确认一下你系统中 libtinfo.so.6 的实际路径3.2 刷新动态链接库缓存创建完软链接后,建议执行一下ldconfig 刷新动态链接库缓存,然后再尝试启动或登录 MySQL,这个问题应该就彻底解决了。3.2 通过系统包管理器安装如果你是 Ubuntu 20.04+ 或 Debian 系统,可以直接安装 libtinfo5 包,我的debian13直接安装这个依赖包时失败的。sudo apt update sudo apt install libtinfo5 -y如果你是 CentOS 8/9、RHEL、Rocky Linux 等系统:安装 ncurses 的兼容库通常会自动包含 libtinfo。执行:sudo dnf install ncurses-compat-libs -y
2026年05月23日
37 阅读
0 评论
0 点赞
2026-05-17
Alpine安装Vnstat统计VPS流量,避免serverstaus系统重启后流量重置
一 前言之前介绍了ServerStat在Linux VPS的安装配置、采用Vnstat来防止重启导致数据丢失的问题,以及如何在LiNUX VPS上手动安装Server-Rust,需要的可以访问之前的博文:1)LiNUX VPS上Server-Rust的手动安装教程2)Serverstaus改用Vnstat统计VPS流量,避免服务器重启引起统计丢失3)Alpine上Server-Rust的手动安装教程博主最近购买了阿里云国际的CDT作为上网备用,限于其配置,只有468M内存和2G硬盘,无法安装debian,因此采用体积和内存占用更小的alpine。本文介绍下如何在Alpine上安装vnstat作为Server-Rust client的流量统计工具。二 vnstat安装教程1 直接apk安装# 更新软件源 apk update # 安装 vnstat apk add vnstat2 查看vnstat版本vnstat --version成功的话会显示vnStat 2.13 by Teemu Toivola (SQLite 3.51.2)3 修改/etc/vnstat.conf,下面这三个字段处要修改,有;注释的需要把;拿掉BandwidthDetection 0 # 禁用自动检测网络接口最大带宽 MaxBandwidth 0 # 解除带宽限制 Interface "" # 自动选择网口(默认非eth0需设置)4 设置启动# 启动 vnstat 服务 sudo rc-service vnstat start注意,这里第2步虽然显示成功了,但其实并没有生成相应的文件,如用上面命令会报错:rc-service: service `vnstat' does not exist问了AI,给了我答案:如果你安装后依然报错,或者想确认服务文件是否存在,可以检查一下 /etc/init.d/ 目录下是否有 vnstat 这个文件:ls -l /etc/init.d/vnstat正常情况下,安装完软件后这个文件就会自动出现,之后你就可以正常使用 rc-service vnstat status 等命令来管理它了。如果 /etc/init.d/ 目录下找不到 vnstat 文件,说明刚才的安装过程没有成功,或者没有正确生成对应的启动脚本,就要按照下面手动创建了。5 手动创建 vnstat 启动脚本在 Alpine Linux 中,如果包管理器没有自动生成,我们可以手动在 /etc/init.d/ 目录下创建一个标准的启动脚本。5.1使用编辑器创建文件:sudo vim /etc/init.d/vnstat5.2将以下标准的 Alpine init 脚本内容复制进去并保存注意,这里要修改目录位置 /usr/bin/vnstatd改为/usr/sbin/vnstatd:#!/sbin/openrc-run description="vnStat network traffic monitor" command="/usr/sbin/vnstatd" command_args="-n -d" pidfile="/run/vnstat/vnstat.pid" command_user="vnstat:vnstat" depend() { need net use logger }保存退出。5.3赋予这个脚本可执行权限sudo chmod +x /etc/init.d/vnstat5.4创建必要的运行目录vnstat 需要一个专门的目录来存放进程文件和数据。手动创建并确保权限正确:# 创建 pid 目录 sudo mkdir -p /run/vnstat # 创建 vnstat 的数据库目录(如果不存在的话) sudo mkdir -p /var/lib/vnstat # 确保 vnstat 用户(如果存在)拥有这些目录的权限 # 如果提示用户不存在,可以先跳过 chown,或者先创建 vnstat 用户 sudo chown -R vnstat:vnstat /run/vnstat /var/lib/vnstat 2>/dev/null || true5.5再次尝试启动现在 /etc/init.d/ 下已经有了 vnstat 脚本,你可以再次运行之前的命令了sudo rc-service vnstat start sudo rc-update add vnstat default三 Serverstat使用vnstat1 修改VPS的/etc/init.d/stat_client文件,在 command_args 末尾添加 -n 参数。command_args="-a 'http://al.fvars.com:8080/report' -u server-alcdt -p 87887191 -n &"2 加载修改文件并重启客户端service stat_client restart3 到这里就配置成功了演示地址http://ss.5var.com
2026年05月17日
32 阅读
0 评论
0 点赞
2026-05-17
Alpine上Server-Rust的手动安装教程
一 前言之前介绍了ServerStat在Linux VPS的安装配置、采用Vnstat来防止重启导致数据丢失的问题,以及如何在安装了openwrt的n1旁路由上安装Serverstat,以及如何在LiNUX VPS上手动安装Server-Rust,需要的可以访问之前的博文:1)随时随地监控你的VPS状态——Serverstat部署折腾之路2)Serverstaus改用Vnstat统计VPS流量,避免服务器重启引起统计丢失3)N1折腾之openwrt安装ServerStatus_Rust客户端4)LiNUX VPS上Server-Rust的手动安装教程博主最近购买了阿里云国际的CDT作为上网备用,限于其配置,只有468M内存和2G硬盘,无法安装debian,因此采用体积和内存占用更小的alpine。但alpine系统部分组件和命令与debian不同,按原文的安装方法无法安装。本文介绍下如何在Alpine上手动安装Server-Rust client客户端(client即发送流量信息的VPS,server即收集流量信息并汇总展示的VPS),一般1台服务器作为服务器端和客户端,其他VPS作为客户端。二 stat_client客户端安装教程1 /opt目录下创建ServerStat目录mkdir -p /opt/ServerStatus && cd /opt/ServerStatus2 下载stat_client客户端到官方地址下载根据自己的服务器内核选择合适的客户端版本,这里以x86 64位的Linux为例:wget --no-check-certificate -qO client-x86_64-unknown-linux-musl.zip https://github.com/zdz/ServerStatus-Rust/releases/download/v1.8.1/client-x86_64-unknown-linux-musl.zip3 解压缩unzip -o client-x86_64-unknown-linux-musl.zip4 修改stat_client的权限chmod +x stat_client5 复制stat_client.service到/etc/init.d/,并改名为stat_clientmv -v stat_client.service /etc/init.d/stat_client6 替换 /etc/init.d/stat_client 文件用下面的代码替换stat_client中的内容,并将IP改为你服务器的IP或你的域名,注意这里的-u后的用户名、-p后面的密码,与上面config.toml中的name、password必须一致,否则会通讯不成功。#!/sbin/openrc-run name="ServerStatus-Rust Client" description="Client for ServerStatus-Rust" command="/opt/ServerStatus/stat_client" command_args="-a 'http://ss.vvars.com:8080/report' -u h1 -p p1 &" command_user="root:root" directory="/opt/ServerStatus" depend() { need net } start_pre() { ebegin "Starting ${name}" } stop_pre() { ebegin "Stopping ${name}" }同时修改stat_client的权限chmod +x /etc/init.d/stat_client7 将 stat_client加入系统服务rc-update add stat_client default8 启动服务service stat_client start10 查看状态,显示running即为成功service stat_client status11 其他命令service stat_client stop 停止客户端服务 service stat_client restart 重启客户端服务
2026年05月17日
52 阅读
1 评论
0 点赞
2025-08-22
在用户的浏览器里挖矿——Anubis 网站防护工具配置教程
一、项目背景Anubis工作模式类似于Cloudflare的Javascript挑战,拦截请求之后,用户需要通过挑战之后才能继续访问。而Anubis需要客户端完成一定难度的Hash计算,简单说就是挖矿。客户端需要进行一定负载的计算,计算出正确结果之后才能进入网站。这对于正常用户的客户端来说并不算是什么,在难度2-4下,大概率计算时间小于2秒钟,一闪而过用户感知小。在难度5-6时,浏览器需要进行10-30秒以上的计算。在CC攻击的时候,攻击者会控制大量的无头浏览器进行攻击,使用Anubis之后,会在攻击者的无头浏览器中执行Hash计算,高难度的Hash计算会拖垮攻击者的服务器,从而降低攻击频率。项目官网我在本地Debian12 + NGINX系统中已经跑通,随后我会发表一篇博客详细描述配置PS;Anubis有非常强大的功能,包括针对不用GEOIP、不同AS的规则,正在进一步探索中。PPS;试了下难度设置为6,大概1分钟才计算完成,期间CPU(i5-13490H)占用80%左右。二、工作原理1 AnubisAnubis是一个网站防护工具,其工作原理类似常见的Cloudflare验证,会在用户进入网站之前对客户端进行检查。客户端需要完成一定难度的Hash计算,服务器验证计算结果后放行,Hash计算代表了客户端可能需要执行几千几万次的计算,而服务器验证执行执行一次,对服务器开销小。当有网络爬虫、CC攻击想进入源站是,需要在攻击者的客户端(比如无头浏览器中)进行一定量的Hash计算,攻击者一般会在一台物理机中运行多个配置了代理的无头浏览器,这些Hash计算会拖垮攻击者的服务器,从而迫使攻击者放弃或减低攻击频率。现代设备通常都具有一定的限制算力,这些任务对于这些客户端来说,通常只需要几毫秒或几秒中即可完成,用户只需要等待一段时间,不需要进行任何操作,成功后会自动进入实际后端服务。2.工作原理Hash计算和经典的比特币挖矿一致,客户端需要使用一个确定的字符串加上任意数字,进行 sha256 计算,得到的 64 为hash值的前x个数为 0,x就是difficultyconst hash = await sha256(`${challenge}${nonce}`);整体流程客户端第一次访问时,会根据访问者的IP、ASN、User-Agent,服务器的工作负载,计算出一个数值 weight,之后通过 weight 匹配不同难度的Hash计算任务给客户端。客户端完成计算后,由服务器进行验证,成功之后放行到真正的后端服务,同时返回 Set-Cookies 以保存一段时间验证结果,当用户下次访问时,可复用上次的验证结果。3.与NGINX搭配![[Pasted image 20250821210211.png]]流量从 80/443 端口进入之后,先交给Anubis进行拦截,延迟完成之后在交还回NGINX进行后续流程。在单个服务器内通过unix socks进行交互。三、安装/配置教程此处以Debian 12 系统为例1 安装Anubis1)下载并安装(1)请在Github获取最新的版本号wget -O /tmp/anubis.deb https://github.com/TecharoHQ/anubis/releases/download/v1.21.3/anubis_1.21.3_amd64.deb && apt install /tmp/anubis.deb(2)不能直连Github,可以使用加速域名,或者手动下载上传到服务器wget -O /tmp/anubis.deb https://ghfast.top/https://github.com/TecharoHQ/anubis/releases/download/v1.21.3/anubis_1.21.3_amd64.deb && apt install /tmp/anubis.deb(3)修改 /etc/anubis/default.env,内容如下BIND=/run/anubis/instance.sock BIND_NETWORK=unix SOCKET_MODE=0666 TARGET=unix:///run/nginx/nginx.sock(4)复制默认策略文件,暂不修改cp /usr/share/doc/anubis/botPolicies.yaml /etc/anubis/botPolicies.yaml2)systemd运行(1)创建service文件vi /etc/systemd/system/anubis.service[Unit] Description=Anubis Bot Protection After=network.target [Service] EnvironmentFile=/etc/anubis/default.env ExecStart=/usr/bin/anubis \ -bind /run/anubis/instance.sock \ -bind-network unix \ -socket-mode 0666 \ -target unix:///run/nginx/nginx.sock \ -metrics-bind 127.0.0.1:9091 \ -metrics-bind-network tcp \ -policy-fname /etc/anubis/botPolicies.yaml Restart=always User=www-data Group=www-data [Install] WantedBy=multi-user.target(2)创建目录mkdir -p /run/anubis /run/nginx(3)修改权限此处的用户和NGINX相同chown www-data:www-data /run/anubis /run/nginx(4)启用Anubissystemctl enable --now anubis.service(5)确保已经成功运行systemctl status anubis2 配置NGINX此处提供一份可用NGINX,请自行修改扩展user root; worker_processes auto; pid /run/nginx.pid; events { worker_connections 1024; } http { upstream anubis { server unix:/run/anubis/instance.sock; } server { listen 443 ssl http2; server_name uptime.vio.vin; ssl_certificate /etc/ssl/violet/certs/all.vio.vin.cert.pem; ssl_certificate_key /etc/ssl/violet/certs/all.vio.vin.key.pem; location / { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_pass http://anubis; } } server { listen unix:/run/nginx/nginx.sock; server_name uptime.vio.vin; location / { proxy_pass http://10.115.15.178:3001; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } }upstream:定义上游服务器为anubis第一个server:监听 443 入站连接,传输给anubis,传输客户端IP用于IP相关策略判断第二个server:anubis验证通过之后,实际反向代理的位置至此,基础配置已完成,默认情况下低分析客户端难度为 2,高风险为 43 Bot策略官网文档:https://anubis.techaro.lol/docs/admin/policies需要调整 botPolicies.yaml 文件默认的botPolicies.yaml 配置文件:https://github.com/TecharoHQ/anubis/blob/main/data/botPolicies.yamlbots中定义了多个规则,可以看到已经通过import导入了一部分规则,这部分的文件可以在 /usr/share/doc/anubis/data/bots 中找到默认的规则如下,可以仿照这些规则写自己的规则1)可配置匹配规则(1)匹配请求头/usr/share/doc/anubis/data/bots/cloudflare-workers.yaml- name: cloudflare-workers headers_regex: CF-Worker: .* action: WEIGH weight: adjust: 15(2)匹配User-Agent/usr/share/doc/anubis/data/bots/headless-browsers.yaml- name: lightpanda user_agent_regex: ^LightPanda/.*$ action: DENY - name: headless-chrome user_agent_regex: HeadlessChrome action: DENY - name: headless-chromium user_agent_regex: HeadlessChromium action: DENY(3)指定表达式/usr/share/doc/anubis/data/bots/aggressive-brazilian-scrapers.yaml- name: deny-aggressive-brazilian-scrapers action: WEIGH weight: adjust: 20 expression: any: # Internet Explorer should be out of support - userAgent.contains("MSIE") # Trident is the Internet Explorer browser engine - userAgent.contains("Trident") # Opera is a fork of chrome now - userAgent.contains("Presto") # Windows CE is discontinued - userAgent.contains("Windows CE") # Windows 95 is discontinued - userAgent.contains("Windows 95") # Windows 98 is discontinued - userAgent.contains("Windows 98") # Windows 9.x is discontinued - userAgent.contains("Win 9x") # Amazon does not have an Alexa Toolbar. - userAgent.contains("Alexa Toolbar") # This is not released, even Windows 11 calls itself Windows 10 - userAgent.contains("Windows NT 11.0") # iPods are not in common use - userAgent.contains("iPod")(4)匹配客户端IP/usr/share/doc/anubis/data/clients/mistral-mistralai-user.yaml# Acts on behalf of user requests # https://docs.mistral.ai/robots/ - name: mistral-mistralai-user user_agent_regex: MistralAI-User/.+; \+https\://docs\.mistral\.ai/robots action: ALLOW # https://mistral.ai/mistralai-user-ips.json remote_addresses: [ "20.240.160.161/32", "20.240.160.1/32", ](5)匹配GEOIP- name: countries-with-aggressive-scrapers action: WEIGH geoip: countries: - BR - CN weight: adjust: 10(6)匹配ASN- name: aggressive-asns-without-functional-abuse-contact action: WEIGH asns: match: - 13335 # Cloudflare - 136907 # Huawei Cloud - 45102 # Alibaba Cloud weight: adjust: 10(7)匹配后动作动作 解释ALLOW 允许,跳过后续所有检查DENY 拒绝访问CHALLENGE 进行客户端挑战WEIGH 修改请求权重ALLOW和DENY不再解释2)CHALLENGE- name: generic-bot-catchall user_agent_regex: (?i:bot|crawler) action: CHALLENGE challenge: difficulty: 16 # impossible report_as: 4 # lie to the operator algorithm: slow # intentionally waste CPU cycles and timename:名称,可自定义user_agent_regex:正则表达式匹配User-Agentaction:动作,立即进行客户端挑战challenge:客户端挑战配置difficulty:难度,16 表示计算出的hash值前 16 位为 0,不可能完成(比特币的前导 0 个数为 19-20),在客户端完成 16 为的计算可能需要几万年甚至更久(攻击者看者 99%的CPU陷入沉思)report_as:用户在界面上看到的难度数值(你甚至可以骗他,这个进度条怎么一直卡在 99%不走呢)algorithm:采用的Hash算法,slow故意折磨CPU3)WEIGH调整请求的权重,正数为增加权重,负数为减少权重,后续会进入到 thresholds 中,针对不同的请求设置不同的CHALLENGE0-10 的权重,进行快速算法,几乎不需要等待- name: mild-suspicion expression: all: - weight > 0 - weight < 10 action: CHALLENGE challenge: algorithm: metarefresh difficulty: 2 report_as: 24)其他根据服务器负载动态调整示例在配置文件中已给出,有需要可以启用 # ## System load based checks. # # If the system is under high load, add weight. # - name: high-load-average # action: WEIGH # expression: load_1m >= 10.0 # make sure to end the load comparison in a .0 # weight: # adjust: 20 ## If your backend service is running on the same operating system as Anubis, ## you can uncomment this rule to make the challenge easier when the system is ## under low load. ## ## If it is not, remove weight. # - name: low-load-average # action: WEIGH # expression: load_15m <= 4.0 # make sure to end the load comparison in a .0 # weight: # adjust: -10
2025年08月22日
331 阅读
0 评论
0 点赞
2025-06-12
适合"养老"的网站收藏夹导航——基于Astro的导航站主题,支持 Vercel 和 Cloudflare Pages一键部署
1 前言源码来源于Nodeseek的zywe,源码地址。演示地址:dh.zywe.de关于xwnav-theme源码的简介:人人都能搭建的简洁美观收藏夹网站。不仅仅是简单的链接集合,更是智能化的导航平台,让您只需专注于内容管理而非技术细节,**只需编辑一个数据文件,所有功能都会自动更新,极大简化了维护工作,打包后部署超轻量化(1-2mb)。🌟 独特优势🤖 自动化功能,让您只需专注于内容管理而非技术细节,只需修改一个数据文件(src/data/navLinks.js),所有功能都会自动更新,极大简化了维护工作自动化功能🖼️ 自动图标获取:添加新网站和新分类时无需手动下载图标,脚本自动获取并优化图标引用图标一条龙📑 自动分类导航:侧边栏分类导航会根据数据文件自动更新,无需手动修改HTML🔎 自动搜索索引:搜索功能会自动检测新增网站和分类,无需额外配置🃏 自动卡片生成:网站卡片布局会自动适应新增内容,保持一致的视觉效果🎨 自动主题切换:根据用户系统配置自动切换暗色/亮色主题🧹 自动清理图标:图标管理脚本会自动清理未使用的图标文件,保持项目整洁📱 自动响应式适配:无需编写额外代码,完美适配各种设备屏幕🗺️ 自动生成站点地图:每次构建项目自动生成robots.txt和sitemap.xml📝 自动SEO元数据:每次构建项目自动生成和管理SEO相关的元标签等等代码🟢灯塔PageSpeed Insights2🌈 主要特点🏷 简洁直观的界面:分类清晰,操作便捷🔍 智能搜索功能:快速查找您需要的网站📎 双分类导航栏:主页横向导航+侧边导航📃 卡片式网站展示:直观美观,一目了然🔄 自动化工作流:减少手动操作,提高效率🌓 暗色模式:智能切换暗色/亮色模式⏱️ 快速返回顶部:一键回到顶部的便捷按钮🚀 快速加载:基于Astro框架构建,性能卓越📸 图片懒加载:提升加载速度和用户体验🔊 流畅的动画过渡:提升用户界面交互体验💻 智能顶部栏: 上滑展出,下滑收缩不挡视野🙌 人性化设计: 搜索框侧边栏可点空白处退出🌤️ 实时天气显示:集成API实时获取当地天气📱 响应式布局:适配所有设备屏幕🔒 无需数据库:纯静态设计,无需数据库🔑 隐藏链接地址:悬停在卡片,不显示链接地址💾 Island岛屿架构按需加载:动态组件独立渲染,提升加载速度静态首屏:首屏纯静态生成,并行加载交互组件延迟水合:交互元素延迟水合,减少首屏阻塞查询优先:搜索和导航操作优先渲染浏览器缓存:利用存储机制优化重复访问3🎶 部署教程推荐:本地Windows开发 + Linux服务器部署:本地开发和构建,仅将执行构建命令后的dist目录部署到服务器3.1 git 拉取git clone https://github.com/zywe03/astro-nav-theme.git(或者下载压缩包源码解压)3.2 windowns安装Node.js 环境安装 Node.js 18.0+ (推荐LTS版本)官网Windows用户:直接从官网下载安装包3.3 包管理器选择启用 pnpm(轻量、高效)corepack enable corepack prepare pnpm@latest --activate3.4 开始安装# 安装依赖 pnpm i # 浏览器实时看效果 pnpm dev # 自动下载图标 npx tsx .\icon-system\0icon.ts # 打包构建生成/dist目录 pnpm build3.5 上传/dist目录到服务器,nginx反代4 借助AI导入导航数据第一次导入大量网址链接,借助AI快速生成网站导航内容(强烈建议)列出想要生成的网站所属分类,名称或网站,短和长描述让AI生成,节省工作量AI提示词:统一分类opensource 网站: github baidu.com 谷歌 具体按照以下样式生成,使用“JavaScript风格格式+单引号”,不要添加"icon字段"和"[]"" { id: 'github', title: 'GitHub', description: '全球最大的开源代码托管平台,支持 Git 版本控制,适用于协作开发、项目管理和自动化工作流,是开发者共享与协作的核心工具。' shortDesc: '代码托管平台。', url: 'https://github.com/', category: 'opensource', }, 描述根据网站实际内容,专业,准确,介绍背景独特优势等等,不要太刻板,臃肿,重复插入数据文件navLinks.js后 执行npx tsx .\icon-system\0icon.ts自动下载图标,即可完成,大量导航网站导入5 💬 日常使用关键文件和目录说明5.1 核心数据文件src/data/navLinks.js: 存储所有网站数据和分类信息,是最常修改的文件,包含网站信息和分类定义5.2 图标存储public/icons/: 存储所有网站图标public/icons/category/: 存储分类图标public/icons/downloaded_sites/: 临时下载目录(自动清理)public/icons/downloaded_categories/: 临时下载目录(自动清理)5.3 📝 增删网站和分类修改 src/data/navLinks.js 文件即可管理所有网站和分类建议统一用一种格式JavaScript风格格式+单引号,避免脚本错误识别5.3.1 添加新分类在 categories 数组中添加新分类:⚠️ 注意:不要手动添加icon字段,不要icon""字段留空,都会导致图标无法自动下载添加icon字段,手动自定义图标除外export const categories = [ // 分类注释 { id: new, //分类ID name: '新分类名称',icon: '/icons/category/new-category.svg' // 分类图标也支持自动生成,基于name的首字生成 } ];5.3.2 添加新网站在 sites 数组中添加新网站:export const sites = [ { id: 'github', // 网站ID title: 'GitHub', // 网站名称 description: '全球最大代码托管平台。', // 网站描述 shortDesc: '代码托管平台。', // 简短描述 url: 'https://github.com/', // 网站链接(包含完整协议(`http://`或`https://`)) category: 'opensource', // 所属分类 ID(必须对应分类中的id) // 注意:不需要添加icon字段,脚本会自动处理 }, ];5.3.3 网站和分类排序一句话调顺序即可分类排序: 调整 categories 数组中分类的顺序即可改变分类的显示顺序网站排序: 调整 sites 数组中网站的顺序即可改变网站的显示顺序生成后插入navLinks.js即可5.4 🖼️ 图标下载脚本使用指南✅ navLinks.js使用“JavaScript风格格式+单引号”,不要添加"icon字段" 由于是静态网站,建议全部图标在构建时下载图标引用使用步骤:首先在 src/data/navLinks.js 中添加好新网站或分类一键执行:# 终端复制粘贴回车 npx tsx .\icon-system\0icon.ts5.5 🔗 修改友情链接和按钮✅使用vscode搜索文本记得修改可快速找到全部需要自定义的内容(强烈建议搜索)5.5.1 修改友情链接和页脚声明位于页脚组件中,修改 src/components/Footer.astro 文件:点开文件一目了然5.5.2 修改网站大标题(名称)和logo修改src\components\LogoName.astro独立出来方便修改,点开文件一目了然5.5.3 修改全部图标default.svg导航网站三级回退机制保底图标logo.png网站社交媒体分享图片logo.svg网站主图标准备您的图标文件(修改图片,但使用固定命名)替换图标文件放入 public\images 目录即可5.5.4 提交站点地图只需要向搜索引擎提交 https://xxx.com/sitemap-index.xml 这一个文件
2025年06月12日
229 阅读
0 评论
0 点赞
2025-05-27
Google AdSense 国内提现教程:首选无手续费的招商银行
一.前言大家都知道,Google Adsense 在收益达到 100 美元后,便会自动使用电汇付款到绑定的银行卡。目前本站每天都有不到1美元的收益,日积月累,很快也到100美元的支付门槛了,但因为迟迟没有办理具有接受外汇的银行卡,导致推迟到现在才把这些流程搞定,而且收到了来自 Google Adsense 的首笔付款。今天就梳理一下我从办理银行卡到收到来自 Google Adsense 首笔打款的经历,同时也方便为自己做个记录,希望对大家有所帮助。二、adsense设置国内银行卡收款2.1 办理可以接收外汇的银行卡并非所有的银行卡均支持接受外汇,使用前请询问发卡地银行是否支持。关于手续费与合同的问题,我发现每个地方的政策都不一样。有些银行可能会存在手续费或是要求提供合同,有点麻烦。基于个人经验,本地的招商银行并未要求提供任何的合同也不存在任何的手续费用。这点,其实可以在询问银行卡能否接收外汇的时候一并问一下。 博主办理的是招行储蓄卡,因为免手续费,没有的小伙伴先申请一张招商银行一卡通。注意:银行卡必须为一类账户,二类及以下账户没有收款外币权限。开通网银和手机银行。招行的收款信息如下:收款行信息(招商银行总行) 银行名称(英文): China Merchants Bank 银行地址(英文):China Merchants Bank Tower NO.7088, Shennan Boulevard, Shenzhen, China 银行 SWIFT 代码: CMBCCNBS 收款人名称: 开户证件姓名的汉语拼音 收款人账号: 一卡通卡号2.2 填写 Adsense 付款方式登录 Google AdSense 管理后台点击 付款 > 付款信息 > 管理付款,添加付款方式。在付款页面可以根据下面信息来填写:付款人 ID(可选):不用填 银行账户上的姓名:Ma Baoguo(姓名拼音,大写,姓和名之间空格) 银行名称:China Merchants Bank(招行总行,不管哪个地方办理的卡都一样) SWIFT BIC:CMBCCNBS 账号:招商银行一卡通卡号 勾选设为主要付款方式 填写完成后,点击保存即可!2.3 等待AdSense 付款注意付款方式添加完成后并不会立刻就付款过来,需要等到余额达到 $100 后,谷歌 AdSense 固定在每个月 21 日(中国时间 22 日)发起付款,1-3 工作日可收到汇款。注意:一般来说 Google Adsense 款项在放款当天算起的 5 个工作日内会到达银行,银行再逐级向下放款,最终才会到达你的银行帐号。不要太着急,十来天到账也很正常。就像此次,我的收款正好赶上五一黄金周假期,假期肯定是没有办法到账,假期一过就到账了。三.招行 APP 结汇我们收到的汇款是美元,需要结汇成人民币,然后才能提现。下载安装登陆招商银行一卡通 APP,找到【外汇结汇】,点开后点击【去结汇】,在【结汇委托】界面:卖出货币:选择美元现汇 结汇资金来源:选择【其他经常转移】或【职工报酬和赡家款】 结汇金额:输入要结汇的金额 最后点击确定,输入密码即可成功结汇,结汇后的人民币就自动打入银行卡。另外需要注意每个人年度结汇总额度为 $50000,如果超出可到银行柜台申请额度。结汇业务办理时间是 8:30-22:00。到此为止,我们就可以通过 Google AdSense 赚取美元,然后结汇成人民币,最后提现到银行卡了。
2025年05月27日
209 阅读
0 评论
0 点赞
2025-05-02
给自己网站增加一个定位插件——调用美团API定位到访者的IP地址
1 前言美团通过IP地址可以快速定位,利用美团API可以给网站增加一个定位到访者的插件。美团API地址为:https://apimobile.meituan.com/locate/v2/ip/loc?rgeo=true&ip=。本文介绍如何调用美团API定位到访者的IP地址,给自己网站增加一个定位插件。2 部署教程2.1 新建ip.php文件在网站目录下新建ip.php文件,如可以选择在子目录tools下新建ip.php文件,其代码如下:<?php if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ip'])) { $ip = $_POST['ip']; $ipData = json_decode(file_get_contents("https://apimobile.meituan.com/locate/v2/ip/loc?rgeo=true&ip=" . urlencode($ip)), true); if (!$ipData || !isset($ipData['data']['lat'])) exit(json_encode(['success' => false])); $lat = $ipData['data']['lat']; $lng = $ipData['data']['lng']; $rgeo = $ipData['data']['rgeo']; $cityData = json_decode(file_get_contents("https://apimobile.meituan.com/group/v1/city/latlng/{$lat},{$lng}?tag=0"), true)['data'] ?? []; exit(json_encode(['success' => true, 'ip' => $ip, 'lat' => $lat, 'lng' => $lng, 'country' => $rgeo['country'] ?? '', 'province' => $rgeo['province'] ?? '', 'city' => $rgeo['city'] ?? '', 'district' => $rgeo['district'] ?? '', 'detail' => $cityData['detail'] ?? ''])); } ?> <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"><title>IP Locator</title><meta name="viewport" content="width=device-width,initial-scale=1"> <script src="https://cdn.tailwindcss.com"></script> <link href="https://fastly.jsdelivr.net/npm/
[email protected]
/dist/leaflet.min.css" rel="stylesheet"/> <script src="https://fastly.jsdelivr.net/npm/
[email protected]
/dist/leaflet.min.js"></script> </head> <body class="bg-slate-50 font-sans p-3 md:p-6"> <div class="max-w-4xl mx-auto"> <h1 class="text-xl font-medium mb-6 text-center text-gray-700">访客地址</h1> <div class="grid md:grid-cols-2 gap-4" id="cards"></div> <div class="text-center text-xs text-gray-400 mt-6">Powered by <a href="https://www.Vvars.com">V+变量建站日记</a></div> </div> <script> (async () => { const sources = [ {id: 'f', url: 'https://ipv4.lvhai.org/', label: '代理IP', color: '#3b82f6'}, {id: 'd', url: 'https://ipv4_cu.itdog.cn/', label: '访客地址', color: '#10b981'} ]; // Create cards & fetch IPs sources.forEach(s => { document.getElementById('cards').innerHTML += ` <div class="bg-white rounded-lg shadow-sm border border-gray-100 overflow-hidden"> <div class="px-3 py-2 border-b border-gray-100 flex items-center justify-between"> <h2 class="text-sm font-medium text-gray-700">${s.label}</h2> <div class="h-2 w-2 rounded-full" style="background:${s.color}"></div> </div> <div id="${s.id}-content" class="p-3 text-sm"> <div class="animate-pulse h-4 w-20 bg-gray-200 rounded"></div> </div> <div id="${s.id}-map" class="h-40 rounded-md mt-2 hidden"></div> </div>`; // Process IP (async () => { try { // Get IP const ip = await fetch(s.url).then(r => s.url.includes('lvhai') ? r.text().then(t => { try { return JSON.parse(t).ip || t.trim(); } catch { return t.trim(); } }) : r.json().then(j => j.ip)).catch(() => null); if (!ip) { document.getElementById(`${s.id}-content`).innerHTML = `<div class="text-red-500">Failed to get IP</div>`; return; } document.getElementById(`${s.id}-content`).innerHTML = `<div class="font-mono text-gray-600">IP: ${ip}</div>`; // Get location const data = await fetch(location.href, { method: 'POST', headers: {'Content-Type': 'application/x-www-form-urlencoded'}, body: `ip=${encodeURIComponent(ip)}` }).then(r => r.json()); if (!data.success) { document.getElementById(`${s.id}-content`).innerHTML += `<div class="text-red-500 text-xs mt-1">Location failed</div>`; return; } // Update content document.getElementById(`${s.id}-content`).innerHTML = ` <div class="font-mono text-gray-600">IP: ${ip}</div> <div class="grid grid-cols-2 gap-x-2 gap-y-1 text-xs mt-2"> <div><span class="text-gray-500">国家:</span> ${data.country||'—'}</div> <div><span class="text-gray-500">省区:</span> ${data.province||'—'}</div> <div><span class="text-gray-500">城市:</span> ${data.city||'—'}</div> <div><span class="text-gray-500">区县:</span> ${data.district||'—'}</div> </div>`; // Show map with CARTO basemap const mapEl = document.getElementById(`${s.id}-map`); mapEl.classList.remove('hidden'); const map = L.map(mapEl, {zoomControl: false, attributionControl: false}).setView([data.lat, data.lng], 10); L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', { subdomains: 'abcd' }).addTo(map); L.circleMarker([data.lat, data.lng], {radius: 6, color: s.color, weight: 2, fillOpacity: 0.3}).addTo(map); setTimeout(() => map.invalidateSize(), 100); } catch (err) { document.getElementById(`${s.id}-content`).innerHTML = `<div class="text-red-500">Error: ${err.message}</div>`; } })(); }); })(); </script> </body> </html>2.2 在网站模板中加入调用代码可以采用iframe调用,示例代码如下:<iframe frameborder=0 src="https://www.vvars.com/tools/ip.php" style="border-radius:8px; height: 300px; transform: scale(0.85); transform-origin: top left;"></iframe>代码参考,需要自行调整height和scale数值。3 最终效果IP显示:https://www.vvars.com/tools/ip.php网站调用显示:https://www.vvars.com/Website-construction/Add-a-location-plug-in-to-your-website---call-Meituan-API-to-locate-the-visitor-s-IP-address.html
2025年05月02日
410 阅读
0 评论
0 点赞
1
2
...
11