Moonlight Game Streaming Without Public IP, Using frp for Remote Gaming (with Video)

Due to certain circumstances, I have recently been using mobile data for my internet connection. When I had a broadband connection, I used to wake up my desktop computer using wakeOnLan on my Raspberry Pi. This allowed me to secretly connect to my desktop computer and play games remotely while at work (usually Final Fantasy 14 fishing). However, since my mobile network doesn’t provide a public IP address, I was curious to see how well game streaming using frp tunneling would work. So, I decided to give it a try…(English version Translated by GPT-3.5, 返回中文)

First, let me clarify a few things

  1. The selected bitrate in Moonlight should not exceed the maximum bandwidth of the server or the router, otherwise there will be significant lag.
  2. My server has a bandwidth of 5 Mbps, which seems to be able to handle streaming at 720p quality. However, games with a lot of motion may appear blurry (as seen in Horizon Zero Dawn).
  3. My desktop computer is connected to the network using 5G (not related to the 5G frequency band used by routers), and I am using an iPad for gaming through the frp tunnel provided by Alibaba Cloud.
  4. Why didn’t I choose to use “Peanut Shell”? I prefer to experiment with things that interest me.
  5. This article is just a record of my personal experiment. Although I also use remote game streaming for games like Onmyoji in my daily life, you may find this article more professional and dedicated to streaming A Comprehensive Guide to PC Game Streaming — Moonlight.

What I used

I used a cloud server with a bandwidth of at least 4 Mbps, preferably located in China (international connections can be slow). In my case, I used Alibaba Cloud.

Installing frps on the server

Download from GitHub:

fatedier frp Releases Page

frp_0.31.1_linux_amd64.tar.gz - for running on a Linux server

frp_0.31.1_windows_amd64.zip - for running on Windows

Installing frp for port forwarding

Installing frp is pretty simple, much simpler than ngrok.

First, download the Linux package and copy it to the server

I’ll be using /usr/local/frps. After downloading the package, use the following command to extract it:

1
tar -zxvf frp_0.31.1_linux_amd64.tar.gz

This will extract the necessary files, and we’re only interested in frps and frps.ini. The other files are not needed.

Next, modify the frps.ini file as follows

Nvidia Game Stream requires the following ports to be exposed:

1
2
[common]
bind_port = 47984

So, my frps.ini configuration is as follows:

1
2
[common]
bind_port = 47984

The bind_port specified above is the communication port between the client and the server. This port must be open. The bind_ip specifies the IP address to listen on, and setting it to 0.0.0.0 means it will listen on all network interfaces. If you have multiple public IP addresses on the server, you can also specify a particular IP address so that only that IP address’s 9200 port can communicate with the server, and other public IP addresses won’t be able to communicate with the 9200 port. This port must be opened, otherwise the frpc client won’t be able to connect to the frps server.

The allow_ports specifies the communication ports for frpc specified in the configuration file below. These remote_ports defined in the configuration file must be allowed here. If you want to access these ports from outside the server, you need to open them.

Finally, start frps. If you are using Alibaba Cloud, don’t forget to add port 9200 to the security group.

1
./frps -c ./frps.ini

For setting up as a service, please refer to the relevant documentation.

Testing the connection via telnet

1
telnet <frps_server_ip> 47984

If you can connect successfully, then the frp tunnel is working.

Setting up frp on the local machine

Download frp_0.31.1_windows_amd64.zip

You’ll find a similar file list as before. I just took the frpc.exe and frpc.ini files from the zip archive.

Modify the configuration file

1
2
3
4
5
6
7
8
9
10
[common]
server_addr = <frps_server_ip>
server_port = 47984
token = <token-received-from-frps-token>

[nvidia-stream-tcp-1]
type = tcp
local_ip = 127.0.0.1
local_port = 48010
remote_port = 48010

Each section name, such as [nvidia-stream-tcp-1], must be unique.

The above configuration is explained as follows:

[nvidia-stream-udp-6] can be interpreted as an ID with uniqueness.
type = udp specifies the communication protocol type, which can be TCP, UDP, or http.
local_ip = 127.0.0.1 specifies the IP that can be accessed on the client.
local_port = 48010 specifies the port that can be accessed on the client.
remote_port = 48010 specifies the port to access the server (the public cloud server in this case).

For example, if you have a public cloud server with IP 64.64.1.222 named “PublicHost” and another company server with IP 10.1.1.100 named “InnerHost”, which cannot be accessed from the internet but can access the internet, and you also have another server at your company with IP 192.168.1.2 named “PrivateHost”, which can only communicate with InnerHost and has all ports open, and PrivateHost cannot access the internet. PrivateHost is deployed with a database on port 3306, and you want to access this port on PrivateHost from the PublicHost’s port 13306 because PrivateHost can only communicate with InnerHost, and InnerHost can access the internet. In this case, you can install the Frpc client on InnerHost with the following complete configuration:

1
2
3
4
5
6
7
8
9
10
[common]
server_addr = 64.64.1.222
server_port = 9200
token = 12345678a

[access-privatehost-db]
type = tcp
local_ip = 192.168.1.2
local_port = 3306
remote_port = 13306

This allows you to access the PrivateHost’s database from the internet through PublicHost’s port 13306.

Run frpc.exe

To run frp client:

1
.\frpc.exe -c .\frpc.ini

With this, the frpc setup is complete. To test if the tunneling is working, you can use telnet for TCP or use dig to check if the DNS is functioning properly (as suggested by the frp author).

Checking if the ports are open

First, change all type = udp configurations in the frpc.ini file to local_ip = 223.5.5.5 and local_port = 53. Then restart frpc. Use dig from any remote server to check if the ports are open. The following example shows the results:

1
dig @<frps_server_ip> -p 53 google.com

Make sure to change the configurations back after testing.

Starting the Game Streaming

Install Moonlight and start playing Horizon Zero Dawn

Here, I’ll be using my iPad. I turned off Wi-Fi and used mobile data (or a mobile hotspot, but in this case, I just wanted to demonstrate that I’m not using a local network).

now-using-mobile-data

Add the server’s IP

add-server-ip

Since we have set up the port forwarding, and the forwarded ports are the same as the GameStream’s original ports, when Moonlight accesses these ports on the server, it is actually accessing these ports on our local machine.

If everything goes well, you should see a locked computer.

locked-pc

If not, you can try the following steps:

  1. Change the configuration back to DNS (local_ip = 223.5.5.5 and local_port = 53), then use dig to confirm.
  2. Test the streaming on the same local network as the PC to ensure that the Nvidia GameStream service is working properly. Check the firewall settings if necessary.

Connecting to the Desktop Computer

Click on the locked computer to initiate the pair request. The iPad will display the following:

ipad-pc-pair-ipad-side

The PC side will show a pop-up message in the bottom right corner:

ipad-pc-pair-pc-side

Enter the same number on the computer, and the pairing process will be completed. (Pairing needs to be done only once)

pair-success

Playing Forza Horizon 4 (with Gameplay Video)

Don’t forget to adjust the parameters; otherwise, there may be lag (because my server’s maximum bandwidth is 5 Mbps).

parameter-setting

Here is a gameplay video. Please forgive my poor gaming skills; this video is only for preview purposes (at 2:57, there is a slight lag, which seems to be caused by the computer, not the network).

You can download the original video with its original bitrate from Baidu Cloud Disk or OneDrive, with the extraction code or access password respectively.

Please note that during the game, the mobile data is constantly downloading. For example, playing for 1 second consumes approximately 500 KB of data. During my 12-minute experience, I consumed approximately 820 MB of data. Based on the incoming and outgoing records from Alibaba Cloud, the bandwidth usage was almost maximum during that period.

all-of-data's

Personal Experience

Here are my personal observations:

  1. Public port forwarding: Unless you have your own public IP address (such as through your home broadband), or if the forwarding bandwidth is sufficient, the results may not be ideal, especially for those who are obsessed with image quality.
  2. Playing games with a controller seems fine. There is some latency, but it is acceptable. However, playing games with a keyboard and mouse results in significant latency, as if the actions are delayed.
  3. Occasional stutters are still a possibility due to the nature of network connections. Personally, I mainly use it for playing Onmyoji or occasionally fishing in Final Fantasy 14 during breaks at work.