前置条件
- 有一台能够运行内网穿透服务的公网服务器(如 阿里云ECS 等),具有独立的公网 IP ,并配置相应域名解析,作为此处的 服务端
- 有一台能够运行在个人内网的服务器,其能够运行 Minecraft JAVA 服务端,作为此处的 客户端
网络拓扑

开始部署
服务端配置
第一步,安装部署FRPS。访问 FRP Github Release 发布页,按照服务端的系统架构选择相应的压缩包下载并上传至服务器(或使用以下命令直接下载至服务器)
wget https://github.com/fatedier/frp/releases/download/v0.54.0/frp_0.54.0_linux_amd64.tar.gz
解压至所期望的安装位置,并设置软链接至如 /usr/bin 的PATH路径下。软件包内包含有:frps(服务端可执行文件)、frpc(客户端可执行文件)、一些示例配置文件等等,此处主要关注frps
tar --gzip -xvf frp_0.54.0_linux_amd64.tar.gz
sudo mv frp_0.54.0_linux_amd64 /opt
sudo ln -s /opt/frp_0.54.0_linux_amd64/frps /usr/bin/frps
输入以下命令确保链接路径正确指向FRPS可执行程序
frps -v
若无误应当得到当前所下载的FRP版本信息:0.54.0
第二步,创建FRPS配置目录以及配置文件。按照惯例,我们将配置创建至系统 /etc 目录下
sudo mkdir /etc/frp
sudo touch /etc/frp/frps.toml
作为此处的示例,在创建的frps.toml配置文件中填入以下配置内容(其中的__your_token_here__请修改为自己设置的密钥)
# 设置服务端监听连接的地址
bindAddr = "0.0.0.0"
# 设置服务端用于接收TCP连接的端口
bindPort = 5443
# 设置服务端用于接收KCP(UDP)连接的端口
kcpBindPort = 5443
# 设置服务端用于接收QUIC(UDP)连接的端口
quicBindPort = 5445
# QUIC协议的相关配置(默认)
transport.quic.keepalivePeriod = 10
transport.quic.maxIdleTimeout = 30
transport.quic.maxIncomingStreams = 100000
# 设置连接池用于减少多用户访问时的连接建立时间
transport.maxPoolCount = 5
# 设置是否强制在FRPS服务端和FRPC客户端之间的通讯启用TLS加密
transport.tls.force = false
# 设置HTTP/HTTPS代理端口
vhostHTTPPort = 80
vhostHTTPSPort = 443
# 设置客户端鉴权方法(默认为token)
auth.method = "token"
# 设置鉴权密码(token)
auth.token = "__your_token_here__"
# 设置每个客户端所能使用的最大端口数目,0代表没有限制
maxPortsPerClient = 0
# 设置服务端根域名,用于在客户端中设置subdomian参数(如,服务端subDomainHost为i2cy.tech,客户端设置subdomain为mc,则访问mc.i2cy.tech即可代理到客户端的对应服务)
subDomainHost = "i2cy.tech"
第三步(可选),将frps设置为随系统启动,并由systemd托管。创建一个名为 frps.service 的文件,并填入以下内容
[Unit]
Description=Frp Server Service
After=network.target
[Service]
Type=simple
User=root
Group=root
Restart=always
RestartSec=5s
ExecStart=/usr/bin/frps -c /etc/frp/frps.toml
LimitNOFILE=1048576
[Install]
WantedBy=multi-user.target
将文件设置为可执行,并移动至 /etc/systemd/system 目录下
chmod +x frps.service
sudo mv frps.service /etc/systemd/system
启用此服务并启动
sudo systemctl enable frps.service
sudo service frps start
查看frps运行状态,若输出日志正常,则部署成功
sudo service frps status
● frps.service - Frp Server Service
Loaded: loaded (/etc/systemd/system/frps.service; enabled; vendor preset: enabled)
Active: active (running) since Sun 2024-02-04 00:24:56 CST; 3 days ago
Main PID: 957668 (frps)
Tasks: 6 (limit: 463)
Memory: 27.1M
CPU: 1h 6min 1.031s
CGroup: /system.slice/frps.service
└─957668 /usr/bin/frps -c /etc/frp/frps.toml
客户端配置
第一步,与服务端一样,将FRP可执行文件链接到 /usr/bin 下。此处主要关注frpc(客户端)
wget https://github.com/fatedier/frp/releases/download/v0.54.0/frp_0.54.0_linux_amd64.tar.gz
tar --gzip -xvf frp_0.54.0_linux_amd64.tar.gz
sudo mv frp_0.54.0_linux_amd64 /opt
sudo ln -s /opt/frp_0.54.0_linux_amd64/frpc /usr/bin/frpc
第二步,与服务端一样,创建FRPS配置目录以及配置文件。按照惯例,我们将配置创建至系统 /etc 目录下
sudo mkdir /etc/frp
sudo touch /etc/frp/frpc.toml
编写frpc配置文件。作为此处的实例,在创建的frpc.toml配置文件中填入以下配置内容(其中的__your_token_here__请修改为自己先前设置的密钥,与frps.toml中的相同)
# 服务端的IP地址和端口,这里选择5445(QUIC/UDP)端口,QUIC协议相较于KCP和TCP更快更省流量
serverAddr = "i2cy.tech"
serverPort = 5445
# 设置传输协议,此处为QUIC
transport.protocol = "quic"
# 设置验证方式,与服务端相同
auth.method = "token"
# 设置密钥,与服务端相同
auth.token = "__your_token_here__"
# 设置连接池
transport.poolCount = 5
# QUIC协议相关设置,此处默认
transport.quic.keepalivePeriod = 10
transport.quic.maxIdleTimeout = 30
transport.quic.maxIncomingStreams = 100000
# 启用TLS
transport.tls.enable = true
# MC服务器穿透
[[proxies]]
name = "mc"
type = "tcp"
localIP = "AppServer"
localPort = 25500
remotePort = 30010
healthCheck.type = "tcp"
healthCheck.timeoutSeconds = 3
healthCheck.maxFailed = 3
healthCheck.intervalSeconds = 10
transport.proxyProtocolVersion = "v2"
# Dynmap地图插件Web页面穿透
[[proxies]]
name = "dynmap-mc"
type = "http"
# 此处指向本地Nginx服务器
localIP = "127.0.0.1"
localPort = 8080
subdomain = "mc"
hostHeaderRewrite = "mc.i2cy.tech"
requestHeaders.set.x-from-where = "frp"
transport.proxyProtocolVersion = "v2"
# -*- 若你没有SSL证书以及相关配置需求,此条注释以下的内容请不要加入配置 -*-
# Dynmap地图插件Web页面穿透,SSL
[[proxies]]
name = "dynmap-mc-ssl"
type = "https"
# 此处指向本地Nginx服务器
localIP = "127.0.0.1"
localPort = 8443
subdomain = "mc"
transport.proxyProtocolVersion = "v2"
*注意,请添加相应的子域名解析记录。按此处配置文件为例,设置的subdomain为mc,根域名为i2cy.tech,请在你的域名提供服务商控制台处添加mc.i2cy.tech到服务端IP的域名解析
第三步(可选),将frpc设置为随系统启动,并由systemd托管。创建一个名为 frpc.service 的文件,并填入以下内容
[Unit]
Description=Frp Client Service
After=network.target
[Service]
User=root
Group=root
Type=simple
DynamicUser=true
Restart=always
RestartSec=5s
ExecStart=frpc -c /etc/frp/frpc.toml
ExecReload=frpc reload -c /etc/frp/frpc.toml
LimitNOFILE=1048576
CPUSchedulingPolicy=rr
CPUSchedulingPriority=3
[Install]
WantedBy=multi-user.target
Alias=frpc.service
将文件设置为可执行,并移动至 /etc/systemd/system 目录下,随后设为启用并启动服务
chmod +x frpc.service
sudo mv frpc.service /etc/systemd/system
sudo systemctl enable frpc.service
sudo service frpc start
第四步,修改你的Minecraft服务端设置,启用PaperMC核心内置的proxy_protocol解析,修改位于Minecraft服务器运行目录(核心.jar文件所在位置)下的 config/paper-global.yml,将proxy条目内的proxy-protocol选项修改为true,片段截取如下:
proxies:
bungee-cord:
online-mode: true
proxy-protocol: true
velocity:
enabled: false
online-mode: false
secret: ''
修改完成后重启MC服务器。至此,你的Minecraft服务器已经能够正确获得玩家真实IP地址了,终端输出的玩家登录内容正确显示IP如下所示

但是,到此为止Dynmap世界地图插件依然不能正确获得Web端访客的IP地址,于是继续
第五步,安装Nginx并设置反向代理。此处所用的系统是Debian系列(Ubuntu同理),可用APT包管理器安装,其它系统安装方式在此处不另作讨论
sudo apt update && sudo apt install nginx
启用Nginx系统服务并启动
sudo systemctl enable nginx
sudo service nginx start
创建Nginx配置文件并编辑,按照规范不直接编辑Nginx默认配置,而在 /etc/nginx/conf.d 下新建一配置文件,此处命名为dynmap.conf。打开并修改 /etc/nginx/conf.d/dynmap.conf,填入以下内容
server {
# 监听端口,与frpc.toml中设置相同
listen 8080 proxy_protocol;
# 注意此处的server_name一定要与frp设置的相同
# 例如你的根域名为i2cy.tech,frpc设置的subdomain为mc,则此处应写为mc.i2cy.tech
server_name mc.i2cy.tech;
# 设置访问日志储存位置
access_log /var/log/nginx/mc.i2cy.tech.non-ssl.access.log;
error_log /var/log/nginx/mc.i2cy.tech.non-ssl.error.log;
# proxy_protocol相关设置
set_real_ip_from 0.0.0.0/0;
real_ip_header proxy_protocol;
location / {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_protocol_addr;
proxy_set_header X-Real-IP $proxy_protocol_addr;
# 此处定向到你的dynmap插件Web地址,默认为8123端口
proxy_pass http://127.0.0.1:8123/;
}
}
# -*- 若你没有SSL证书以及相关配置需求,此条注释以下的内容请不要加入配置 -*-
server {
# 监听端口,与frpc.toml中设置相同
listen 8443 ssl proxy_protocol;
# 注意此处的server_name一定要与frp设置的相同
# 例如你的根域名为i2cy.tech,frpc设置的subdomain为mc,则此处应写为mc.i2cy.tech
server_name mc.i2cy.tech;
# 设置访问日志储存位置
access_log /var/log/nginx/mc.i2cy.tech.access.log;
error_log /var/log/nginx/mc.i2cy.tech.error.log;
# SSL证书设置
ssl_certificate /etc/letsencrypt/live/mc.i2cy.tech/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mc.i2cy.tech/privkey.pem;
# SSL验证相关设置
ssl_session_timeout 5m; #cache durations
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; #crypto
ssl_protocols TLSv1.1 TLSv1.2; #avaliable TLS protocols
ssl_prefer_server_ciphers on; #use prefered server ciphers
# proxy_protocol相关设置
set_real_ip_from 0.0.0.0/0;
real_ip_header proxy_protocol;
location / {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_protocol_addr;
proxy_set_header X-Real-IP $proxy_protocol_addr;
# 此处定向到你的dynmap插件Web地址,默认为8123端口
proxy_pass http://127.0.0.1:8123/;
}
}
保存后重启Ngnix服务
service nginx restart
在自己的浏览器中访问Dynmap地址,此处为http://mc.i2cy.tech/,随后观察nginx访问日志
tail -f /var/log/nginx/mc.i2cy.tech.non-ssl.access.log
可以看到访客的IP地址被正确解析到了每行开头

对于大多数人讲,此刻已经完成所有配置了,但如果你的Nginx服务与Minecraft服务并非运行在同一服务器上,则另外需要修改dynmap插件配置文件添加对Nginx服务所在服务器内网IP地址的信任,见下一步
第六步(补充),修改dynmap插件配置文件添加对Nginx服务所在服务器内网IP地址的信任。修改位于Minecraft服务器运行目录(核心.jar文件所在位置)下的 plugins/dynmap/configuration.txt ,找到 trusted-proxies 条目并在其下方添加Ngnix服务器的内网IP地址(例如MC服务器内网IP为:10.0.0.101,Nginx服务器内网IP为:10.0.0.102,则添加一行 – “10.0.0.102”,紧跟 – “0:0:0:0:0:0:0:1” 之后,注意缩进)。修改后的配置片段截取如下
# Trusted proxies for web server - which proxy addresses are trusted to supply valid X-Forwarded-For fields
trusted-proxies:
- "127.0.0.1"
- "0:0:0:0:0:0:0:1"
- "10.0.0.102"
大功告成!现在登陆你的MC服务器,用同一台电脑再打开浏览器访问你的Dynmap Web地址,若聊天功能启用(默认启用),则当你在Web左下角的聊天框输入内容并发送时,会自动附上你的游戏内名称,如下所示

游戏内玩家看到的内容也会显示玩家名称,如下所示

Dynmap网页端同步显示玩家名称的原理概述大致如下:
1. 玩家登陆后,dynmap插件从PaperMC核心底层获取玩家IP地址,并创建IP-玩家的映射关系,映射信息储存在plugins/dynmap/ids-by-ip.txt文件中
2. 根据先前创建的映射关系,若有与该玩家IP相同的浏览器用户访问到Dynmap的Web页面,则dynmap插件自动将该浏览器与对应玩家绑定在一起,在浏览器中的操作将被视为是该玩家的操作