PaperMC / Velocity

The modern, next-generation Minecraft server proxy.
https://papermc.io/software/velocity
GNU General Public License v3.0
1.79k stars 631 forks source link

Feature: Multiple Listeners (2+ ports bind + with unique motd and other) #1046

Open softy-oniguru opened 1 year ago

softy-oniguru commented 1 year ago

I would like to see this function in Velocity, because after switching from Bungeecord I could not find it. In Bungeecord, this is implemented using:

listeners:
    - server1: "address"
    motd: "Welcome to server1"
    ...something...

    - server2: "address"
    motd: "Welcome to server2"
    ...something...

I think you can also implement this somehow using lists, just specify a separate section in the config named [Network] and make a list of servers and connection data into it (bind, motd, show-max-players, online-mode)

My idea about it in the config:

[network]
bind = "localhost:25565"
motd = "<#09add3>A Velocity Server"
show-max-players = 500
#online-mode = true (I think this can be a difficult task, because it is not implemented even in bungeecord)

[network]
bind = "localhost:25566"
motd = "<#d3ad09>A Velocity Server"
show-max-players = 250
#online-mode = false

in JSON form it would look like:

{
  "network": [
    { "bind": "localhost:25565", "motd": "<#09add3>A Velocity Server", "show-max-players": 250, "online-mode": true},
    { "bind": "localhost:25566", "motd": "<#d3ad09>A Velocity Server", "show-max-players": 500, "online-mode": false}
  ]
}

I don't know English well, I use a translator, so there may be inaccuracies in the translation.

softy-oniguru commented 1 year ago

I feel like this will get in a future 4.0.0 update xd we are waiting for update in 2024 šŸ’€

JustEli commented 1 year ago

Fully agreed. Would be extremely useful for bigger networks that want to move to Velocity but are currently stuck on Bungee. I would love to see the possibility to bind multiple IP addresses to different servers (like you can with Bungee).

PedroMPagani commented 1 year ago

why not launch 2 velocities? -> you kind of want 2 netty servers so ;O

PedroMPagani commented 1 year ago

and btw, if you dont know this, you can already do it, you can track hostnames and you can just bind the 0.0.0.0 or the two ips to ptero and velocity on 0.0.0.0, both ips will forward requests.

JustEli commented 1 year ago

why not launch 2 velocities? -> you kind of want 2 netty servers so ;O

Because then you can't send players around between servers.

and btw, if you dont know this, you can already do it, you can track hostnames and you can just bind the 0.0.0.0 or the two ips to ptero and velocity on 0.0.0.0, both ips will forward requests.

It's not an ideal solution, but I'm currently doing something like that. Not ideal, because for one, if you have players with 3 of your servers in their list, it tends to time out the ping for the later ones in their server list, because they are pinging the same netty server multiple times for multiple servers. It's not only for that reason tho.

PedroMPagani commented 1 year ago
  1. YOU mean send between backend servers?
  2. Are you saying that if they ping the same netty server the ping is denied? Are you using any anti ddos service here or are you talking about direct-ip connect?
MrPowerGamerBR commented 1 year ago

Here's another use case that I'm currently using in Waterfall that can't be currently reproduced in Velocity:

Currently my setup is Waterfall + Geyser (standalone), the Waterfall proxy has two listeners: One that is open to everyone, and another localhost bound listener with PROXY protocol enabled. This works, and it is nifty since I'm able to know what connections are Java or Bedrock connections by looking up what listener they connected to, and I can update the Geyser proxy without restarting the Waterfall proxy

However I don't know how I could replicate this setup easily with Velocity, because Velocity doesn't support multiple listeners


I thought about running Geyser directly in Velocity, but then every time I need to update Geyser, I need to restart the entire Velocity proxy. I also have some code that checks if the user is connected via Geyser in PreLoginEvent, and Geyser's API can only check if a player is a Geyser player by its UUID. (which, sadly, the UUID is not present during the PreLoginEvent phase)

I thought about running two Velocity instances, but that's bad since I wouldn't have a "single source of truth" of how many players are connected to the server, and proxy wide broadcasts would be completely borked. (Yes, I know there are solutions about this, such as running RedisBungee and stuff like that... but I would rather not do this)

I thought about running Velocity (connected via PROXY protocol) -> Velocity <- Geyser (connected via PROXY protocol), but it seems that if you are doing Velocity to Velocity connections, you are probably doing something very wrong.

It seems that maybe the solution would be Velocity (with PROXY protocol), then Geyser connects to Velocity and then you have a nginx server running PROXY protocol that redirects Java players to the Velocity instance.

However, it makes the system way more complex compared to the simplicity of setting up two listeners instead.

xism4 commented 1 year ago

Here's another use case that I'm currently using in Waterfall that can't be currently reproduced in Velocity:

Currently my setup is Waterfall + Geyser (standalone), the Waterfall proxy has two listeners: One that is open to everyone, and another localhost bound listener with PROXY protocol enabled. This works, and it is nifty since I'm able to know what connections are Java or Bedrock connections by looking up what listener they connected to, and I can update the Geyser proxy without restarting the Waterfall proxy

However I don't know how I could replicate this setup easily with Velocity, because Velocity doesn't support multiple listeners

I thought about running Geyser directly in Velocity, but then every time I need to update Geyser, I need to restart the entire Velocity proxy. I also have some code that checks if the user is connected via Geyser in PreLoginEvent, and Geyser's API can only check if a player is a Geyser player by its UUID. (which, sadly, the UUID is not present during the PreLoginEvent phase)

I thought about running two Velocity instances, but that's bad since I wouldn't have a "single source of truth" of how many players are connected to the server, and proxy wide broadcasts would be completely borked. (Yes, I know there are solutions about this, such as running RedisBungee and stuff like that... but I would rather not do this)

I thought about running Velocity (connected via PROXY protocol) -> Velocity <- Geyser (connected via PROXY protocol), but it seems that if you are doing Velocity to Velocity connections, you are probably doing something very wrong.

It seems that maybe the solution would be Velocity (with PROXY protocol), then Geyser connects to Velocity and then you have a nginx server running PROXY protocol that redirects Java players to the Velocity instance.

However, it makes the system way more complex compared to the simplicity of setting up two listeners instead.

You can use redisbungee

MrPowerGamerBR commented 1 year ago

Here's another use case that I'm currently using in Waterfall that can't be currently reproduced in Velocity: Currently my setup is Waterfall + Geyser (standalone), the Waterfall proxy has two listeners: One that is open to everyone, and another localhost bound listener with PROXY protocol enabled. This works, and it is nifty since I'm able to know what connections are Java or Bedrock connections by looking up what listener they connected to, and I can update the Geyser proxy without restarting the Waterfall proxy However I don't know how I could replicate this setup easily with Velocity, because Velocity doesn't support multiple listeners I thought about running Geyser directly in Velocity, but then every time I need to update Geyser, I need to restart the entire Velocity proxy. I also have some code that checks if the user is connected via Geyser in PreLoginEvent, and Geyser's API can only check if a player is a Geyser player by its UUID. (which, sadly, the UUID is not present during the PreLoginEvent phase) I thought about running two Velocity instances, but that's bad since I wouldn't have a "single source of truth" of how many players are connected to the server, and proxy wide broadcasts would be completely borked. (Yes, I know there are solutions about this, such as running RedisBungee and stuff like that... but I would rather not do this) I thought about running Velocity (connected via PROXY protocol) -> Velocity <- Geyser (connected via PROXY protocol), but it seems that if you are doing Velocity to Velocity connections, you are probably doing something very wrong. It seems that maybe the solution would be Velocity (with PROXY protocol), then Geyser connects to Velocity and then you have a nginx server running PROXY protocol that redirects Java players to the Velocity instance. However, it makes the system way more complex compared to the simplicity of setting up two listeners instead.

You can use redisbungee

I could, but this makes the stack way more complex since I would need to host a Redis instance AND host two separate Velocity instances.

Here's the solution that I came up with: I forked Velocity and exposed the ConnectionManager to let plugins to be able to setup binds, each bind with their custom settings

Then in my plugin I setup the listeners two listeners: One for Java Edition, then another localhost only bind with PROXY protocol enabled for Geyser, making it work like Bungee's multi listener support.

You may be thinking "well that's more complex than using RedisBungee and two Velocity instances!!!" and to that I say: smh let me have fun it wasn't even that hard šŸ˜­

RezzedUp commented 8 months ago

With the recently announced end of life of Waterfall, the only thing keeping me back from migrating over to Velocity is the lack of this specific feature.

My use case is as follows: I essentially run a group of independent but loosely related servers which happen to share a network. Each one is directly joinable and there is no centralized hub. Now, why would I want independent listeners with distinct configuration? Server lists. I obviously can't reuse the same IP/port for each server, since server lists would correctly identify them as "the same server". With my current setup, I'm able to run several distinct communities under the same network while simultaneously assigning each server a different publicly accessible port rather than simply relying on something like forced hosts.

PedroMPagani commented 8 months ago

would forced hosts not work for you?

RezzedUp commented 8 months ago

would forced hosts not work for you?

No. Again, each one of my servers needs a unique IP/port in order to be listed separately on server lists. I currently achieve this on Waterfall by having multiple listeners bound to different ports. Since Velocity only supports one listener (one port binding) for the entire proxy, forced hosts obviously won't solve this problem.

PedroMPagani commented 8 months ago

pay someone to impl this on velocity

MrPowerGamerBR commented 8 months ago

pay someone to impl this on velocity

Implementing this is not that hard, the only reason Velocity does not support this yet is because of Velocity's configuration format iirc (I may be wrong, check it on PaperMC's Discord server when I asked about it there)

If they just want to migrate to Velocity now with a stop gap solution, it isn't hard to expose the connection manager to plugins

https://github.com/SparklyPower/SparklyVelocity

PedroMPagani commented 8 months ago

do it

JustEli commented 8 months ago

pay someone to impl this on velocity

Implementing this is not that hard, the only reason Velocity does not support this yet is because of Velocity's configuration format iirc (I may be wrong, check it on PaperMC's Discord server when I asked about it there)

If they just want to migrate to Velocity now with a stop gap solution, it isn't hard to expose the connection manager to plugins

https://github.com/SparklyPower/SparklyVelocity

pull request when

alexstaeding commented 8 months ago

would forced hosts not work for you?

No. Again, each one of my servers needs a unique IP/port in order to be listed separately on server lists. I currently achieve this on Waterfall by having multiple listeners bound to different ports. Since Velocity only supports one listener (one port binding) for the entire proxy, forced hosts obviously won't solve this problem.

Would it not be possible to set up multiple NAT mappings to the same internal ip and port? This way you expose multiple ports externally.

You can also achieve a similar result if you have access to multiple external IPs - it shouldn't be a problem to pass L4 packets from multiple IPs/ports to your velocity instance.