跳至主要內容

公网局域网映射

LincZero大约 7 分钟

公网局域网映射

见 "网络工具/转发工具"

GPT

Nginx方案

我有一台公网Debian设备(8.134.151.111)和局域网Ubuntu设备(192.168.31.164),两台机器在不同的环境,我想将公网的8081端口映射到局域网的8081端口

实现这个目标,你需要在公网Debian设备上设置一个反向代理,这样它就可以将来自8081端口的流量转发到局域网Ubuntu设备的8081端口。你可以使用Nginx或者Apache等工具来实现这个功能。这里我提供一个使用Nginx的示例:

首先,在公网Debian设备上安装Nginx:

sudo apt-get update
sudo apt-get install nginx

然后,创建一个新的Nginx配置文件,例如/etc/nginx/conf.d/reverse-proxy.conf,并添加以下内容:

server {
    listen 8081;
    location / {
        proxy_pass http://192.168.31.164:8081;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

最后,重启Nginx:

sudo service nginx restart

这样,公网的8081端口就被映射到局域网的8081端口了。

但是,请注意,你需要确保公网Debian设备可以访问到局域网Ubuntu设备。如果两台设备在不同的物理网络中,你可能需要设置VPN或者其他的网络转发机制。

ssh隧道方案 (仅TCP)

公网访问不了局域网设备,局域网能访问公网

如果局域网设备可以访问公网设备,但公网设备不能访问局域网设备,那么你可以考虑使用SSH隧道技术来解决这个问题。SSH隧道可以让你在局域网设备上建立一个到公网设备的连接,然后公网设备可以使用这个连接来访问局域网设备。

局域网操作

下面是一个步骤,你可以在局域网设备上运行这些命令,以在公网设备上的8081端口和局域网设备上的8081端口之间创建一个SSH隧道:

  1. 在局域网设备上安装sshautossh(如果尚未安装的话):

    sudo apt-get update
    sudo apt-get install ssh autossh
    
  2. 创建SSH密钥对(如果尚未创建的话):

    ssh-keygen
    
    # 例如
    $ ssh-keygen
    Generating public/private rsa key pair.
    Enter file in which to save the key (/root/.ssh/id_rsa): id_rsa
    Enter passphrase (empty for no passphrase): qwe123
    Enter same passphrase again: qwe123
    Your identification has been saved in id_rsa
    Your public key has been saved in id_rsa.pub
    The key fingerprint is:
    SHA256:uS65+kL6mxnJJFCnF4d2/kVHeTskXOw1yoJFd2PJrBk root@msy
    The key's randomart image is:
    +---[RSA 3072]----+
    |  . o..   .+.=++.|
    | . ooo.   ..*E*=o|
    |. ...o   .o..==o.|
    | . .  .  o.. =+  |
    |  . .  .S.  .  . |
    |   +..  ..       |
    |   o+  ..        |
    |  . .+o.         |
    |   .*=oo.        |
    +----[SHA256]-----+
    
  3. 将局域网设备的公钥添加到公网设备的~/.ssh/authorized_keys文件中。你可以通过ssh-copy-id命令来完成这个步骤:

    ssh-copy-id <公网设备用户名>@8.134.151.111
    
    # 例如
    $ ssh-copy-id root@8.134.151.215
    /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
    The authenticity of host '8.134.151.215 (8.134.151.215)' can't be established.
    ED25519 key fingerprint is SHA256:cnincYMzCu8zoJ+26nAZBdayDT9QS8Mq5Sp3Fmn2zoM.
    This key is not known by any other names
    Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
    /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
    /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
    root@8.134.151.215's password:
    
    Number of key(s) added: 1
    
    Now try logging into the machine, with:   "ssh 'root@8.134.151.215'"
    and check to make sure that only the key(s) you wanted were added.
    
  4. 使用autossh创建一个SSH隧道:

    autossh -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -R 8081:localhost:8081 <公网设备用户名>@8.134.151.111
    
    # 例如:
    $ autossh -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -R 8081:localhost:8081 root@8.134.151.215
    Enter passphrase for key '/root/.ssh/id_rsa': qwe123
    Linux iZ7xv8wxsqxfla1txzmm8lZ 5.10.0-21-amd64 #1 SMP Debian 5.10.162-1 (2023-01-21) x86_64
    Welcome to Alibaba Cloud Elastic Compute Service !
    Last login: Fri Nov  3 10:58:22 2023 from 27.45.72.99
    

这样,公网设备上的8081端口就被映射到了局域网设备的8081端口。

公网操作

注意,你可能需要在公网设备上修改SSH配置以允许远程端口转发。这可以通过编辑/etc/ssh/sshd_config文件并添加或修改以下行来完成:

GatewayPorts yes

然后重启SSH服务:

sudo service ssh restart

这个设置将允许从公网设备的任何地址连接到转发的端口。如果你只想从公网设备本身连接到转发的端口,你可以将GatewayPorts设置为localhost

验证

curl http://localhost:8081

Windows版

与上面差不多,保证好公网配置好和局域网安装好ssh后,powershell:

ssh -R 8080:localhost:8080 root@8.134.151.215

如果你想让这个SSH隧道在后台运行,你可以添加-f -N参数:

ssh -f -N -R 52955:localhost:52955 <公网设备用户名>@8.134.151.111

iptable方案 (可UDP)

在这种情况下,你可以在Linux A上使用iptables进行端口转发。这需要在Linux A上运行的网络防火墙配置中进行一些修改。

以下是一种可能的iptables规则配置方式:

# 允许转发
echo 1 > /proc/sys/net/ipv4/ip_forward

# 设置NAT规则
iptables -t nat -A PREROUTING -p udp --dport 7000 -j DNAT --to-destination [LinuxB的内网IP地址]:7000
iptables -t nat -A POSTROUTING -p udp -d [LinuxB的内网IP地址] --dport 7000 -j SNAT --to-source [LinuxA的公网IP地址]

这里的规则意味着:

  1. 当一个UDP包到达Linux A的7000端口时,PREROUTING规则会将它的目标地址更改为Linux B的内网IP地址,端口保持为7000。
  2. 当Linux B向Linux A响应UDP包时,POSTROUTING规则会将源地址更改为Linux A的公网IP地址,这样对于外部的客户端来说,就像是与Linux A进行通信一样。

注意这里的IP地址需要替换为你实际的IP地址。同时,确保Linux A的防火墙允许7000端口的UDP流量。

这种方式需要Linux A具有路由到Linux B的能力,也就是说,Linux A需要知道如何将包发送到Linux B。如果Linux A和Linux B在同一个子网内,或者Linux A知道去往Linux B的路由,那么这通常不是问题。

此外,这种设置可能需要root权限才能进行。如果你没有root权限,你可能需要联系你的系统管理员。

最后,这些更改可能在重启后失效。如果你希望它们在重启后仍然有效,你可能需要将这些命令添加到启动脚本中,或者使用iptables持久化工具,如iptables-persistent

这是一个基础的解决方案,实际的网络环境可能会更复杂,需要更多的配置。例如,如果你的网络中有其他的防火墙或路由设备,你可能需要在这些设备上进行额外的配置。

openVPN (可UDP)

对不起,我之前没有完全理解你的问题。你的情况是Linux A无法直接访问Linux B,但Linux B可以访问Linux A,并且你希望进行UDP流量的转发。这确实比我之前描述的更复杂一些。

你可以考虑使用SSH隧道的UDP版本,也就是VPN。如果你有权限在Linux B上运行服务,那么你可以在那里设置一个VPN服务器,然后在Linux A上连接到这个VPN。这样,Linux A就可以访问Linux B了,然后你就可以使用我之前描述的iptables规则进行端口转发。

OpenVPN是一种常见的VPN解决方案,它支持UDP流量。以下是一个简单的OpenVPN配置示例:

在Linux B(VPN服务器)上:

openvpn --remote [LinuxA的公网IP地址] --dev tun --ifconfig 10.8.0.1 10.8.0.2 --cipher none --auth none --proto udp

在Linux A(VPN客户端)上:

openvpn --remote [LinuxB的公网IP地址] --dev tun --ifconfig 10.8.0.2 10.8.0.1 --cipher none --auth none --proto udp

然后在Linux A上设置iptables规则进行端口转发:

iptables -t nat -A PREROUTING -p udp --dport 7000 -j DNAT --to-destination 10.8.0.1:7000
iptables -t nat -A POSTROUTING -p udp -d 10.8.0.1 --dport 7000 -j SNAT --to-source [LinuxA的公网IP地址]

这只是一个基本的示例,实际的配置可能会更复杂。例如,你可能需要考虑安全性问题,例如使用加密和身份验证而不是--cipher none --auth none。你也可能需要根据你的网络环境调整--ifconfig参数。

请注意,这种方法需要Linux B可以访问Linux A,而且需要在两台机器上都安装OpenVPN。如果你不能在Linux B上运行服务,那么这种方法可能无法工作。