多网卡Linux做软路由

多网卡Linux做软路由

背景

电信宽带:家里是电信宽带。

公网ip:电信打10000找人工客服是可以给公网ip (ipv4),ipv6默认就给的。但是这个公网ip是动态分配的,可能过两天就变成了另一个ip地址。

DDNS:用域名+dnspod接口+shell脚本实现ddns。

电信光猫上配置DMZ主机, 或配置端口映射。

以上(公网IP+DDNS动态域名绑定+内网端口映射),可以将内网服务暴露到公网。通过域名:端口访问,基本可以满足日常需求。

问题

但是使用过程中遇到以下几个问题:

  • DMZ的那台主机是我的个人台式电脑,偶尔也是会关闭电脑的。像代理之类的服务,我希望可以长期稳定。
  • 内网端口映射可能会变动,从外网很访问光猫调整配置受到限制。

预期

因此就打算买一台多网卡小主机做软路由,常用的服务直接放到这台小主机上面。

光猫改桥接,光猫LAN直连小主机某个网卡接口,比如enp2s0。

家庭网络(局域网)中的其他设备通过交换机互相连接,最后连接到小主机另一个网卡接口,比如enp3s0 。

小主机负责如下功能:

  • 使用ppp协议和ISP拨号连接。因为小主机网卡接口是以太网,所以实际使用的协议是PPPoE (PPP over Ethernet)
  • 数据路由和NAT。根据其功能,也称这样的小主机为软路由。
  • 向家庭网络其他设备提供DHCP服务。(略,我是直接采购了无线AC和AP,DHCP服务由AC控制器负责了)。

准备

多网卡小主机(我是淘宝搜软路由,下单了一台 N5105,4个千兆接口)

小主机装Linux系统(我是直接让发货前预装CentOS, 厂家给装的CentOS7. )最后写文章的时候改成了CentOS stream 8, 没啥区别,但都是redhat系,其他linux 配置可能会略有区别。

netfilter/iptables基本概念和命令(尤其是数据在网卡,网络stack,四表五链间的传输过程)

实践

配置

开启内核转发

(重启仍生效需要写到配置文件)

cat /proc/sys/net/ipv4/ip_forward

#编辑这个文件
vim /etc/sysctl.conf
# 增加如下配置
net.ipv4.ip_forward = 1

重启linux

shutdown -r now

添加pppoe拨号配置

根据centos pppoe 路由器找到下面这个帖子,是使用cli菜单添加的dsl配置。(nmtui命令)

参考这个:CentOS 8 下配置 PPPoE 拨号上网 – 黑山雁 – 博客园 (cnblogs.com)

以及这个:

http://www.360doc.com/content/22/0608/15/65839694_1035172190.shtml

用nmtui创建了adsl配置,安装了NetworkManager-ppp依赖。

没参考这个,但是很受震撼: https://www.jianshu.com/p/1265004c2922

安装iptables

yum install iptables

备份并清空初始规则

备份自带的规则,清空重建

//备份iptables原始规则
mkdir /etc/iptables
iptables-save > /etc/iptables/rule.v4_origin

//删除用户定义的规则
iptables -F
//删除用户定义的链
iptables -X

iptables软路由规则

Centos实现软路由 参考了点这个, 但是没有pppoe拨号的相关内容。只适用于局域网两个网段的转发。当然,用路由表也可以。 但是这个文章的iptables配置有不符合需求的地方(因为ppp拨号后,动态获取的公网ip,需要动态伪装MASQURADING)。

百度出来乱糟糟的, google了一下,这篇不错:

How to Turn a Linux Server into a Router to Handle Traffic Statically and Dynamically – Part 10

将的很有条理, 还讲了pppoe的情况。iptables大概要类似这样的配置。

# iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
# iptables -A FORWARD -i ppp0 -o enp3s0 -m state --state RELATED,ESTABLISHED -j ACCEPT
# iptables -A FORWARD -i enp3s0 -o ppp0 -j ACCEPT

前面清掉了iptables已有规则,所以这几条规则其实是iptables最前面的规则。注意!!!

这几条规则大概意思是:

  1. 从 ppp0出去的数据自动做源地址映射(从局域网向公网发出的数据包 step2)(记录临时的映射表里,这种行为叫masquerade)
  2. 如果数据是从ppp0进来,向enp3s0出去(从公网向局域网发回的数据包), 并且是已建立的链路(tcp有类似建立session的概念,udp也会在临时记录表里有一段时间的记录),允许通过。
  3. 从enp3s0进来,向ppp0出去的数据包,(从局域网向公网发出的数据包 step1)直接放行。

如果要做暴露路由器上某个端口到公网,以及将局域网某个主机端口映射到路由器上某个端口,则需要进一步的iptables配置。这里先不管,先让局域网能上公网再说。

关防火墙

很多人配到这里就可以用了。很奇怪,我这边还是不行。灵光一闪,是不是防火墙的问题?

//查看防火墙状态
iptables status firewalld
//看到是开着的。。。
//先关掉看看,是不是这个问题
iptables stop firewalld
iptables disable firewalld

关SELinux

还是不行,局域网内主机有极小概率能ping通以下公网,网页打不开。又灵光一闪,是不是selinux开着?

//看下默认配置,是不是开着
vi /etc/selinux/config

//看到一行:SELINUX=enforcing
//改为:SELINUX=disabled


//备份iptables规则
iptables-save > /etc/iptables/rule.v4_20230216_2335
//重启服务器
shutdown -r now

//重启后可以看到,iptables规则已经重置
iptables -L -v
//删除用户定义的规则
iptables -F
//删除用户定义的链
iptables -X
//使用关机前的iptables规则
iptables-restore /etc/iptables/rule.v4_20230216_2335

出现了一个奇怪的问题, 百度能打开(正常),搜索也有结果(正常),但是点击搜索结果,进入页面一直刷新不完整(异常)。

调整ppp包的MSS大小

百思不得其解, google搜索 pppoe nat iptables 三个关键字,下面这边文章给多讲了一点底层的逻辑:

How to Setup a Linux Firewall with PPPoE/NAT/iptables

根据对方给的思路,估摸着大概是PPPoE有附加的字节, **Maximum Segment Size (MSS)**超了。

果然,注意到对方末尾例子中有如下几行, 但是是注释状态。

//...

IPTABLES="iptables"
//...

# echo "Mainly for PPPoE, VPN and DSL (MTU Fix, activate it if you have)"
# echo "Problems with large Downloads over PPPoE"
# $IPTABLES -A OUTPUT -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
# $IPTABLES -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

google搜了下末尾两行, 找到一篇相关的文章,也是说是MSS的问题:

该如何缓解网卡的普遍问题?

文章说:

iptables -A FORWARD-p tcp- -tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

该规则的目的就是改变TCP MSS以适应PMTU(Path MTU)

反正大概就是协议设计的时候没多考虑中间插了一层ppp,包头变大了,能传输的数据要比默认的MTU小一些才行。或者可以自动协商。

试着在这两条链前面加上这两个规则,

iptables -I OUTPUT -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
iptables -I FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

有网了,打完收工。

对了nmtui配置adsl连接的时候,好像也有MSS大小的设置项,可以设小一点试试,说不定可以不用加上面的规则(没去试,不确定)。

设置开机自动restore我们的iptables规则

等等,还记得前面重启电脑,我们写的iptables规则自动丢失了吗。需要改为开机自动restore为我们自己的规则的。

可以自己写个启动脚本,也有现成的。参考:https://blog.csdn.net/Victor2code/article/details/105768946

iptables 重启会失效,需要持久化写好的规则,做成服务启动时加载。

yum install iptables-services
//把我们之前备份的规则复制一份到特定位置
cp /etc/iptables/rules.v4 /etc/sysconfig/iptables
//启动对应的服务
systemctl start iptables.service
systemctl enable iptables.service

多网卡默认网关的问题

多网卡默认网关的问题。

前面ppp的配置也算是与NetworkManager那一套网络工具配套的(nmtui创建了adsl配置,安装了NetworkManager-ppp依赖),

我的软路由的enp2s0接口接了公网(光纤-光猫-接出来的WAN口)。

我的ppp0配置是建立在enp2s0接口之上的,ppp0的ip是ISP动态分配的。

内网连了软路由的enp3s0接口,使用固定ip 192.168.1.1,掩码255.255.255.0,这个直接在desktop的gui界面设置好了(之后这里有个小问题,会自动在对应的配置文件中写入GATEWAY信息)。

这时ip route show命令查看路由表,就会发现,有两条默认网关。而每次启动,这两条默认网关前后顺序是随机的。需要把enp3s0接口的默认网关去掉,否则默认网关可能走了192.168.1.1而不是公网网关。

vim /etc/sysconfig/network-scripts/ifcfg-enp3s0
//用#注释掉GATEWAY一行
#GATEWAY=192.168.1.1

最后提供一份成型的iptables规则备份

[root@localhost ~]# cat /etc/sysconfig/iptables
# Generated by iptables-save v1.8.4 on Thu Feb 16 23:38:34 2023
*filter
:INPUT ACCEPT [5241:1345465]
:FORWARD ACCEPT [8114:591767]
:OUTPUT ACCEPT [8841:914546]
-A FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
-A OUTPUT -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
-A FORWARD -i ppp0 -o enp3s0 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i enp3s0 -o ppp0 -j ACCEPT
COMMIT
# Completed on Thu Feb 16 23:38:34 2023
# Generated by iptables-save v1.8.4 on Thu Feb 16 23:38:34 2023
*security
:INPUT ACCEPT [3797:362810]
:FORWARD ACCEPT [64:87552]
:OUTPUT ACCEPT [8841:914546]
COMMIT
# Completed on Thu Feb 16 23:38:34 2023
# Generated by iptables-save v1.8.4 on Thu Feb 16 23:38:34 2023
*raw
:PREROUTING ACCEPT [23642:2589162]
:OUTPUT ACCEPT [8841:914546]
COMMIT
# Completed on Thu Feb 16 23:38:34 2023
# Generated by iptables-save v1.8.4 on Thu Feb 16 23:38:34 2023
*mangle
:PREROUTING ACCEPT [23642:2589162]
:INPUT ACCEPT [5241:1345465]
:FORWARD ACCEPT [18344:1239420]
:OUTPUT ACCEPT [8841:914546]
:POSTROUTING ACCEPT [8929:1004924]
:LIBVIRT_PRT - [0:0]
-A POSTROUTING -j LIBVIRT_PRT
-A LIBVIRT_PRT -o virbr0 -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill
COMMIT
# Completed on Thu Feb 16 23:38:34 2023
# Generated by iptables-save v1.8.4 on Thu Feb 16 23:38:34 2023
*nat
:PREROUTING ACCEPT [19749:2139220]
:INPUT ACCEPT [13:3286]
:POSTROUTING ACCEPT [30:3747]
:OUTPUT ACCEPT [45:3478]
:LIBVIRT_PRT - [0:0]
-A POSTROUTING -o ppp0 -j MASQUERADE
-A POSTROUTING -o ppp0 -j MASQUERADE
COMMIT
# Completed on Thu Feb 16 23:38:34 2023

配置DDNS

家里用的是电信宽带。打电话10000要客服给了ipv4公网地址,但是公网地址是经常变的。

crond定时任务自动更新dns

后来从DnsPod买了个域名配 DDNS做动态域名解析。动态域名解析用的是DnsPod提供的接口和免费服务。家里192.168.1.7这台主机定时每15分钟,运行一次脚本,获取一下家里主机的公网ip,然后调用DnsPod接口更新域名解析 很显然,是动态域名解析失败了。

cd /usr/local
git clone git@github.com:rehiy/dnspod-shell.git

修改其中的配置文件。主要是调整这里的域名和dnspod账号的token。

dnspod账号token的说明,见这里: https://docs.dnspod.cn/account/dnspod-token/

[root@jingmin-kube-master1 dnspod-shell]# cd /usr/local/dnspod-shell/
[root@jingmin-kube-master1 dnspod-shell]# ls
ardnspod  ddnspod.sh  README.md
[root@jingmin-kube-master1 dnspod-shell]# cat ddnspod.sh 
#!/bin/sh
#

# Import ardnspod functions
. /usr/local/dnspod-shell/ardnspod

# Combine your token ID and token together as follows
#arToken="12345,7676f344eaeaea9074c123451234512d"
arToken="322277,9883b5824e52246cd72bc17c2f80d214"

# Force to use third party API to get IP or not
forceUseThirdApi=false

# Place each domain you want to check as follows
# you can have multiple arDdnsCheck blocks

# IPv4:
#arDdnsCheck "test.org" "subdomain"
#arDdnsCheck "ole12138.top" "www"
arDdnsCheck "ole12138.top" 

# IPv6:
#arDdnsCheck "ole12138.top" "@" 6

看下ardnspod

[root@jingmin-kube-master1 dnspod-shell]# cat ardnspod 
#!/bin/sh
#

#############################################################
# AnripDdns v6.1.1
#
# Dynamic DNS using DNSPod API
#
# Author: Rehiy, https://github.com/rehiy
#                https://www.anrip.com/?s=dnspod
# Collaborators: ProfFan, https://github.com/ProfFan
#
# Usage: please refer to `ddnspod.sh`
#
#############################################################

# TokenID,Token

export arToken=""

# Force to use third party API to get IP or not

export forceUseThirdApi=false

# Get WAN IPv4

arWanIp4() {

    local hostIp

    local lanIps="^$"

    lanIps="$lanIps|(^10\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$)"
    lanIps="$lanIps|(^127\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$)"
    lanIps="$lanIps|(^169\.254\.[0-9]{1,3}\.[0-9]{1,3}$)"
    lanIps="$lanIps|(^172\.(1[6-9]|2[0-9]|3[0-1])\.[0-9]{1,3}\.[0-9]{1,3}$)"
    lanIps="$lanIps|(^192\.168\.[0-9]{1,3}\.[0-9]{1,3}$)"

    case $(uname) in
        'Linux')
            hostIp=$(ip -o -4 addr list | grep -Ev '\s(docker|lo)' | awk '{print $4}' | cut -d/ -f1 | grep -Ev "$lanIps")
        ;;
        Darwin|FreeBSD)
            hostIp=$(ifconfig | grep "inet " | grep -v 127.0.0.1 | awk '{print $2}' | grep -Ev "$lanIps")
        ;;
    esac

    if [ -z "$hostIp" -o "$forceUseThirdApi" = true ]; then
        if type wget >/dev/null 2>&1; then
            hostIp=$(wget -q -O- https://v4.myip.la)
        else
            hostIp=$(curl -s https://v4.myip.la)
        fi
    fi

    if [ -z "$hostIp" ]; then
        echo "arWanIp4 - Can't get ip address"
        return 1
    fi

    if [ -z "$(echo $hostIp | grep -E '^[0-9\.]+$')" ]; then
        echo "arWanIp4 - Invalid ip address $hostIp"
        return 1
    fi

    echo $hostIp

}

# Get WAN IPv6

arWanIp6() {

    local hostIp

    local lanIps="(^$)|(^::1$)|(^[fF][eE][8-9a-fA-F])"

    case $(uname) in
        'Linux')
            hostIp=$(ip -o -6 addr list | grep -Ev '\s(docker|lo)' | awk '{print $4,substr($NF,0,length($NF)-3)}' | sed 's/fore/2592000/g' | sort -k 2 -n | cut -d/ -f1 | grep -Ev "$lanIps" | head -n 1)
        ;;
        Darwin|FreeBSD)
            hostIp=$(ifconfig | grep "inet6 " | awk '{print $2}' | grep -Ev "$lanIps" | head -n 1)
        ;;
    esac

    if [ -z "$hostIp" -o "$forceUseThirdApi" = true ]; then
        if type wget >/dev/null 2>&1; then
            hostIp=$(wget -q -O- https://v6.myip.la)
        else
            hostIp=$(curl -s https://v6.myip.la)
        fi
    fi

    if [ -z "$hostIp" ]; then
        echo "arWanIp6 - Can't get ip address"
        return 1
    fi

    if [ -z "$(echo $hostIp | grep -E '^[0-9a-fA-F:]+$')" ]; then
        echo "arWanIp6 - Invalid ip address"
        return 1
    fi

    echo $hostIp

}

# Dnspod Bridge
# Args: type data

arDdnsApi() {

    local agent="AnripDdns/6.1.0(wang@rehiy.com)"

    local apiurl="https://dnsapi.cn/${1:?'Info.Version'}"
    local params="login_token=$arToken&format=json&$2"

    if type wget >/dev/null 2>&1; then
        wget -q -O- --no-check-certificate -U $agent --post-data $params $apiurl
    else
        curl -s -A $agent -d $params $apiurl
    fi

}

# Fetch Ids of Domain and Record
# Args: recordType domain subdomain

arDdnsIds() {

    local errMsg

    local domainId
    local recordId

    # Get Domain Id
    domainId=$(arDdnsApi "Domain.Info" "domain=$2")
    domainId=$(echo $domainId | sed 's/.*"id":"\([0-9]*\)".*/\1/')

    if ! [ "$domainId" -gt 0 ] 2>/dev/null ;then
        errMsg=$(echo $domainId | sed 's/.*"message":"\([^\"]*\)".*/\1/')
        echo "arDdnsIds - $errMsg"
        return 1
    fi

    # Get Record Id
    recordId=$(arDdnsApi "Record.List" "domain_id=$domainId&sub_domain=$3&record_type=$1")
    recordId=$(echo $recordId | sed 's/.*"id":"\([0-9]*\)".*/\1/')

    if ! [ "$recordId" -gt 0 ] 2>/dev/null ;then
        errMsg=$(echo $recordId | sed 's/.*"message":"\([^\"]*\)".*/\1/')
        echo "arDdnsIds - $errMsg"
        return 1
    fi

    echo $domainId $recordId
}

# Fetch Record Ip
# Args: domainId recordId

arDdnsRecordIp() {

    local errMsg

    local recordIp

    # Get Record Ip
    recordIp=$(arDdnsApi "Record.Info" "domain_id=$1&record_id=$2")
    recordIp=$(echo $recordIp | sed 's/.*,"value":"\([0-9a-fA-F\.\:]*\)".*/\1/')

    # Output Record Ip
    case "$recordIp" in
        [0-9a-fA-F]*)
            echo $recordIp
            return 0
        ;;
        *)
            errMsg=$(echo $recordIp | sed 's/.*"message":"\([^\"]*\)".*/\1/')
            echo "arDdnsRecordIp - $errMsg"
            return 1
        ;;
    esac

}

# Update Record Ip
# Args: domainId recordId subdomain hostIp recordType

arDdnsUpdate() {

    local errMsg

    local recordRs
    local recordIp
    local recordCd

    if [ -z "$5" ]; then
        echo "arDdnsUpdate - Args number error"
        return 1
    fi

    # Update Ip
    recordRs=$(arDdnsApi "Record.Modify" "domain_id=$1&record_id=$2&sub_domain=$3&record_type=$5&value=$4&record_line=%e9%bb%98%e8%ae%a4")
    recordIp=$(echo $recordRs | sed 's/.*,"value":"\([0-9a-fA-F\.\:]*\)".*/\1/')
    recordCd=$(echo $recordRs | sed 's/.*{"code":"\([0-9]*\)".*/\1/')

    # Output Result
    if [ "$recordIp" = "$4" ] && [ "$recordCd" = "1" ]; then
        echo "arDdnsUpdate - success"
        return 0
    else
        errMsg=$(echo $recordRs | sed 's/.*,"message":"\([^"]*\)".*/\1/')
        echo "arDdnsUpdate - $errMsg"
        return 1
    fi

}

# DDNS Check
# Args: Main Sub
arDdnsCheck() {

    local errCode

    local recordType
    local hostIp

    local ddnsIds
    local lastIp
    local postRs

    echo "Fetching Host Ip"
    if [ "$3" = "6" ]; then
        recordType=AAAA
        hostIp=$(arWanIp6)
    else
        recordType=A
        hostIp=$(arWanIp4)
    fi

    errCode=$?
    echo "> Host Ip: $hostIp"
    echo "> Record Type: $recordType"
    if [ $errCode -ne 0 ]; then
        return 1
    fi

    echo "Fetching Ids of $2.$1"
    ddnsIds=$(arDdnsIds "$recordType" "$1" "$2")

    errCode=$?
    echo "> Domain Ids: $ddnsIds"
    if [ $errCode -ne 0 ]; then
        return 1
    fi

    echo "Checking Record for $2.$1"
    lastIp=$(arDdnsRecordIp $ddnsIds)

    errCode=$?
    echo "> Last Ip: $lastIp"
    if [ $errCode -ne 0 ]; then
        return 1
    fi

    if [ "$lastIp" = "$hostIp" ]; then
        echo "> Last Ip is the same as host Ip"
        return 0
    fi

    echo "Updating Record for $2.$1"
    postRs=$(arDdnsUpdate $ddnsIds "$2" "$hostIp" "$recordType")

    errCode=$?
    echo "> $postRs"
    if [ $errCode -ne 0 ]; then
        return 1
    fi

}

域名解析脚本用的是别人提供的。

[root@archlinux dnspod-shell]# git remote -v
origin  git@github.com:rehiy/dnspod-shell.git (fetch)
origin  git@github.com:rehiy/dnspod-shell.git (push)

定时任务

[root@archlinux dnspod-shell]# crontab -l
*/15 * * * * /usr/local/dnspod-shell/ddnspod.sh

如果没有将日志重定向到单独的地方。 那就看下定时任务的系统日志

journalctl -u cronie

PPP重连后自动更新dns解析

参考:https://tldp.org/HOWTO/PPP-HOWTO/ip-up.html

After the link comes up – the /etc/ppp/ip-up script

[root@jingmin-kube-master1 ppp]# cd /etc/ppp
[root@jingmin-kube-master1 ppp]# ls
chap-secrets  eaptls-client  eaptls-server  ip-down  ip-down.ipv6to4  ip-up  ip-up.ipv6to4  ip-up.local  ipv6-down  ipv6-up  options  options.pptpd  pap-secrets
[root@jingmin-kube-master1 ppp]# cat ip-up
#!/bin/bash
# This file should not be modified -- make local changes to
# /etc/ppp/ip-up.local instead

PATH=/sbin:/usr/sbin:/bin:/usr/bin
export PATH

LOGDEVICE=$6
REALDEVICE=$1

[ -f /etc/sysconfig/network-scripts/ifcfg-${LOGDEVICE} ] && /etc/sysconfig/network-scripts/ifup-post --realdevice ${REALDEVICE} ifcfg-${LOGDEVICE}

/etc/ppp/ip-up.ipv6to4 ${LOGDEVICE}

[ -x /etc/ppp/ip-up.local ] && /etc/ppp/ip-up.local "$@"

exit 0

可知,我们需要编辑的是/etc/ppp/ip-up.local

[root@jingmin-kube-master1 ppp]# cat /etc/ppp/ip-up.local 
#!/bin/bash
/usr/local/dnspod-shell/ddnspod.sh | mail -s "ppp reconnected" 784319947@qq.com

PPP重连后延迟重启远程服务器上的nginx

这是我的自定义配置,可忽略不看。

我有台服务器,上面开了nginx. 将其中某些流量转发到了家里的软路由上。

nginx 启动时缓存了域名解析,若要更新域名解析,默认需要重启nginx。

加入了 resolver配置,以及 valid选项,无效。(社区版nginx 这两个配置是无效的)

可以使用变量的方式(但无法使用upstream),也可以使用商业版nginx。

也可以ppp重连时,触发自动更新ddns域名脚本,也触发重启各主机上nginx的脚本。(或者crond定时重启nginx)

生成密钥对

ssh-keygen

公钥丢到要登录的远程服务器

//公钥丢到要登录的远程服务器
//输密码,复制
scp ./id_rsa.pub root@ole12138.cn:/root/.ssh/

//登录远程服务器
ssh root@ole12138.cn

//将刚刚上传的公钥追加到对应的文件/root/.ssh/authorized_keys 末尾
cd /root/.ssh
cat id_rsa.pub >> authorized_keys

//从远程服务器退出
exit

在本机尝试使用刚刚密钥对中的私钥登录远程服务器

ssh -i /root/.ssh/id_rsa root@ole12138.cn

参考: https://developer.aliyun.com/article/269047

参考: https://www.3mu.me/linux%E4%B8%AD%E7%9A%84shell%E7%94%A8ssh%E8%87%AA%E5%8A%A8%E7%99%BB%E5%BD%95%E8%BF%9C%E7%A8%8B%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%90%8E%E6%89%A7%E8%A1%8C%E5%91%BD%E4%BB%A4%E5%B9%B6%E8%87%AA%E5%8A%A8/

没问题后,远程执行命令

sleep 60 && ssh -i /root/.ssh/id_rsa root@ole12138.cn "nginx -s reload"

这里的意思是,暂停60s后,登陆远程服务器,重载一下nginx. (社区版nginx的stream中的resolver的valid配置无效,upstream中出现的域名解析,需要通过重载配置或重启nginx才能生效。)

将此内容追加到/etc/ppp/if-up.local中去,ppp重连后,并更新dns后,60s后重启一下远程服务器上的nginx.

[root@jingmin-kube-master1 ppp]# vim /etc/ppp/ip-up.local 
[root@jingmin-kube-master1 ppp]# cat /etc/ppp/ip-up.local
#!/bin/bash

/usr/local/dnspod-shell/ddnspod.sh | mail -s "ppp reconnected" 784319947@qq.com

sleep 60 && ssh -i /root/.ssh/id_rsa root@ole12138.cn "nginx -s reload"

最好在远程服务器上,也加个定时任务,保证域名解析能更新掉。

配置更新

配置专线

后来家里又拉了一条电信专线。原来的宽带也还在。

专线是固定ip. 宽带是pppoe拨号。

配置固定IP:专线插到路由器另一个网口。 用的nmtui命令,比较傻瓜式。

配置iptables转发:类似前面配置pppoe, 专线固定ip和内网的通信, 也需要配置iptables FORWARD链。并且NAT需要做MASQURADE.

这里直接给出最后的 /etc/sysconfig/iptables配置。 基本是在前面pppoe的配置上作了些改动。

[root@jingmin-kube-master1 ~]# cat /etc/sysconfig/iptables
# Generated by iptables-save v1.8.4 on Thu Feb 16 23:38:34 2023
*filter
:INPUT ACCEPT [5241:1345465]
:FORWARD ACCEPT [8114:591767]
:OUTPUT ACCEPT [8841:914546]
#-A FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
-A FORWARD -i ppp0 -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
-A FORWARD -o ppp0 -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
#-A OUTPUT -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
-A OUTPUT -o ppp0 -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
-A FORWARD -i ppp0 -o enp3s0 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i enp3s0 -o ppp0 -j ACCEPT
-A FORWARD -i enp3s0 -o enp4s0 -j ACCEPT
-A FORWARD -i enp4s0 -o enp3s0 -j ACCEPT
COMMIT
# Completed on Thu Feb 16 23:38:34 2023
# Generated by iptables-save v1.8.4 on Thu Feb 16 23:38:34 2023
*security
:INPUT ACCEPT [3797:362810]
:FORWARD ACCEPT [64:87552]
:OUTPUT ACCEPT [8841:914546]
COMMIT
# Completed on Thu Feb 16 23:38:34 2023
# Generated by iptables-save v1.8.4 on Thu Feb 16 23:38:34 2023
*raw
:PREROUTING ACCEPT [23642:2589162]
:OUTPUT ACCEPT [8841:914546]
COMMIT
# Completed on Thu Feb 16 23:38:34 2023
# Generated by iptables-save v1.8.4 on Thu Feb 16 23:38:34 2023
*mangle
:PREROUTING ACCEPT [23642:2589162]
:INPUT ACCEPT [5241:1345465]
:FORWARD ACCEPT [18344:1239420]
:OUTPUT ACCEPT [8841:914546]
:POSTROUTING ACCEPT [8929:1004924]
:LIBVIRT_PRT - [0:0]
-A POSTROUTING -j LIBVIRT_PRT
-A LIBVIRT_PRT -o virbr0 -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill
COMMIT
# Completed on Thu Feb 16 23:38:34 2023
# Generated by iptables-save v1.8.4 on Thu Feb 16 23:38:34 2023
*nat
:PREROUTING ACCEPT [19749:2139220]
:INPUT ACCEPT [13:3286]
:POSTROUTING ACCEPT [30:3747]
:OUTPUT ACCEPT [45:3478]
:LIBVIRT_PRT - [0:0]
-A POSTROUTING -o ppp0 -j MASQUERADE
-A POSTROUTING -o enp4s0 -j MASQUERADE
COMMIT
# Completed on Thu Feb 16 23:38:34 2023

然后查看路由表

ip route show

可能会有两条默认路由。(nmtui配置时, 两个接口都允许作为默认路由的原因)。 我这里专线默认metric值低一点, 优先级更高, 不管了。

TODO

iptables端口映射

之前说到如果有暴露内网端口到公网的需求(向公网提供服务),前面提到的这边文章的代码中有例子,有需要可以看下。

How to Setup a Linux Firewall with PPPoE/NAT/iptables

也可以考虑使用nginx做tcp、udp转发。

若装docker可能会影响到现有规则

还有就是如果路由器上装了docker,好像会影响iptables。(docker好像自动加了些规则,可能要适配一下的)。 虽然路由器专机专用最好(Keep it simple and stupid),但是路由器有公网ip能ddns绑域名,而且软路由性能也过剩的。装个docker放点服务个人用用还是挺方便的。

后来装了docker,看起来暂时没啥问题。又装了k8s和flannel网络插件,也没啥问题。

内网使用公网ip访问内网服务的问题

NAT Lookback 与 Hairpin NAT

https://www.cnblogs.com/dream397/p/14522392.html

家庭网络公网ip封80端口的问题

注意:ddns+linux软路由网关,使家庭网络建站和向公网提供服务成为可能。但是注意:默认的80/443端口,运营商(电信)是封掉的。其他端口正常。

https://www.bilibili.com/read/cv15787877/

参考或待整理:

https://cn.bing.com/search?q=centos%20%E8%BD%AF%E8%B7%AF%E7%94%B1&qs=n&form=QBRE&pc=U316&sp=-1&pq=&sc=0-0&sk=&cvid=2424D4BA216F42818C39410E67DEA45E&ghsh=0&ghacc=0&ghpl=

https://blog.csdn.net/ichen820/article/details/115549050

https://www.jianshu.com/p/196e57a99a9a

https://cn.bing.com/search?q=route+%E5%92%8C+iptables+%E5%8C%BA%E5%88%AB&PC=U316&first=11&FORM=PORE

IPTables packet traverse map

https://www.jianshu.com/p/653122f8433d

https://cn.bing.com/search?q=centos+dns+server&PC=U316&FORM=CHROMN

https://cloud.tencent.com/developer/article/1804618

https://www.cnblogs.com/travis-li/p/12908739.html

https://blog.csdn.net/wesleyflagon/article/details/80272696

https://cn.bing.com/search?q=linux+%e5%a4%9a%e7%bd%91%e5%8d%a1+%e8%bd%ac%e5%8f%91&qs=RI&pq=%e5%a4%9a%e7%bd%91%e5%8d%a1+%e8%bd%ac%e5%8f%91&sk=PRES1RI1&sc=2-6&cvid=245A9019D3E5492DA403E44DE47E83E8&FORM=QBRE&sp=2


评论

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注