/infrared

An ultra lightweight minecraft reverse proxy and idle placeholder

Primary LanguageGoApache License 2.0Apache-2.0

Discord Docker Pulls

build GitHub

Infrared - a Minecraft Proxy

An ultra lightweight Minecraft reverse proxy and idle placeholder: Ever wanted to have only one exposed port on your server for multiple Minecraft servers? Then Infrared is the tool you need! Infrared works as a reverse proxy using a subdomain to connect clients to a specific Minecraft server. It works similar to Nginx for those of you who are familiar.

Features

  • Reverse Proxy
  • Display Placeholder Server
  • Autostart Server when pinged
  • Logger Callback URLs
  • HAProxy Protocol Support
  • TCPShield/RealIP Protocol Support
  • Prometheus Support
  • REST API

Deploy

$ docker build --no-cache -t haveachin/infrared:latest https://github.com/haveachin/infrared.git &&
  docker image prune -f --filter label=stage=intermediate &&
  docker run -d --name infrared --restart=unless-stopped -it -v /usr/local/infrared/configs/:/configs -p 25565:25565/tcp --expose 25565 haveachin/infrared:latest

Update

$ docker build --no-cache -t haveachin/infrared:latest https://github.com/haveachin/infrared.git &&
  docker image prune -f --filter label=stage=intermediate &&
  docker stop infrared &&
  docker rm infrared &&
  docker run -d --name infrared --restart=unless-stopped -it -v /usr/local/infrared/configs/:/configs -p 25565:25565/tcp --expose 25565 haveachin/infrared:latest

Environment Variables

Info: Command-line flags override environment variables.

INFRARED_CONFIG_PATH is the path to all your server configs [default: "./configs/"] INFRARED_RECEIVE_PROXY_PROTOCOL if Infrared should be able to receive proxy protocol [default: "false"]

INFRARED_API_ENABLED if the api should be enabled [default: "false"]
INFRARED_API_BIND change the http bind option [default: "127.0.0.1:8080"]

INFRARED_PROMETHEUS_ENABLED enables the Prometheus stats exporter [default: "false"]
INFRARED_PROMETHEUS_BIND specifies what the Prometheus HTTP server should bind to [default: ":9100"]

Command-Line Flags

-config-path specifies the path to all your server configs [default: "./configs/"]

-receive-proxy-protocol if Infrared should be able to receive proxy protocol [default: false]

-enable-prometheus enables the Prometheus stats exporter [default: false]

-prometheus-bind specifies what the Prometheus HTTP server should bind to [default: :9100]

Example Usage

./infrared -config-path="." -receive-proxy-protocol=true -enable-prometheus -prometheus-bind="localhost:9123"

Proxy Config

Field Name Type Required Default Description
domainName String true localhost Should be fully qualified domain name.
Note: Every string is accepted. So localhost is also valid.
listenTo String true :25565 The address (usually just the port; so short term :port) that the proxy should listen to for incoming connections.
Accepts basically every address format you throw at it. Valid examples: :25565, localhost:25565, 0.0.0.0:25565, 127.0.0.1:25565, example.de:25565
proxyTo String true The address that the proxy should send incoming connections to. Accepts Same formats as the listenTo field.
proxyBind String false The local IP that is being used to dail to the server on proxyTo. (Same as Nginx proxy-bind)
disconnectMessage String false Sorry {{username}}, but the server is offline. The message a client sees when he gets disconnected from Infrared due to the server on proxyTo won't respond. Currently available placeholders:
- username the username of player that tries to connect
- now the current server time
- remoteAddress the address of the client that tries to connect
- localAddress the local address of the server
- domain the domain of the proxy (same as domainName)
- proxyTo the address that the proxy proxies to (same as proxyTo)
- listenTo the address that Infrared listens on (same as listenTo)
timeout Integer true 1000 The time in milliseconds for the proxy to wait for a ping response before the host (the address you proxyTo) will be declared as offline. This "online check" will be resend for every new connection.
spoofForcedHost String false If Infrared should modify the handshake packet to spoof BungeeCords forced_hosts option.
proxyProtocol Boolean false false If Infrared should use HAProxy's Proxy Protocol for IP forwarding.
Warning: You should only ever set this to true if you now that the server you proxyTo is compatible.
realIp Boolean false false If Infrared should use TCPShield/RealIP Protocol for IP forwarding.
Warning: You should only ever set this to true if you now that the server you proxyTo is compatible.
docker Object false See Docker Optional Docker configuration to automatically start a container and stop it again if unused.
Note: Infrared will not take direct connections into account. Be sure to route all traffic that connects to the container through Infrared.
onlineStatus Object false This is the response that Infrared will give when a client asks for the server status and the server is online.
offlineStatus Object false See Response Status This is the response that Infrared will give when a client asks for the server status and the server is offline.
callbackServer Object false See Callback Server Optional callback server configuration to send events as a POST request to a specified URL.

Docker

Field Name Type Required Default Description
dnsServer String false 127.0.0.11 The address of the DNS that resolves the container names.
containerName String true The name of the container that should be automatically started/stopped.
portainer Object false Optional Portainer configuration for authorization management.

Portainer

More info on Portainer.

Field Name Type Required Default Description
address String true URL of the Portainer instance.
endpointId String true The ID typically an integer of the docker endpoint in the portainer instance.
username String true Username for the Portainer user.
password String true Password for the Portainer user.

Response Status

Field Name Type Required Default Description
versionName String false Infrared 1.18 The version name of the Minecraft Server.
protocolNumber Integer true 757 The protocol version number.
maxPlayers Integer false 20 The maximum number of players that can join the server.
Note: Infrared will not limit more players from joining. This number is just for display.
playersOnline Integer false 0 The number of online players.
Note: Infrared will not that this number is also just for display.
playerSamples Array false An array of player samples. See [Player Sample](#Player Sample).
iconPath String false The path to the server icon.
motd String false The motto of the day, short MOTD.

Player Sample

Field Name Type Required Default Description
Name String true Username of the player.
uuid String false UUID of the player.

Callback Server

Field Name Type Required Default Description
url String true URL of the callback server URL.
events Array true A string array of event names. Currently available event names are:
- Error will send error logs
- PlayerJoin will send player joins
- PlayerLeave will send player leaves
- ContainerStart will send container starts
- ContainerStop will send container stops

Examples

Minimal Config

min.example.com
{
  "domainName": "mc.example.com",
  "proxyTo": ":8080"
}

Full Config

full.example.com
{
  "domainName": "mc.example.com",
  "listenTo": ":25565",
  "proxyTo": ":8080",
  "proxyBind": "0.0.0.0",
  "proxyProtocol": false,
  "realIp": false,
  "timeout": 1000,
  "disconnectMessage": "Username: {{username}}\nNow: {{now}}\nRemoteAddress: {{remoteAddress}}\nLocalAddress: {{localAddress}}\nDomain: {{domain}}\nProxyTo: {{proxyTo}}\nListenTo: {{listenTo}}",
  "docker": {
    "dnsServer": "127.0.0.11",
    "containerName": "mc",
    "timeout": 30000,
    "portainer": {
      "address": "localhost:9000",
      "endpointId": "1",
      "username": "admin",
      "password": "foobar"
    }
  },
  "onlineStatus": {
    "versionName": "1.18",
    "protocolNumber": 757,
    "maxPlayers": 20,
    "playersOnline": 2,
    "playerSamples": [
      {
        "name": "Steve",
        "uuid": "8667ba71-b85a-4004-af54-457a9734eed7"
      },
      {
        "name": "Alex",
        "uuid": "ec561538-f3fd-461d-aff5-086b22154bce"
      }
    ],
    "motd": "Join us!"
  },
  "offlineStatus": {
    "versionName": "1.18",
    "protocolNumber": 757,
    "maxPlayers": 20,
    "playersOnline": 0,
    "motd": "Server is currently offline"
  },
  "callbackServer": {
    "url": "https://mc.example.com/callback",
    "events": [
      "Error",
      "PlayerJoin",
      "PlayerLeave",
      "ContainerStart",
      "ContainerStop"
    ]
  }
}

Rest API

The API should not be accessible from the internet!

Enabling API

To enable the API the environment variable INFRARED_API_ENABLED must be set to "true". To change the http bind, set the env variable INFRARED_API_BIND to something like "0.0.0.0:3000" the default value is "127.0.0.1:8080"

API Methods

Create new config

POST /proxies
Body must contain:

{
"domainName": "mc.example.com",
"proxyTo": ":8080"
}

But all values (like in a normal config file) can be set.

The API then will create a file with the name of the domain (if the file exists it will be overwritten) and write the body to it. The proxy can now be visited.


POST /proxies/{fileName}
Body must contain:

{
"domainName": "mc.example.com",
"proxyTo": ":8080"
}

But all values (like in a normal config file) can be set.

The server will create a file with the given filename (if the file exists it will be overwritten) and store the config in it.

Remove config

DELETE /proxies/{fileName}
Replace :file with the name of the proxy configuration file.

If the file was found it will be unloaded and deleted. Open connections do not close, but no new player can connect anymore.

Prometheus exporter

The built-in prometheus exporter can be used to view metrics about infrareds operation.
When the command line flag -enable-prometheus is enabled it will bind to :9100 by default, if you would like to use another port or use an application like node_exporter that also uses port 9100 on the same machine you can change the port with the -prometheus-bind command line flag, example: -prometheus-bind=":9070".
It is recommended to firewall the prometheus exporter with an application like ufw or iptables to make it only accessible by your own Prometheus instance.

Prometheus configuration:

Example prometheus.yml configuration:

scrape_configs:
  - job_name: infrared
    static_configs:
    - targets: ['infrared-exporter-hostname:port']

Metrics:

  • infrared_connected: show the amount of connected players per instance and proxy:
    • Example response: infrared_connected{host="proxy.example.com",instance="vps1.example.com:9070",job="infrared"} 10
    • host: listenTo domain as specified in the infrared configuration.
    • instance: what infrared instance the amount of players are connected to.
    • job: what job was specified in the prometheus configuration.
  • infrared_proxies: show the amount of active infrared proxies:
    • Example response: infrared_proxies{instance="vps1.example.com:9070",job="infrared"} 5
    • instance: what infrared instance has that amount of active proxies.
    • job: what job was specified in the prometheus configuration.

Coding Guidelines

Commit Messages

When contributing to this project please follow the Conventional Commits specification for writing commit messages, so that changelogs and release versions can be generated automatically.

Example commit message

fix: prevent racing of requests

Introduce a request id and a reference to latest request. Dismiss
incoming responses other than from latest request.

Remove timeouts which were used to mitigate the racing issue but are
obsolete now.

Reviewed-by: Z
Refs: #123

Some tooling that can help you author those commit messages are the following plugins:

Similar Projects