Minecraft server without port-forwarding

Let friends join your server without port forwarding using ngrok

Home Games Software In Your Browser Animation Tutorials Miscellaneous
Not everyone wants to or is able to port-forward their router so friends can join their Minecraft server. Fortunately, it is easy to share your server without port forwarding using secure tunneling services like ngrok. Below is a condensed tutorial showing you how to use ngrok with your Minecraft server.

Note: This will only work with Java Edition servers because at the time of writing, ngrok does not support UDP, which Bedrock servers use.

Part 0: Download the Minecraft server software

If you already have a server set up, you can skip to Part 1.
If you want to extend a LAN world instead of a dedicated server you can also skip to Part 1.
You can download the server software for the latest release version of Minecraft Java Edition here.
Create a new folder and place the server software in that folder.

Part 1: Setup Ngrok

Note: Windows users, instead of running ./ngrok, run ngrok.exe
  1. Create an account at ngrok.com. This is free and you will need one to use ngrok.
  2. Open the ngrok web dashboard.
  3. Follow steps 1-3 on the ngrok dashboard.

Part 2: Run the server with ngrok

Steps 1 and 2 can be performed in any order.
  1. Start Ngrok: ./ngrok tcp 25565
    If you're using a port other than the default port, update the last argument above accordingly.
    This works with LAN worlds too! Upon opening the world to LAN, write the port listed in the game's chat instead of 25565 in the ngrok command.
  2. Start the Minecraft server: java -jar server.jar nogui
    You do not need to install Java separately to run Java edition if Minecraft is already installed on your system. See Part 1 of Installing Optifine Without Java to find the path where Minecraft manages its own copy of Java.
  3. Copy your public ngrok address.
    The address will be listed under Forwarding in the terminal window. Copy it without the tcp://. This is the address your friends will connect to when they join your server. For example, if my public ngrok address was tcp://0.tcp.ngrok.io:19565, I would instruct people to paste 0.tcp.ngrok.io:19565 into the Direct Connect box.
  4. Join your server and play! Note that each time you start ngrok, your public address will change. Keep this in mind when connecting people to your server.
    In addition, remember to close ngrok when you stop your server.

Automating Part 2

With a simple script you can automate the startup and shutdown of ngrok and your server. Examples:

macOS / Linux

    # Stop ngrok if the script is stopped with ctrl-c
    trap ctrl_c INT
    
    function ctrl_c() {
            killall ngrok
    }
    
    # stop ngrok if it is already running
    killall ngrok
    
    # start ngrok
    (./ngrok tcp 25565 -log=stdout &)
    
    # start the server
    java -jar server.jar nogui
    
    # if the server stops (/stop or crash), stop ngrok
    killall ngrok
Windows (Batch)

@echo off

taskkill /f /im ngrok.exe 

START /b cmd /c ngrok tcp 25565 -log=stdout
java -jar server.jar nogui

taskkill /f /im ngrok.exe 
Windows (Powershell)

# Run using powershell -ExecutionPolicy Bypass -File script.ps1 

# stop Ngrok it if is running
ps ngrok -ErrorAction SilentlyContinue | kill -PassThru
try
{
    cmd.exe /c "START /b cmd /c ngrok tcp 25565 -log=stdout"
    java -jar server.jar nogui
}
finally
{
    # if the server is stopped, crashes, or the script is killed, stop ngrok
    Stop-Process -Name "ngrok"
    write-host "Stopped Ngrok"
}
The =log=stdout flag tells ngrok to print to the shell normally, instead of displaying a custom shell UI. Your public address will be listed in the log as a message that looks like this: lvl=info msg="started tunnel" obj=tunnels name=command_line addr=//localhost:25565 url=tcp://0.tcp.ngrok.io:18239

The Windows Batch script cannot detect when it is terminated, while the Powershell and *nix scripts can. On macOS (zsh), the async ngrok process will automatically be stopped when the script is stopped. On Linux this is not always the case. Test this on your distro and shell to determine the behavior and adjust the script accordingly.