安装Listmonk邮件营销系统

一、安装软件

pacman -U listmonk-bin-5.0.2-1-x86_64.pkg.tar.zst

二、配置 postgresql

创建目录并设置权限:

mkdir -p /srv/postgres
chown -R postgres:postgres /srv/postgres
chmod 700 /srv/postgres

用 postgres 用户初始化数据库群集

su -l postgres -c "initdb --locale=C.UTF-8 --encoding=UTF8 -D '/srv/postgres/data'"'"

告诉 systemd 使用新 PGDATA

nano -w /usr/lib/systemd/system/postgresql.service

会打开编辑器,写入以下内容:

[Service]
Environment=PGDATA=/srv/postgres
PIDFile=/srv/postgres/data/postmaster.pid

重新加载 systemd 并启动:

systemctl daemon-reload
systemctl start postgresql
systemctl enable postgresql   # 若需要开机自启

三、初始化数据

$ sudo -u postgres psql
postgres=# CREATE USER listmonk WITH PASSWORD '<your_password>';
postgres=# CREATE DATABASE listmonk WITH OWNER listmonk;
postgres=# \q

编辑软件配置

nano -w /etc/listmonk/config.toml

password = "xxxx"

初始化数据

sudo -u listmonk listmonk --config /etc/listmonk/config.toml --install

四、启动服务

systemctl enable listmonk && systemctl start listmonk

五、访问

https://ip:9000 创建你的管理员账号和密码

发表在 Linux | 安装Listmonk邮件营销系统已关闭评论

Proxmox KVM 模版虚拟机的Cloud-init配置

一、安装软件包

# 1. 完全卸载
apt-get purge -y cloud-init
apt-get autoremove -y

# 2. 清理残留
rm -rf /etc/cloud
rm -rf /var/lib/cloud

# 3. 更新软件源
apt-get update

# 4. 重新安装
apt-get install -y cloud-init

# 5. 重新加载 systemd
systemctl daemon-reload

二、修改配置

# The top level settings are used as module
# and system configuration.
# A set of users which may be applied and/or used by various modules
# when a 'default' entry is found it will reference the 'default_user'
# from the distro configuration specified below
users:
   - name: root
     lock_passwd: false


# If this is set, 'root' will not be able to ssh in and they
# will get a message to login instead as the default $user
disable_root: false

# This will cause the set+update hostname module to not operate (if true)
preserve_hostname: false

ssh_pwauth: true
chpasswd:
  expire: false

apt:
   # This prevents cloud-init from rewriting apt's sources.list file,
   # which has been a source of surprise.
   preserve_sources_list: true

# If you use datasource_list array, keep array items in a single line.
# If you use multi line array, ds-identify script won't read array items.
# Example datasource config
# datasource:
#    Ec2:
#      metadata_urls: [ 'blah.com' ]
#      timeout: 5 # (defaults to 50 seconds)
#      max_wait: 10 # (defaults to 120 seconds)
datasource_list: [ NoCloud, ConfigDrive ]

# The modules that run in the 'init' stage
cloud_init_modules:
 - seed_random
 - bootcmd
 - write-files
 - growpart
 - resizefs
 - disk_setup
 - mounts
 - set_hostname
 - update_hostname
 - update_etc_hosts
 - ca-certs
 - rsyslog
 - users-groups
 - ssh

# The modules that run in the 'config' stage
cloud_config_modules:
 - snap
 - ssh-import-id
 - keyboard
 - locale
 - set-passwords
 - resolv-conf 
 - grub-dpkg
 - apt-pipelining
 - apt-configure
 - ntp
 - timezone
 - disable-ec2-metadata
 - runcmd
 - byobu

# The modules that run in the 'final' stage
cloud_final_modules:
 - package-update-upgrade-install
 - fan
 - landscape
 - lxd
 - write-files-deferred
 - puppet
 - chef
 - mcollective
 - salt-minion
 - reset_rmc
 - scripts-vendor
 - scripts-per-once
 - scripts-per-boot
 - scripts-per-instance
 - scripts-user
 - ssh-authkey-fingerprints
 - keys-to-console
 - install-hotplug
 - phone-home
 - final-message
 - power-state-change

# System and/or distro specific settings
# (not accessible to handlers/transforms)
system_info:
   # This will affect which distro class gets used
   distro: debian
   # Default user name + that default users groups (if added/used)
   default_user:
     name: root
     lock_passwd: false
     shell: /bin/bash
   # Other config here will be given to the distro class and/or path classes
   paths:
      cloud_dir: /var/lib/cloud/
      templates_dir: /etc/cloud/templates/
   package_mirrors:
     - arches: [default]
       failsafe:
         primary: https://deb.debian.org/debian
         security: https://deb.debian.org/debian-security
   ssh_svcname: ssh

三、WHMCS中一定要选择生成key,因为默认模版会删除key,每台机器都会自动生成,防止安全隐患

dpkg-reconfigure openssh-server

四、清除临时文件,并且打包上传

# 清理 cloud-init
cloud-init clean --logs --seed

# 清理 SSH 密钥
rm -f /etc/ssh/ssh_host_*

# 清理 machine-id
truncate -s 0 /etc/machine-id

# 清理历史
history -c

# 写入DNS配置
cat > /etc/cloud/cloud.cfg.d/99_custom_dns.cfg << 'EOF'
manage_resolv_conf: true
resolv_conf:
  nameservers: ['8.8.8.8', '1.1.1.1']
  searchdomains: ['local']
  domain: fortu.cfd

bootcmd:
  - [ cloud-init, single, --name, cc_resolv_conf, --frequency, always ]

runcmd:
  - rm -f /etc/resolv.conf
  - echo "nameserver 8.8.8.8" > /etc/resolv.conf
  - echo "nameserver 1.1.1.1" >> /etc/resolv.conf
  - echo "search fortu.cfd local" >> /etc/resolv.conf
EOF

# 关机
halt

然后把文件拷贝出来即可

五、有些服务器要默认启动

systemctl enable sshd

六、安装计算机上

qm importdisk 100 debian12.qcow2 local
qm set 100 --scsi0 local:vm-100-disk-0
qm set 100 --ide0 local:cloudinit

发表在 Linux | Proxmox KVM 模版虚拟机的Cloud-init配置已关闭评论

修改Proxmox原始模板文件

一、解压现有模板

# 进入模板目录
cd /var/lib/vz/template/cache

# 解压模板(以Ubuntu为例)
mkdir temp_template
cd temp_template

# 解压ubuntu
zstd -d -c ../ubuntu-24.10-standard_24.10-1_amd64.tar.zst | tar -xf -
# 解压debian
zstd -d -c ../debian-13-standard_13.1-1_amd64.tar.zst | tar -xf -

二、修改模板内容

# 修改SSH配置
nano etc/ssh/sshd_config

添加配置

PermitRootLogin yes
PasswordAuthentication yes
PubkeyAuthentication yes

三、重新打包模板

# 重新打包ubuntu
tar -cf - * | zstd -19 -T0 > ../ubuntu-24.10-standard_24.10-1_amd64.tar.zst
# 重新打包debian
tar -cf - * | zstd -19 -T0 > ../debian-13-standard_13.1-1_amd64.tar.zst

# 清理临时文件
cd ..
rm -rf temp_template
发表在 Linux | 修改Proxmox原始模板文件已关闭评论

VirtFusion WHMCS 开机模块

此模块要求 VirtFusion v1.7.3 或更高版本,因为它是基于该版本开发的。请参阅官方文档。

安装

  1. 发布页 下载最新版本.
  2. 解压缩压缩包的内容,并将 modules 文件夹 上传到你的 WHMCS 安装目录中.

❗ 注意事项 ❗

你必须在 WHMCS 中创建 两个自定义字段 才能让此模块正常工作。
你需要在每一个要使用此模块的产品上配置以下自定义字段。

字段名字段类型描述验证选项仅管理员必须字段显示在订单显示在发票
Initial Operating SystemText BoxSet to whatever you wantLeave BlankLeave Blank
Initial SSH KeyText BoxSet to whatever you wantLeave BlankLeave Blank

你可以运行以下 SQL 查询 来创建这些自定义字段:

-- Insert records for Initial Operating System if they don't already exist
INSERT INTO tblcustomfields
(type, relid, fieldname, fieldtype, description, fieldoptions, regexpr, adminonly, required, showorder, showinvoice,
 sortorder, created_at, updated_at)
SELECT 'product',
       id,
       'Initial Operating System',
       'text',
       '',
       '',
       '',
       '',
       '',
       'on',
       '',
       0,
       UTC_TIMESTAMP(),
       UTC_TIMESTAMP()
FROM tblproducts
WHERE servertype = 'VirtFusionDirect'
  AND NOT EXISTS (SELECT 1
                  FROM tblcustomfields
                  WHERE fieldname = 'Initial Operating System'
                    AND relid = tblproducts.id);

-- Insert records for Initial SSH Key if they don't already exist
INSERT INTO tblcustomfields
(type, relid, fieldname, fieldtype, description, fieldoptions, regexpr, adminonly, required, showorder, showinvoice,
 sortorder, created_at, updated_at)
SELECT 'product',
       id,
       'Initial SSH Key',
       'text',
       '',
       '',
       '',
       '',
       '',
       'on',
       '',
       0,
       UTC_TIMESTAMP(),
       UTC_TIMESTAMP()
FROM tblproducts
WHERE servertype = 'VirtFusionDirect'
  AND NOT EXISTS (SELECT 1
                  FROM tblcustomfields
                  WHERE fieldname = 'Initial SSH Key'
                    AND relid = tblproducts.id);

What does this module change?

This module changes the following things:

  • Adds configurable options to the product configuration page to allow the user to select the operating system and add an ssh key to the initial deployment.

TODO

  • Add post checkout checks to ensure the user has selected an operating system and added a ssh key.
发表在 Linux | VirtFusion WHMCS 开机模块已关闭评论

将 Debian 12 转换为 Proxmox VE

一、准备工作

确保系统是纯净的 Debian 12

最好是全新安装的系统

确保网络连接正常

1.更新系统

apt update && apt upgrade -y

写入主机名

虽然您可以保留将127.0.1.1环回地址映射到主机名的条目,但由于Proxmox VE的集群系统循环遍历所有地址,直到找到一个非环回地址为止,如果不确定,建议从该记录中删除主机名,因为这样可以避免任何歧义。

例如,如果你的IP地址是192.168.15.77,主机名是sgpo01,那么你的/etc/hosts文件可能看起来像:

127.0.0.1       localhost
192.168.15.77   sgpo01.fortu.cfd sgpo01

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

你可以使用hostname命令来测试你的设置是否正确:

hostname --ip-address
192.168.15.77 # 应该返回至少一个非环回IP地址在这里

固化hostname

echo "sgpo01" > /etc/hostname

生效

hostnamectl set-hostname sgpo01.fortu.cfd

验证

hostname --ip-address
192.168.15.77 # should return at least one non-loopback IP address here
reboot

2.安装 Proxmox VE

添加 Proxmox VE 存储库

echo "deb [arch=amd64] http://download.proxmox.com/debian/pve bookworm pve-no-subscription" > /etc/apt/sources.list.d/pve-install-repo.list

添加 Proxmox VE 存储库密钥

wget https://enterprise.proxmox.com/debian/proxmox-release-bookworm.gpg -O /etc/apt/trusted.gpg.d/proxmox-release-bookworm.gpg

# verify
sha512sum /etc/apt/trusted.gpg.d/proxmox-release-bookworm.gpg 
7da6fe34168adc6e479327ba517796d4702fa2f8b4f0a9833f5ea6e6b48f6507a6da403a274fe201595edc86a84463d50383d07f64bdde2e3658108db7d6dc87  /etc/apt/trusted.gpg.d/proxmox-release-bookworm.gpg

更新包列表

apt update && apt full-upgrade

安装内核

apt install proxmox-default-kernel
systemctl reboot

安装 Proxmox VE

apt install proxmox-ve postfix open-iscsi chrony

设置密码并且重启系统

passwd && sync && reboot

访问 Web 界面

重启后,你可以通过浏览器访问 Proxmox VE 的 Web 管理界面:
第一次需要用ip地址登录不知道原因

  • 地址:https://sgpo01.fortu.cfd:8006
  • 用户名:root
  • 密码:你的 root 密码

创建系统模版

# 在 Proxmox 服务器上检查可用的容器模板
pveam update
pveam available

# 查看已下载的模板
ls -la /var/lib/vz/template/cache/

# 下载一些常用模板(如果没有)
pveam download local ubuntu-24.10-standard_24.10-1_amd64.tar.zst
pveam download local debian-13-standard_13.1-1_amd64.tar.zst

后续配置

移除 Debian 内核(可选) 安装完成后,你可以移除原来的 Debian 内核:

apt remove linux-image-amd64 'linux-image-6.1*'
update-grub

删除 os-prober

apt remove os-prober

移除企业版存储库警告(可选) 如果你使用的是免费版本,可以禁用企业版存储库:

echo '#deb https://enterprise.proxmox.com/debian/pve bookworm pve-enterprise' > /etc/apt/sources.list.d/pve-enterprise.list

验证和创建必要的目录结构

# 如果 /etc/pve 现在已挂载但缺少 local 目录
if [ -d "/etc/pve" ] && [ ! -d "/etc/pve/local" ]; then
    echo "创建 local 目录..."
    mkdir -p /etc/pve/local
fi

# 检查是否成功创建
ls -la /etc/pve/

重新初始化单节点集群

# 如果 /etc/pve 现在正常工作
pvecm expected 1

# 启动其他服务
systemctl start pvedaemon
systemctl start pveproxy

# 检查所有服务状态
systemctl status pve-cluster pvedaemon pveproxy

生成 SSL 证书

# 现在 /etc/pve/local 应该存在,生成 SSL 证书
if [ -d "/etc/pve/local" ]; then
    echo "生成 SSL 证书..."
    HOSTNAME=$(hostname -f)
    
    # 生成私钥
    openssl genrsa -out /etc/pve/local/pve-ssl.key 4096
    
    # 生成自签名证书
    openssl req -new -x509 -key /etc/pve/local/pve-ssl.key -out /etc/pve/local/pve-ssl.pem -days 3650 -subj "/CN=$HOSTNAME"
    
    # 设置权限
    chown root:www-data /etc/pve/local/pve-ssl.key /etc/pve/local/pve-ssl.pem
    chmod 640 /etc/pve/local/pve-ssl.key
    chmod 644 /etc/pve/local/pve-ssl.pem
    
    echo "SSL 证书已生成"
    ls -la /etc/pve/local/pve-ssl.*
else
    echo "错误:/etc/pve/local 目录仍不存在"
fi

最终验证

# 重启 pveproxy 服务
systemctl restart pveproxy

# 检查服务状态
systemctl status pveproxy

# 检查端口监听
ss -tlnp | grep 8006

# 测试 Web 界面
curl -k https://localhost:8006

WHMCS的配置

PVE端口映射

#!/bin/bash

# PVE兼容的端口映射方案 - 改进版
# 修复了原脚本的问题并增加了更多功能

set -euo pipefail  # 严格错误处理

echo "=== PVE 端口映射配置向导 (改进版) ==="

# 配置变量
INTERNAL_NETWORK="192.168.100"
BASE_PORT=30000
LOG_FILE="/var/log/pve-port-mapping.log"

# 日志函数
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

# 错误处理
error_exit() {
    log "错误: $1"
    exit 1
}

# 检查权限
check_permissions() {
    if [[ $EUID -ne 0 ]]; then
        error_exit "需要root权限运行此脚本"
    fi
}

# 检查PVE防火墙状态
check_pve_firewall() {
    log "检查 PVE 防火墙状态..."
    
    if systemctl is-active --quiet pve-firewall 2>/dev/null; then
        log "⚠️  PVE防火墙已启用"
        echo "建议方案:使用PVE防火墙 + 最小化iptables规则"
        return 1
    else
        log "✅ PVE防火墙未启用"
        echo "可以使用完整的iptables方案"
        return 0
    fi
}

# 备份现有iptables规则
backup_iptables() {
    local backup_file="/etc/iptables/rules.backup.$(date +%Y%m%d_%H%M%S)"
    mkdir -p /etc/iptables
    
    log "备份现有iptables规则到: $backup_file"
    iptables-save > "$backup_file" || error_exit "备份iptables规则失败"
}

# 方案1:PVE防火墙 + 最小iptables(推荐)
setup_pve_friendly() {
    log "开始配置方案1:PVE防火墙友好方案"
    
    backup_iptables
    
    # 创建端口映射脚本,不干扰PVE防火墙
    cat > /usr/local/bin/pve-port-mapper << 'EOF'
#!/bin/bash

# 仅创建NAT规则,不干扰PVE防火墙的FILTER规则
INTERNAL_NETWORK="192.168.200"
BASE_PORT=30000
LOG_FILE="/var/log/pve-port-mapping.log"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

log "开始配置端口映射和安全屏蔽..."

# 开启IP转发
echo 'net.ipv4.ip_forward = 1' > /etc/sysctl.d/99-port-mapping.conf
sysctl -p /etc/sysctl.d/99-port-mapping.conf

# 应用安全屏蔽规则
apply_security_rules() {
    log "应用P2P/BT屏蔽规则..."
    
    # P2P和BT协议屏蔽
    local bt_keywords=(
        "torrent" ".torrent" "peer_id=" "announce" "info_hash" 
        "get_peers" "find_node" "BitTorrent" "announce_peer" 
        "BitTorrent protocol" "announce.php?passkey=" "magnet:" 
        "xunlei" "sandai" "Thunder" "XLLiveUD"
    )
    
    for keyword in "${bt_keywords[@]}"; do
        iptables -A OUTPUT -m string --string "$keyword" --algo bm -j DROP 2>/dev/null || true
        iptables -A FORWARD -m string --string "$keyword" --algo bm -j DROP 2>/dev/null || true
    done
    
    log "应用挖矿池屏蔽规则..."
    
    # 挖矿池屏蔽
    local mining_pools=(
        "ethermine.com" "antpool.one" "antpool.com" "pool.bar" "seed_hash"
    )
    
    for pool in "${mining_pools[@]}"; do
        iptables -A OUTPUT -m string --string "$pool" --algo bm -j DROP 2>/dev/null || true
        iptables -A FORWARD -m string --string "$pool" --algo bm -j DROP 2>/dev/null || true
    done
    
    log "应用测速网站屏蔽规则..."
    
    # 测速网站屏蔽
    local speedtest_sites=(
        ".speed" "speed." ".speed." "fast.com" "speedtest.net" 
        "speedtest.com" "speedtest.cn" "test.ustc.edu.cn" 
        "10000.gd.cn" "db.laomoe.com" "jiyou.cloud" 
        "ovo.speedtestcustom.com" "speed.cloudflare.com" "speedtest"
    )
    
    for site in "${speedtest_sites[@]}"; do
        iptables -A OUTPUT -m string --string "$site" --algo bm -j DROP 2>/dev/null || true
        iptables -A FORWARD -m string --string "$site" --algo bm -j DROP 2>/dev/null || true
    done
    
    log "安全屏蔽规则应用完成"
}

# 应用安全规则
apply_security_rules

# 清空自定义NAT链
iptables -t nat -F PORT_MAPPING 2>/dev/null || true
iptables -t nat -X PORT_MAPPING 2>/dev/null || true

# 创建自定义链
iptables -t nat -N PORT_MAPPING

# 创建端口映射规则
for ip in $(seq 1 254); do
    internal_ip="${INTERNAL_NETWORK}.${ip}"
    base_port=$((BASE_PORT + (ip - 1) * 10))
    
    # SSH 映射: base_port -> IP:22
    iptables -t nat -A PORT_MAPPING -p tcp --dport $base_port \
        -j DNAT --to-destination ${internal_ip}:22
    
    # HTTP 映射: base_port+1 -> IP:80
    iptables -t nat -A PORT_MAPPING -p tcp --dport $((base_port + 1)) \
        -j DNAT --to-destination ${internal_ip}:80
        
    # HTTPS 映射: base_port+2 -> IP:443
    iptables -t nat -A PORT_MAPPING -p tcp --dport $((base_port + 2)) \
        -j DNAT --to-destination ${internal_ip}:443
    
    # RDP 映射: base_port+3 -> IP:3389 (Windows远程桌面)
    iptables -t nat -A PORT_MAPPING -p tcp --dport $((base_port + 3)) \
        -j DNAT --to-destination ${internal_ip}:3389
        
    # VNC 映射: base_port+4 -> IP:5900 (VNC)
    iptables -t nat -A PORT_MAPPING -p tcp --dport $((base_port + 4)) \
        -j DNAT --to-destination ${internal_ip}:5900
done

# 检查PREROUTING链是否已有规则
if ! iptables -t nat -C PREROUTING -j PORT_MAPPING 2>/dev/null; then
    iptables -t nat -I PREROUTING -j PORT_MAPPING
    log "添加PREROUTING规则"
fi

# MASQUERADE规则 - 修复源地址伪装
if ! iptables -t nat -C POSTROUTING -s ${INTERNAL_NETWORK}.0/24 -j MASQUERADE 2>/dev/null; then
    iptables -t nat -A POSTROUTING -s ${INTERNAL_NETWORK}.0/24 -j MASQUERADE
    log "添加MASQUERADE规则"
fi

log "端口映射和安全屏蔽配置完成,与PVE防火墙兼容"
log "端口范围: $BASE_PORT - $((BASE_PORT + 254 * 10 - 1))"
EOF

    chmod +x /usr/local/bin/pve-port-mapper
    
    # 创建系统服务
    cat > /etc/systemd/system/pve-port-mapping.service << 'EOF'
[Unit]
Description=PVE Port Mapping Service
After=network.target pve-firewall.service
Before=pve-guests.service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/pve-port-mapper
ExecStop=/usr/local/bin/pve-port-mapper-stop
RemainAfterExit=yes
TimeoutStartSec=60

[Install]
WantedBy=multi-user.target
EOF

    # 创建停止脚本
    cat > /usr/local/bin/pve-port-mapper-stop << 'EOF'
#!/bin/bash
# 清理端口映射规则和安全屏蔽规则
iptables -t nat -D PREROUTING -j PORT_MAPPING 2>/dev/null || true
iptables -t nat -F PORT_MAPPING 2>/dev/null || true
iptables -t nat -X PORT_MAPPING 2>/dev/null || true

# 清理安全屏蔽规则(注意:这会清理所有包含这些关键词的规则)
echo "清理安全屏蔽规则..."
iptables-save | grep -E "(torrent|BitTorrent|speedtest|ethermine)" | sed 's/-A/-D/' | while read rule; do
    iptables $rule 2>/dev/null || true
done

echo "端口映射和安全规则已清理"
EOF

    chmod +x /usr/local/bin/pve-port-mapper-stop
    
    systemctl daemon-reload
    systemctl enable pve-port-mapping.service
    log "✅ PVE兼容方案配置完成"
}

# 方案2:优化的独立iptables方案  
setup_standalone_iptables() {
    log "开始配置方案2:独立iptables优化方案"
    
    backup_iptables
    
    # 确保PVE防火墙不干扰
    if systemctl is-active --quiet pve-firewall 2>/dev/null; then
        log "停用PVE防火墙以避免冲突"
        systemctl stop pve-firewall
        systemctl disable pve-firewall
    fi
    
    # 安装ipset
    if ! command -v ipset &> /dev/null; then
        log "安装ipset..."
        apt-get update && apt-get install -y ipset || error_exit "无法安装ipset"
    fi
    
    # 创建高效的端口映射
    cat > /usr/local/bin/optimized-port-mapper << 'EOF'
#!/bin/bash

INTERNAL_NETWORK="192.168.200"
BASE_PORT=30000

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}

# 安全屏蔽规则函数
apply_security_blocking() {
    log "配置独立优化方案 + 安全屏蔽..."
    
    # P2P和BT协议屏蔽
    local bt_keywords=(
        "torrent" ".torrent" "peer_id=" "announce" "info_hash" 
        "get_peers" "find_node" "BitTorrent" "announce_peer" 
        "BitTorrent protocol" "announce.php?passkey=" "magnet:" 
        "xunlei" "sandai" "Thunder" "XLLiveUD"
    )
    
    for keyword in "${bt_keywords[@]}"; do
        iptables -A OUTPUT -m string --string "$keyword" --algo bm -j DROP 2>/dev/null || true
        iptables -A FORWARD -m string --string "$keyword" --algo bm -j DROP 2>/dev/null || true
    done
    
    # 挖矿池屏蔽
    local mining_pools=(
        "ethermine.com" "antpool.one" "antpool.com" "pool.bar" "seed_hash"
    )
    
    for pool in "${mining_pools[@]}"; do
        iptables -A OUTPUT -m string --string "$pool" --algo bm -j DROP 2>/dev/null || true
        iptables -A FORWARD -m string --string "$pool" --algo bm -j DROP 2>/dev/null || true
    done
    
    # 测速网站屏蔽
    local speedtest_sites=(
        ".speed" "speed." ".speed." "fast.com" "speedtest.net" 
        "speedtest.com" "speedtest.cn" "test.ustc.edu.cn" 
        "10000.gd.cn" "db.laomoe.com" "jiyou.cloud" 
        "ovo.speedtestcustom.com" "speed.cloudflare.com" "speedtest"
    )
    
    for site in "${speedtest_sites[@]}"; do
        iptables -A OUTPUT -m string --string "$site" --algo bm -j DROP 2>/dev/null || true
        iptables -A FORWARD -m string --string "$site" --algo bm -j DROP 2>/dev/null || true
    done
    
    log "安全屏蔽规则配置完成"
}

log "配置独立优化方案..."

# 应用安全屏蔽
apply_security_blocking

# 开启IP转发
echo 'net.ipv4.ip_forward = 1' > /etc/sysctl.d/99-port-mapping.conf
sysctl -p /etc/sysctl.d/99-port-mapping.conf

# 清理现有规则和ipset
iptables -t nat -F PREROUTING 2>/dev/null || true
iptables -t nat -F POSTROUTING 2>/dev/null || true
iptables -F FORWARD 2>/dev/null || true

# 清理ipset
ipset destroy ssh_mapping 2>/dev/null || true
ipset destroy http_mapping 2>/dev/null || true
ipset destroy https_mapping 2>/dev/null || true

# 创建不同服务的ipset
ipset create ssh_mapping hash:ip,port
ipset create http_mapping hash:ip,port  
ipset create https_mapping hash:ip,port

# 批量添加映射关系
for ip in $(seq 1 254); do
    internal_ip="${INTERNAL_NETWORK}.${ip}"
    base_port=$((BASE_PORT + (ip - 1) * 10))
    
    # SSH映射
    ipset add ssh_mapping ${internal_ip},$base_port
    # HTTP映射
    ipset add http_mapping ${internal_ip},$((base_port + 1))
    # HTTPS映射
    ipset add https_mapping ${internal_ip},$((base_port + 2))
done

# 创建高效的NAT规则
iptables -t nat -A PREROUTING -p tcp -m set --match-set ssh_mapping dst,dst \
    -j DNAT --to-destination \$(echo \$INTERNAL_NETWORK | cut -d. -f1-3).1-254:22

iptables -t nat -A PREROUTING -p tcp -m set --match-set http_mapping dst,dst \
    -j DNAT --to-destination \$(echo \$INTERNAL_NETWORK | cut -d. -f1-3).1-254:80

iptables -t nat -A PREROUTING -p tcp -m set --match-set https_mapping dst,dst \
    -j DNAT --to-destination \$(echo \$INTERNAL_NETWORK | cut -d. -f1-3).1-254:443

# MASQUERADE
iptables -t nat -A POSTROUTING -s ${INTERNAL_NETWORK}.0/24 -j MASQUERADE

# FORWARD规则
iptables -A FORWARD -d ${INTERNAL_NETWORK}.0/24 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -s ${INTERNAL_NETWORK}.0/24 -j ACCEPT

log "高性能独立方案 + 安全屏蔽配置完成"
EOF

    chmod +x /usr/local/bin/optimized-port-mapper
    log "✅ 独立优化方案配置完成"
}

# 显示端口映射规则
show_port_mapping() {
    echo ""
    echo "📋 端口映射规则说明:"
    echo "内网网段: ${INTERNAL_NETWORK}.0/24"
    echo "外部端口范围: ${BASE_PORT} - $((BASE_PORT + 2540 - 1))"
    echo ""
    echo "映射规则 (每台虚拟机占用10个端口):"
    echo "- SSH:   外部端口 = $BASE_PORT + (IP末位-1) * 10"
    echo "- HTTP:  外部端口 = $BASE_PORT + (IP末位-1) * 10 + 1"  
    echo "- HTTPS: 外部端口 = $BASE_PORT + (IP末位-1) * 10 + 2"
    echo "- RDP:   外部端口 = $BASE_PORT + (IP末位-1) * 10 + 3"
    echo "- VNC:   外部端口 = $BASE_PORT + (IP末位-1) * 10 + 4"
    echo ""
    echo "示例:"
    echo "- ${INTERNAL_NETWORK}.10 SSH:  外部端口 $((BASE_PORT + 9 * 10))"
    echo "- ${INTERNAL_NETWORK}.10 HTTP: 外部端口 $((BASE_PORT + 9 * 10 + 1))"
    echo "- ${INTERNAL_NETWORK}.100 SSH: 外部端口 $((BASE_PORT + 99 * 10))"
}

# 主逻辑
main() {
    check_permissions
    
    show_port_mapping
    
    if check_pve_firewall; then
        echo ""
        echo "推荐使用方案1(PVE友好)"
        echo "是否继续配置方案1? (y/n): "
        read -r response
        if [[ "$response" =~ ^[Yy]$ ]]; then
            setup_pve_friendly
            
            echo ""
            echo "是否立即启动端口映射服务? (y/n): "
            read -r start_response
            if [[ "$start_response" =~ ^[Yy]$ ]]; then
                systemctl start pve-port-mapping.service
                log "端口映射服务已启动"
            fi
        fi
    else
        echo ""
        echo "可选择以下方案:"
        echo "1. PVE友好方案(保留PVE防火墙功能)"
        echo "2. 独立优化方案(最高性能)"
        echo "请选择 (1/2): "
        read -r choice
        
        case $choice in
            1) 
                setup_pve_friendly
                systemctl start pve-port-mapping.service 2>/dev/null || true
                ;;
            2) 
                setup_standalone_iptables
                /usr/local/bin/optimized-port-mapper
                ;;
            *) 
                error_exit "无效选择" 
                ;;
        esac
    fi
    
    echo ""
    echo "✅ 配置完成!"
    echo "日志文件: $LOG_FILE"
    echo "可以使用以下命令检查状态:"
    echo "- systemctl status pve-port-mapping.service"
    echo "- iptables -t nat -L -n -v"
}

# 显示重要提示
echo ""
echo "📋 重要说明:"
echo "1. PVE 8+ 支持基于nftables的新防火墙"
echo "2. 如果启用PVE防火墙,建议使用方案1"
echo "3. 高并发场景推荐方案2"
echo "4. 脚本会自动备份现有iptables规则"
echo "5. 确保外部端口范围 $BASE_PORT-$((BASE_PORT + 2540)) 未被占用"
echo ""

main "$@"

配置dhcp

安装sndmasq

apt install dnsmasq

添加ip地址的自动分配

nano /etc/dnsmasq.conf

interface=vmbr0

dhcp-range=192.168.200.2,192.168.200.254,72h
dhcp-option=option:router,192.168.200.1    
dhcp-option=option:dns-server,8.8.8.8,1.1.1.1

禁用默认的systemd-resolved

systemctl stop systemd-resolved
systemctl disable systemd-resolved

启用dnsmasq

systemctl start dnsmasq

修改系统默认的dns

rm -f /etc/resolv.conf
echo "nameserver 8.8.8.8" > /etc/resolv.conf

发表在 Linux | 将 Debian 12 转换为 Proxmox VE已关闭评论

WHMCS安装

一、安装基础组件

PHP

pacman -S php php-fpm php-gd php-sqlite
pacman -U php-ioncube-loader-14.4.1-1-x86_64.pkg.tar.zst

NGINX

pacman -S nginx

MySQL

pacman -U libmysqlclient80-8.0.42-1-x86_64.pkg.tar.zst mysql-clients80-8.0.42-1-x86_64.pkg.tar.zst mysql80-8.0.42-1-x86_64.pkg.tar.zst 

二、修改配置

/etc/mysql/my.cnf

[mysqld]
# Don't listen on a TCP/IP port at all. This can be a security enhancement,
# if all processes that need to connect to mysqld run on the same host.
# All interaction with mysqld must be made via Unix sockets or named pipes.
# Note that using this option without enabling named pipes on Windows
# (via the "enable-named-pipe" option) will render mysqld useless!
# 
bind-address                                            = 0.0.0.0
port                                                    = 3306
socket                                                  = /run/mysqld/mysqld.sock
#skip-networking
skip-name-resolve 
skip-ssl
#ssl-ca                                                         = /srv/mysql/ca.pem 
#ssl-cert                                                       = /srv/mysql/server-cert.pem 
#ssl-key                                                        = /srv/mysql/server-key.pem

#sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

# These are commonly set, remove the # and set as required.
basedir                                                         = /usr
datadir                                                         = /srv/mysql/data
# Point the following paths to different dedicated disks
#tmpdir                                                 = /tmp/

default-time-zone                                       = '+8:00'
character-set-server                            = UTF8MB4
#default_authentication_plugin          = mysql_native_password

# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size                                        = 128M
sort_buffer_size                                        = 1024M
# read_rnd_buffer_size                            = 2M 
max_heap_table_size                             = 2048M
tmp_table_size                                          = 2048M
max_connections                                         = 16384
max_allowed_packet                                      = 20M

innodb_data_home_dir                            = /srv/mysql/inno
innodb_log_group_home_dir                       = /srv/mysql/inno
innodb_data_file_path                           = ibdata1:10M:autoextend
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
innodb_buffer_pool_size                         = 128M
# innodb_log_group_home_dir               = /srv/mysql/logs
# innodb_additional_mem_pool_size         = 2M
innodb_log_file_size                            = 32M
innodb_log_buffer_size                          = 8M
innodb_flush_log_at_trx_commit          = 1
innodb_lock_wait_timeout                        = 50
innodb_lock_wait_timeout                        = 1814400


#init_connect                            = 'SET collation_connection = utf8_general_ci,NAMES utf8'
#collation_server                        = utf8_general_ci
#character_set_client                    = utf8
#character_set_server                    = utf8
#skip-external-locking
#key_buffer_size                                         = 16M
#max_allowed_packet                              = 1M
#table_open_cache                                        = 64
#sort_buffer_size                                        = 512K
#net_buffer_length                                       = 8K
#read_buffer_size                                        = 256K
#read_rnd_buffer_size                            = 512K
#myisam_sort_buffer_size                         = 8M


# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin

# Replication Master Server (default)
# binary logging is required for replication
#log-bin=mysql-bin

# binary logging format - mixed recommended
#binlog_format=mixed

# required unique id between 1 and 2^32 - 1
# defaults to 1 if master-host is not set
# but will not function as a master if omitted
#server-id       = 1

# Replication Slave (comment out master section to use this)
#
# To configure this host as a replication slave, you can choose between
# two methods :
#
# 1) Use the CHANGE MASTER TO command (fully described in our manual) -
#    the syntax is:
#
#    CHANGE MASTER TO MASTER_HOST=<host>, MASTER_PORT=<port>,
#    MASTER_USER=<user>, MASTER_PASSWORD=<password> ;
#
#    where you replace <host>, <user>, <password> by quoted strings and
#    <port> by the master's port number (3306 by default).
#
#    Example:
#
#    CHANGE MASTER TO MASTER_HOST='125.564.12.1', MASTER_PORT=3306,
#    MASTER_USER='joe', MASTER_PASSWORD='secret';
#
# OR
#
# 2) Set the variables below. However, in case you choose this method, then
#    start replication for the first time (even unsuccessfully, for example
#    if you mistyped the password in master-password and the slave fails to
#    connect), the slave will create a master.info file, and any later
#    change in this file to the variables' values below will be ignored and
#    overridden by the content of the master.info file, unless you shutdown
#    the slave server, delete master.info and restart the slaver server.
#    For that reason, you may want to leave the lines below untouched
#    (commented) and instead use CHANGE MASTER TO (see above)
#
# required unique id between 2 and 2^32 - 1
# (and different from the master)
# defaults to 2 if master-host is set
# but will not function as a slave if omitted
#server-id       = 2
#
# The replication master for this slave - required
#master-host     =   <hostname>
#
# The username the slave will use for authentication when connecting
# to the master - required
#master-user     =   <username>
#
# The password the slave will authenticate with when connecting to
# the master - required
#master-password =   <password>
#
# The port the master is listening on.
# optional - defaults to 3306
#master-port     =  <port>
#
# binary logging - not required for slaves, but recommended
#log-bin=mysql-bin


# The following options will be passed to all MySQL clients
[client]
password       = <PASSWORD>
port           = 3306
socket         = /run/mysqld/mysqld.sock

# Here follows entries for some specific programs

[mysqldump]
quick
max_allowed_packet = 16M

[mysql]
no-auto-rehash
default-character-set = utf8mb4
# Remove the next comment character if you are not familiar with SQL
#safe-updates
#ssl-ca = /srv/mysql/ca.pem
#ssl-cert = /srv/mysql/client-cert.pem
#ssl-key = /srv/mysql/client-key.pem

[myisamchk]
key_buffer_size = 20M
sort_buffer_size = 20M
read_buffer = 2M
write_buffer = 2M

[mysqlhotcopy]
interactive-timeout
mkdir -p /srv/mysql/{data,inno}
chown -R mysql:mysql /srv/mysql

mysqld --initialize --user=mysql --basedir=/usr --datadir=/srv/mysql/data --innodb_data_home_dir=/srv/mysql/inno --innodb_log_group_home_dir=/srv/mysql/inno

mysql修改密码

ALTER USER USER() IDENTIFIED BY 'password';

CREATE USER 'root'@'%' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;

创建数据库

CREATE DATABASE whmcs;
CREATE USER 'whmcs'@'localhost' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON whmcs.* TO 'whmcs'@'localhost';
FLUSH PRIVILEGES;
EXIT;
systemctl enable mysqld && systemctl restart mysqld

/etc/nginx/xxx.com_ssl.conf

server {
    listen 443 ssl;
    server_name xxx.com;
    ssl_certificate /etc/nginx/ssl/server.pem;
    ssl_certificate_key /etc/nginx/ssl/server.key;
    ssl_session_timeout 5m;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers 'HIGH:!aNULL:!MD5';
    ssl_prefer_server_ciphers off;

    root        /srv/http/whmcs;
    index       index.html index.php;

    #charset koi8-r;

    access_log  /var/log/nginx/fortu.cfd.access.log;
    error_log   /var/log/nginx/fortu.cfd.error.log;

    # no size limit of uploaded file
    client_max_body_size 0;

    # 安全配置
    location ~ /\.ht {
        deny all;
    }
    
    location ~ /\.git {
        deny all;
    }

    # WHMCS 特定配置
    location ~* \.(tpl|twig)$ {
        deny all;
    }

    location ~ ^/(downloads|utilities|vendor|.composer|whois.json) {
        deny all;
    }

    # PHP 文件处理
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

        # 修复 HTTPS 代理问题
        fastcgi_param HTTPS on;
        fastcgi_param HTTP_X_FORWARDED_PROTO https;
        fastcgi_param HTTP_X_FORWARDED_SSL on;

        include fastcgi_params;
    }

    # 静态文件缓存
    location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # URL 重写规则
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    #用于清除缓存,假设一个URL为http://my.domain.com/test.gif,通过访问
    #http://git.magicwall.org/purge/test.gif可以清除该URL的缓存
    location ~ /purge(/.*)
    {
        #设置只允许指定的IP或IP段才可以清除URL缓存
        allow 172.16.0.0/24;
        deny all;
        #proxy_cache_purge staticCache $host$1$is_args$args ;
    }
}

三、下载 WHMCS

设置权限

chown -R http:http /srv/http/whmcs
chmod -R 755 /srv/http/whmcs

四、设置PHP

配置 PHP-FPM

extension=curl
extension=ftp
extension=gd
extension=intl
extension=mysqli
extension=pdo_mysql
extension=zip
systemctl enable php-fpm && systemctl restart php-fpm

五、安装

http://yourdomain.com/install/install.php
发表在 Linux | WHMCS安装已关闭评论

Virtualizor 开心版 LXC镜像下载

Virtualizor 开心版 LXC镜像 不能下载了
解决办法
https://images.linuxcontainers.org/images/
从这里下载镜像
例如

cd /var/virtualizor/lxc
wget https://images.linuxcontainers.org/images/debian/trixie/amd64/cloud/20250829_05%3A24/rootfs.tar.xz

更换后缀

unxz rootfs.tar.xz
gzip rootfs.tar

重新命名

mv rootfs.tar.gz Debian13.tar.gz

就好了

然后在后台添加
Media-Add OS Template
选项
Virtualization Type-LXC
OS Template-Debian
Url-空
Filename-Debian13.tar.gz
就好了

发表在 Linux | Virtualizor 开心版 LXC镜像下载已关闭评论

Linux 优化基础脚本

#!/bin/bash
# setup-limits-and-bbr.sh
# 自动配置系统资源限制 + 开启 BBR

set -e

echo ">>> 第一步:修改 /etc/systemd/system.conf ..."
SYSTEM_CONF="/etc/systemd/system.conf"

cat <<EOF | sudo tee -a $SYSTEM_CONF > /dev/null

# 自定义资源限制
DefaultLimitNOFILE=8192:524288
DefaultLimitNPROC=8192:524288
EOF

echo ">>> 重新加载 systemd ..."
sudo systemctl daemon-reexec


echo ">>> 第二步:修改 /etc/security/limits.conf ..."
LIMITS_CONF="/etc/security/limits.conf"

cat <<EOF | sudo tee -a $LIMITS_CONF > /dev/null

# 自定义资源限制
* soft nofile 65536
* hard nofile 65536
EOF


echo ">>> 第三步:修改 /etc/pam.d/login ..."
PAM_LOGIN="/etc/pam.d/login"
LINE="session    required     /usr/lib64/security/pam_limits.so"

if ! grep -Fxq "$LINE" $PAM_LOGIN; then
  echo "$LINE" | sudo tee -a $PAM_LOGIN > /dev/null
fi


echo ">>> 第四步:写入 sysctl 配置(启用 BBR)..."
CONF_FILE="/etc/sysctl.d/99-bbr.conf"

cat <<EOF | sudo tee $CONF_FILE > /dev/null
net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr
EOF

sudo sysctl --system


echo ">>> 当前拥塞控制算法:"
sysctl net.ipv4.tcp_congestion_control

echo ">>> 检查是否已加载 BBR 模块:"
lsmod | grep bbr || echo "提示:未看到 tcp_bbr 也没关系,内核会按需加载。"

echo ">>> 所有设置完成!建议重新登录以使 pam/limits 配置完全生效。"

直接下载

wget https://gating.site/scrpits/setup-limits-and-bbr.sh

发表在 Linux | Linux 优化基础脚本已关闭评论

在 Arch Linux 上安装 Apache Guacamole

一、安装依赖

Guacamole 分两部分:

  • guacamole-server (guacd):本地代理进程
  • guacamole-client (Web 前端):Tomcat 里运行的 guacamole.war

先安装编译依赖和运行依赖:

sudo pacman -S guacd

二、安装 guacamole-server

Arch 官方仓库自带:

pacman -S guacd

启动并设置开机自启:

sudo systemctl enable --now guacd

检查:

systemctl status guacd

三、安装 guacamole-client (Web 前端)

安装 Tomcat:

sudo pacman -S tomcat9

下载 Web 应用包(继承jdbc认证):

wget https://downloads.apache.org/guacamole/1.5.5/binary/guacamole-1.5.5.war -O guacamole.war
sudo mv guacamole.war /var/lib/tomcat9/webapps/guacamole.war

启动 Tomcat:

sudo systemctl enable --now tomcat9

四、配置 Guacamole

创建配置目录:

sudo mkdir -p /etc/guacamole

主配置文件 /etc/guacamole/guacamole.properties

guacd-hostname: localhost
guacd-port: 4822

auth-provider: net.sourceforge.guacamole.net.auth.mysql.MySQLAuthenticationProvider

mysql-hostname: localhost
mysql-port: 3306
mysql-database: guacamole
mysql-username: guacamole
mysql-password: strongpassword

让 Tomcat 能找到配置

ln -s /etc/guacamole/guacamole.properties /etc/guacamole.properties
mkdir -p /usr/share/tomcat9/.guacamole/{extensions,lib}
ln -sf /etc/guacamole/guacamole.properties /usr/share/tomcat9/.guacamole/guacamole.properties

cp guacamole-auth-jdbc-mysql-1.6.0.jar /usr/share/tomcat9/.guacamole/extensions
cp mysql-connector-j-8.4.0.jar /usr/share/tomcat9/.guacamole/lib

重启服务

sudo systemctl restart guacd
sudo systemctl restart tomcat9

访问

http://<服务器IP>:8080/guacamole

输入 guacaadmin / guacaadmin 登录,点击你配置的 VNC 或 RDP 连接,即可进入远程桌面。

发表在 Linux | 在 Arch Linux 上安装 Apache Guacamole已关闭评论

xboard 在 archlinux 上的安装

一、相关依赖

  • PHP 8.2
  • MySQL 5.7+
  • KeyVal
  • Nginx (any version)

二、安装组件

安装官方PHP包

pacman -S php php-fpm php-igbinary php-redis readline file c-ares postgresql-libs
php -m | grep -E 'redis|fileinfo|swoole|readline|event'

安装自有软件包,需要和版本一致

pacman -U php-event-3.1.4-1-x86_64.pkg.tar.zst php-openswoole-git-22.1.2.r76.g525c247b0-1-any.pkg.tar.zst

安装redis

pacman -S redis 

开启插件并且检/查

/etc/php/php.in

extension=curl
extension=gd
extension=iconv
extension=mysqli
extension=pdo_mysql
extension=sockets
extension=zip
echo "extension=sockets" | sudo tee /etc/php/conf.d/20-sockets.ini
echo "extension=event"   | sudo tee /etc/php/conf.d/30-event.ini
echo "extension=fileinfo" | sudo tee /etc/php/conf.d/20-fileinfo.ini

echo "extension=igbinary" | sudo tee /etc/php/conf.d/20-igbinary.ini
php -m | grep -E 'redis|fileinfo|swoole|readline|event'
event
fileinfo
openswoole
readline
redis

安装mysql

pacman -U libmysqlclient80-8.0.42-1-x86_64.pkg.tar.zst mysql-clients80-8.0.42-1-x86_64.pkg.tar.zst mysql80-8.0.42-1-x86_64.pkg.tar.zst

安装nginx

pacman -S nginx

三、安装程序

# Enter site directory
cd /srv/http/xboard

# Clone repository
git clone https://github.com/cedar2025/Xboard.git ./

# Install dependencies
sh init.sh

四、安装主启动脚本

nano -w /etc/systemd/system/octane-xboard.service

[Unit]
Description=Laravel Octane (Swoole) - xboard
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
User=root
Group=root
WorkingDirectory=/srv/http/xboard

# 可按需调整
Environment=APP_ENV=production
Environment=OCTANE_SERVER=swoole
Environment=OCTANE_HOST=0.0.0.0
Environment=OCTANE_PORT=7001

# 启动 / 重载 / 停止
ExecStart=/usr/bin/php artisan octane:start --server=${OCTANE_SERVER} --host=${OCTANE_HOST} --port=${OCTANE_PORT} --max-requests=500
ExecReload=/usr/bin/php artisan octane:reload
ExecStop=/usr/bin/php artisan octane:stop

# 保障项
Restart=always
RestartSec=3
TimeoutStopSec=60
KillSignal=SIGINT
LimitNOFILE=65535
# 生产环境通常不建议 --watch
# 若用 RoadRunner:把 OCTANE_SERVER 设为 roadrunner

[Install]
WantedBy=multi-user.target

五、安装计划任务

运行 Laravel 定时任务调度器
nano -w /etc/systemd/system/xboard-schedule.service

[Unit]
Description=XBoard Schedule Task Runner
After=network.target mysql.service

[Service]
Type=oneshot
User=root
Group=root

WorkingDirectory=/srv/http/xboard
ExecStart=/usr/bin/php artisan schedule:run

TimeoutStartSec=120

Environment=LANG=en_US.UTF-8
Environment=LC_ALL=en_US.UTF-8

StandardOutput=journal
StandardError=journal
SyslogIdentifier=xboard-schedule

NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/srv/http/xboard/storage
ReadWritePaths=/srv/http/xboard/bootstrap/cache

nano -w xboard-schedule.timer

[Unit]
Description=Run XBoard Scheduled Tasks every minute
Requires=xboard-schedule.service

[Timer]
OnCalendar=*:*:00
Persistent=true
RandomizedDelaySec=10

[Install]
WantedBy=timers.target

启动 Laravel Horizon 队列管理器
nano -w /etc/systemd/system/xboard-horizon.service

[Unit]
Description=XBoard Horizon Queue Manager
After=network.target mysql.service redis.service
Wants=network.target
Requires=redis.service

[Service]
Type=simple
User=root
Group=root
Restart=always
RestartSec=5s
StartLimitInterval=60s
StartLimitBurst=3

WorkingDirectory=/srv/http/xboard
ExecStart=/usr/bin/php artisan horizon

ExecReload=/bin/kill -USR2 $MAINPID
KillMode=mixed
KillSignal=SIGTERM
TimeoutStopSec=60

Environment=LANG=en_US.UTF-8
Environment=LC_ALL=en_US.UTF-8

StandardOutput=journal
StandardError=journal
SyslogIdentifier=xboard-horizon

NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/srv/http/xboard/storage
ReadWritePaths=/srv/http/xboard/bootstrap/cache

[Install]
WantedBy=multi-user.target
发表在 默认分类 | xboard 在 archlinux 上的安装已关闭评论