最新的OPENWRT与FRPC不兼容问题

最新的openwrt (04.21.2026)如果使用编译添加了frpc,启动会报错:

bash 复制代码
frp服务启动失败,请检查服务端 "TCP多路复用(tcp_mux)"设置,确保与客户端完全一致!

不要被这个坑爹的提示误导了。它的实际意义是:

frpc进程没有在运行,而已!

究其原因,是因为启动脚本一个字没变,但是最新的服务启动停止命令变成start-stop-daemon了!

于是乎启动服务脚本失效了!

解决办法,就是修改/etc/init.d/frp这个服务,修改为以下内容:

bash 复制代码
#!/bin/sh /etc/rc.common

START=99

LOGFILE="/var/etc/frp/frpc.log"

echo_date(){
        local log=$1
        echo $(date +%Y/%m/%d\ %X): "$log" >> $LOGFILE
}

Reduce_Log(){
        local log=$1
        [ ! -f "$log" ] && return
        local sc=200
        [ -n "$2" ] && sc=$2
        local count=$(grep -c "" $log)
        if [ $count -gt $sc ];then
                let count=count-$sc
                sed -i "1,$count d" $log
        fi
}

conf_proxy_add() {
        local cfg="$1"
        local tmpconf="$2"
        local enable type domain_type custom_domains remote_port local_ip local_port enable_http_auth enable_host_header_rewrite host_header_rewrite
        local subdomain proxy_protocol_version use_encryption use_compression http_user http_pwd remark locations
        local enable_plugin plugin plugin_http_user plugin_http_passwd plugin_unix_path stcp_role stcp_secretkey stcp_servername xtcp_role xtcp_secretkey xtcp_servername
        local enable_https_plugin https_plugin plugin_local_addr plugin_crt_path plugin_key_path plugin_host_header_rewrite plugin_header_X_From_Where

        config_get_bool enable "$cfg" enable 1
        [ "$enable" -gt 0 ] || return 1

        config_get type "$cfg" type
        config_get custom_domains "$cfg" custom_domains
        config_get subdomain "$cfg" subdomain
        config_get remote_port "$cfg" remote_port
        config_get local_ip "$cfg" local_ip
        config_get local_port "$cfg" local_port
        config_get locations "$cfg" locations
        config_get host_header_rewrite "$cfg" host_header_rewrite
        config_get http_user "$cfg" http_user
        config_get http_pwd "$cfg" http_pwd
        config_get remark "$cfg" remark
        config_get plugin "$cfg" plugin
        config_get plugin_http_user "$cfg" plugin_http_user
        config_get plugin_http_passwd "$cfg" plugin_http_passwd
        config_get plugin_unix_path "$cfg" plugin_unix_path
        config_get stcp_role "$cfg" stcp_role
        config_get stcp_secretkey "$cfg" stcp_secretkey
        config_get stcp_servername "$cfg" stcp_servername
        config_get xtcp_role "$cfg" xtcp_role
        config_get xtcp_secretkey "$cfg" xtcp_secretkey
        config_get xtcp_servername "$cfg" xtcp_servername
        config_get proxy_protocol_version "$cfg" proxy_protocol_version
        config_get https_plugin "$cfg" https_plugin
        config_get plugin_local_addr "$cfg" plugin_local_addr
        config_get plugin_crt_path "$cfg" plugin_crt_path
        config_get plugin_key_path "$cfg" plugin_key_path
        config_get plugin_host_header_rewrite "$cfg" plugin_host_header_rewrite
        config_get plugin_header_X_From_Where "$cfg" plugin_header_X_From_Where

        [ -n "$remark" ] && [ -n "$type" ] || return 1

        echo "" >>$tmpconf
        echo "[$remark]" >>$tmpconf
        echo "type=$type" >>$tmpconf
        [ -n "$custom_domains" ] && echo "custom_domains=$custom_domains" >>$tmpconf
        [ -n "$subdomain" ] && echo "subdomain=$subdomain" >>$tmpconf
        [ -n "$remote_port" ] && echo "remote_port=$remote_port" >>$tmpconf
        [ -z "$stcp_role" ] && [ -z "$xtcp_role" ] && [ -n "$local_ip" ] && echo "local_ip=$local_ip" >>$tmpconf
        [ -z "$stcp_role" ] && [ -z "$xtcp_role" ] && [ -n "$local_port" ] && echo "local_port=$local_port" >>$tmpconf
        [ -n "$locations" ] && echo "locations=$locations" >>$tmpconf
        [ -n "$http_user" -a -n "$http_pwd" ] && {
                echo "http_user=$http_user" >>$tmpconf
                echo "http_pwd=$http_pwd" >>$tmpconf
        }
        [ -n "$host_header_rewrite" ] && echo "host_header_rewrite=$host_header_rewrite" >>$tmpconf
        [ -n "$plugin" ] && echo "plugin=$plugin" >>$tmpconf
        [ -n "$plugin_http_user" -a -n "$plugin_http_passwd" ] && {
                echo "plugin_http_user=$plugin_http_user" >>$tmpconf
                echo "plugin_http_passwd=$plugin_http_passwd" >>$tmpconf
        }
        [ -n "$plugin_unix_path" ] && echo "plugin_unix_path=$plugin_unix_path" >>$tmpconf

        [ -n "$stcp_role" ] && {
                if [ "$stcp_role" == "visitor" ]; then
                        echo "role=$stcp_role" >>$tmpconf
                        [ -n "$local_ip" ] && echo "bind_addr=$local_ip" >>$tmpconf
                        [ -n "$local_port" ] && echo "bind_port=$local_port" >>$tmpconf
                        [ -n "$stcp_servername" ] && echo "server_name=$stcp_servername" >>$tmpconf || return 1
                else
                        [ -n "$local_ip" ] && echo "local_ip=$local_ip" >>$tmpconf
                        [ -n "$local_port" ] && echo "local_port=$local_port" >>$tmpconf
                fi
                [ -n "$stcp_secretkey" ] && echo "sk=$stcp_secretkey" >>$tmpconf || return 1
        }

        [ -n "$xtcp_role" ] && {
                if [ "$xtcp_role" == "visitor" ]; then
                        echo "role=$xtcp_role" >>$tmpconf
                        [ -n "$local_ip" ] && echo "bind_addr=$local_ip" >>$tmpconf
                        [ -n "$local_port" ] && echo "bind_port=$local_port" >>$tmpconf
                        [ -n "$xtcp_servername" ] && echo "server_name=$xtcp_servername" >>$tmpconf || return 1
                else
                        [ -n "$local_ip" ] && echo "local_ip=$local_ip" >>$tmpconf
                        [ -n "$local_port" ] && echo "local_port=$local_port" >>$tmpconf
                fi
                [ -n "$xtcp_secretkey" ] && echo "sk=$xtcp_secretkey" >>$tmpconf || return 1
        }

        [ -n "$proxy_protocol_version" ] && {
                if [ "$proxy_protocol_version" != "disable" ]; then
                        echo "proxy_protocol_version=$proxy_protocol_version" >>$tmpconf
                fi
        }

        [ -n "$https_plugin" ] && echo "plugin=$https_plugin" >>$tmpconf
        [ -n "$plugin_local_addr" ] && echo "plugin_local_addr=$plugin_local_addr" >>$tmpconf
        [ -n "$plugin_crt_path" -a -n "$plugin_key_path" ] && {
                echo "plugin_crt_path=$plugin_crt_path" >>$tmpconf
                echo "plugin_key_path=$plugin_key_path" >>$tmpconf
        }
        [ -n "$plugin_host_header_rewrite" ] && echo "plugin_host_header_rewrite=$plugin_host_header_rewrite" >>$tmpconf
        [ -n "$plugin_header_X_From_Where" ] && echo "plugin_header_X_From_Where=$plugin_header_X_From_Where" >>$tmpconf

        frp_write_bool use_encryption $cfg 1
        frp_write_bool use_compression $cfg 1
}

frp_write_bool() {
        local opt="$1"
        local config="$2"
        local def="$3"
        local val

        config_get_bool val $config "$opt" "$def"
        if [ "$val" -eq 0 ]; then
                echo "${opt}=false" >> $tmpconf
        else
                echo "${opt}=true" >> $tmpconf
        fi
}

frp_add_cru(){
        time=$1
        if [ ! -f "/etc/crontabs/root" ] || [ -z "$(cat /etc/crontabs/root | grep frp)" ]; then
                sed -i '/frp/d' /etc/crontabs/root >/dev/null 2>&1
                echo "*/$time * * * * /etc/init.d/frp restart" >> /etc/crontabs/root
        fi
}

frp_del_cru(){
        if [ ! -f "/etc/crontabs/root" ] || [ -n "$(cat /etc/crontabs/root | grep frp)" ]; then
                sed -i '/frp/d' /etc/crontabs/root >/dev/null 2>&1
        fi
}

download_binary(){
        echo_date "开始下载frpc二进制文件..."
        /usr/bin/wget --no-check-certificate --timeout=10 --tries=1 -o $LOGFILE https://github.com/fatedier/frp/releases/download/v0.13.0/frp_0.13.0_linux_arm.tar.gz -O /tmp/frp_0.13.0_linux_arm.tar.gz
        [ ! -s "/tmp/frp_0.13.0_linux_arm.tar.gz" ] && /usr/bin/wget -q --no-check-certificate --timeout=10 --tries=1 https://any.mokoo.xyz/app/frp_0.13.0_linux_arm.tar.gz -O /tmp/frp_0.13.0_linux_arm.tar.gz
        [ -f "/tmp/frp_0.13.0_linux_arm.tar.gz" ] && tar -xf /tmp/frp_0.13.0_linux_arm.tar.gz -C /tmp && \
                mv /tmp/frp_0.13.0_linux_arm/frpc /usr/bin/frpc
        rm -rf /tmp/frp_0.13.0_linux_arm*
        if [ -f "/usr/bin/frpc" ]; then
                chmod +x /usr/bin/frpc && echo_date "成功下载frpc二进制文件"
        else
                echo_date "下载frpc二进制文件失败,请重试!"
        fi
}

boot() {
        sleep 10s
        start
}

start() {
    start_service
}

stop() {
    stop_service
}

start_service() {
        config_load "frp"
        local enabled server_addr server_port time privilege_token user tcp_mux enable_cpool tls_enable
        local pool_count log_level log_max_days login_fail_exit http_proxy protocol admin_port admin_user admin_pwd
        local tls_cert_file tls_key_file tls_trusted_ca_file

        config_get_bool enabled common enabled 1
        [ "$enabled" -gt 0 ] || return 1

        config_get server_addr common server_addr
        config_get server_port common server_port
        config_get token common token
        config_get user common user
        config_get enable_cpool common enable_cpool
        config_get pool_count common pool_count
        config_get log_level common log_level
        config_get log_max_days common log_max_days
        config_get http_proxy common http_proxy
        config_get protocol common protocol
        config_get time common time
        config_get admin_port common admin_port
        config_get admin_user common admin_user
        config_get admin_pwd common admin_pwd
        config_get tls_cert_file common tls_cert_file
        config_get tls_key_file common tls_key_file
        config_get tls_trusted_ca_file common tls_trusted_ca_file

        mkdir -p /var/etc/frp
        [ ! -f "$LOGFILE" ] && touch $LOGFILE

        [ ! -f "/usr/bin/frpc" ] && download_binary
        [ ! -f "/usr/bin/frpc" ] && logger -t Frp 'Download frpc failed, please retry.' && exit 0

        local tmpconf="/var/etc/frp/frpc.conf"

        echo "[common]" >$tmpconf
        echo "server_addr=${server_addr}" >>$tmpconf
        echo "server_port=${server_port}" >>$tmpconf
        echo "token=${token}" >>$tmpconf
        [ -n "$user" ] && echo "user=$user" >>$tmpconf
        echo "log_level=${log_level}" >>$tmpconf
        echo "log_max_days=${log_max_days}" >>$tmpconf
        echo "protocol=${protocol}" >>$tmpconf
        echo "log_file=$LOGFILE" >>$tmpconf
        [ -n "$http_proxy" ] && echo "http_proxy=$http_proxy" >>$tmpconf
        [ -n "$pool_count" ] && echo "pool_count=$pool_count" >>$tmpconf
        [ -n "$admin_port" ] && echo "admin_addr=0.0.0.0" >>$tmpconf && echo "admin_port=$admin_port" >>$tmpconf
        [ -n "$admin_user" ] && echo "admin_user=$admin_user" >>$tmpconf
        [ -n "$admin_pwd" ] && echo "admin_pwd=$admin_pwd" >>$tmpconf
        [[ -n "$tls_cert_file" && -n "$tls_key_file" ]] && echo "tls_cert_file=$tls_cert_file" >>$tmpconf && echo "tls_key_file=$tls_key_file" >>$tmpconf
        [ -n "$tls_trusted_ca_file" ] && echo "tls_trusted_ca_file=$tls_trusted_ca_file" >>$tmpconf

        config_load "frp"
        frp_write_bool tcp_mux common 1
        frp_write_bool tls_enable common 0
        frp_write_bool login_fail_exit common 1
        config_foreach conf_proxy_add proxy "$tmpconf"

        [ "$(cat "$tmpconf" | grep -c "type=")" -gt 0 ] || (echo_date "frp服务启动失败,请首先添加服务列表!" && return 1)

        start-stop-daemon -S -b -m -p /var/run/frpc.pid -x /usr/bin/frpc -- -c "$tmpconf"

        [ "$time" -gt 0 ] && frp_add_cru $time

        # 延迟检查进程是否启动成功
        sleep 2
        [ -z "$(pgrep /usr/bin/frpc)" ] && echo_date 'frp服务启动失败,请检查服务端 "TCP多路复用(tcp_mux)"设置,确保与客户端完全一致!'
}

stop_service() {
        frp_del_cru

        if [ -n "$(pidof frpc)" ]; then
                logger -t FRPC 'Shutting down frp service'

                # 优雅停止
                kill $(pidof frpc) 2>/dev/null

                # 最多等5秒
                for i in $(seq 1 5); do
                        sleep 1
                        pidof frpc >/dev/null || break
                done

                # 兜底强杀
                kill -9 $(pidof frpc) 2>/dev/null
        fi

        Reduce_Log $LOGFILE
}

或者用procd的模式:

bash 复制代码
#!/bin/sh /etc/rc.common

START=99
STOP=10
USE_PROCD=1

LOGFILE="/var/etc/frp/frpc.log"

# ================= 工具函数 =================

echo_date(){
    echo "$(date +%Y/%m/%d\ %X): $1" >> $LOGFILE
}

Reduce_Log(){
    local log=$1
    [ ! -f "$log" ] && return
    local sc=${2:-200}
    local count=$(wc -l < "$log")
    if [ "$count" -gt "$sc" ]; then
        sed -i "1,$((count-sc))d" "$log"
    fi
}

# ================= frp辅助函数 =================

frp_write_bool() {
    local opt="$1"
    local config="$2"
    local def="$3"
    local val

    config_get_bool val $config "$opt" "$def"
    if [ "$val" -eq 0 ]; then
        echo "${opt}=false" >> $tmpconf
    else
        echo "${opt}=true" >> $tmpconf
    fi
}

conf_proxy_add() {
    local cfg="$1"
    local tmpconf="$2"

    local enable type remark local_ip local_port remote_port custom_domains subdomain

    config_get_bool enable "$cfg" enable 1
    [ "$enable" -gt 0 ] || return

    config_get type "$cfg" type
    config_get remark "$cfg" remark
    config_get local_ip "$cfg" local_ip
    config_get local_port "$cfg" local_port
    config_get remote_port "$cfg" remote_port
    config_get custom_domains "$cfg" custom_domains
    config_get subdomain "$cfg" subdomain

    [ -n "$remark" ] || return

    echo "" >>$tmpconf
    echo "[$remark]" >>$tmpconf
    echo "type=$type" >>$tmpconf
    [ -n "$local_ip" ] && echo "local_ip=$local_ip" >>$tmpconf
    [ -n "$local_port" ] && echo "local_port=$local_port" >>$tmpconf
    [ -n "$remote_port" ] && echo "remote_port=$remote_port" >>$tmpconf
    [ -n "$custom_domains" ] && echo "custom_domains=$custom_domains" >>$tmpconf
    [ -n "$subdomain" ] && echo "subdomain=$subdomain" >>$tmpconf
}

frp_add_cru(){
    local time=$1
    sed -i '/frp/d' /etc/crontabs/root 2>/dev/null
    echo "*/$time * * * * /etc/init.d/frp restart" >> /etc/crontabs/root
}

frp_del_cru(){
    sed -i '/frp/d' /etc/crontabs/root 2>/dev/null
}

download_binary(){
    echo_date "下载 frpc..."
    wget -q https://github.com/fatedier/frp/releases/download/v0.51.3/frp_0.51.3_linux_arm.tar.gz -O /tmp/frp.tar.gz
    tar -xf /tmp/frp.tar.gz -C /tmp
    cp /tmp/frp_*/frpc /usr/bin/frpc
    chmod +x /usr/bin/frpc
    rm -rf /tmp/frp*
}

# ================= 核心逻辑 =================

start_service() {
    config_load "frp"

    local enabled server_addr server_port token time log_level log_max_days

    config_get_bool enabled common enabled 1
    [ "$enabled" -gt 0 ] || return 1

    config_get server_addr common server_addr
    config_get server_port common server_port
    config_get token common token
    config_get log_level common log_level
    config_get log_max_days common log_max_days
    config_get time common time

    mkdir -p /var/etc/frp
    [ ! -f "$LOGFILE" ] && touch $LOGFILE

    [ ! -f "/usr/bin/frpc" ] && download_binary
    [ ! -f "/usr/bin/frpc" ] && return 1

    tmpconf="/var/etc/frp/frpc.conf"

    echo "[common]" >$tmpconf
    echo "server_addr=$server_addr" >>$tmpconf
    echo "server_port=$server_port" >>$tmpconf
    echo "token=$token" >>$tmpconf
    echo "log_file=$LOGFILE" >>$tmpconf
    echo "log_level=$log_level" >>$tmpconf
    echo "log_max_days=$log_max_days" >>$tmpconf

    config_foreach conf_proxy_add proxy "$tmpconf"

    [ -f "$tmpconf" ] || return 1

    # ===== procd 启动 =====
    procd_open_instance
    procd_set_param command /usr/bin/frpc -c "$tmpconf"
    procd_set_param respawn
    procd_set_param stdout 1
    procd_set_param stderr 1
    procd_close_instance

    [ "$time" -gt 0 ] && frp_add_cru $time
}

stop_service() {
    frp_del_cru
    Reduce_Log $LOGFILE
}
相关推荐
dovens2 小时前
httpslocalhostindex 配置的nginx,一刷新就报404了
运维·nginx
适应规律2 小时前
Docker和虚拟机
运维·docker·容器
A-刘晨阳2 小时前
k8s之镜像拉取策略
运维·docker·容器·kubernetes·运维开发·harbor
IMPYLH3 小时前
【无标题】
linux·运维·服务器·网络·bash
比昨天多敲两行3 小时前
Linux权限管理
linux·运维·服务器
runningshark3 小时前
【Linux】VirtualBox ↔ Ubuntu+WinSCP 文件传输
linux·运维·ubuntu
MXsoft6183 小时前
信创时代的运维“铁三角”:一体化监控、自主底座与A预判
运维
aidream12393 小时前
Linux文件操作-文件打包和压缩(tar/gzip/bzip2/xz/zip)
linux·运维·服务器
迷茫运维路3 小时前
云枢运维管理系统
运维·golang·kubernetes·gin·casbin