Proxy block

The proxy block allows you to configure host spoofing via web reverse proxies or WEBIRC.

''NOTE: If you are running UnrealIRCd 6.1.0 or older, then instead see the WebIRC block for webirc support.

Is a reverse proxy a good idea?
Note that while using WEBIRC is reasonably common, using other proxy types like using a reverse proxy for IRC is rare. Using a reverse proxy could be useful in the specific case where you don't expose the IRC server directly to the internet and only allow it to be accessed through websocket connections through a reverse proxy (like, having an IRC server for webchats only). Using a reverse proxy makes considerable less sense when your IRC server is still directly reachable from the internet (direct IRC without websockets, without the reverse proxy).

Also, using a reverse proxy adds another Point of Failure (another host in-between that may be down, have glitches, network resets, etc.). For example, Cloudflare resets idle websocket connections after 2 minutes and may reset websocket connections during day to day upgrades of their servers. Make sure you understand the effects before going this route.

If you were considering reverse proxies to distribute user load, then better read Distributing user load and doing server maintenance instead, which uses DNS RR and takes away the need for the reverse proxy inbetween.

Syntax
proxy name-of-proxy { type [webirc|forwarded|x-forwarded|cloudflare]; match { ip 1.2.3.4; } password "somepass"; };

The name-of-proxy is a short name for the proxy. It is not used yet as of UnrealIRCd 6.1.1, but may be used or displayed somewhere at a later point.

Within the block:
 * type is the type of proxy:
 * webirc: a WEBIRC / CGI:IRC gateway, see also WebIRC Support.
 * forwarded: a web proxy sending  headers (modern standard, but less common)
 * x-forwarded: a web proxy sending  and   headers (not standardized but more common)
 * cloudflare: if you are using cloudflare as a reverse proxy, this uses a combination of  and  . IMPORTANT: Cloudflare terminates idle websocket connections after 2 minutes and has a policy of only allowing a certain number of concurrent websocket connections. See the Cloudflare documentation. As you can see, the maximum concurrent connections vary by plan and the exact numbers are unspecified. Using Cloudflare for IRC websockets is likely not an ideal choice.
 * match is checked against the proxy that is trying to connect. It is a Mask item.
 * password is only used for type webirc

Examples
We have several examples:
 * WEBIRC example with KiwiIRC
 * NGINX reverse proxy for websockets

WEBIRC example with KiwiIRC
The example below configures KiwiIRC and UnrealIRCd. Note that this is just an example, if you use something other than KiwiIRC you edit that instead of the KiwiIRC-side.

The most important thing is that you set the same password on both the Kiwi side and on the UnrealIRCd side, we use  as an example here.

KiwiIRC-side (old and outdated)
Edit kiwiirc's config.js as follows (note: this is NOT a complete configuration file, it just shows 3 important sections): // WebIRC passwords enabled for this server conf.webirc_pass = { "irc1.yournetwork.org":       "ThisIsMySecretWebIRCPassword" };

// Default settings for the client. These may be changed in the browser conf.client = { server: 'irc1.yournetwork.org', port:   6697, ssl:    true, channel: '#test', nick:   'kiwi_?' }; // or use conf.restrict_server etc... to achieve the same effect (see example config.js file).

// What matters is that the server name in conf.client or conf.restrict_server // match the server name in conf.webirc_pass (and use the right password). // So be sure to replace BOTH the irc1.yournetwork.org instances with the same server name.

// Now something else... "send ip as username".... // Be sure *NOT* to list your server here !!!! // If you add it here, then the IP will show up in the ident. This is NOT what you want // as the IP is already sent via WEBIRC. Doing so would reveal the users' IP to everyone which is bad. conf.ip_as_username = [ "do_not_set_your_server_here" ];

KiwiIRC-side (new aka nextclient)
Edit kiwiirc's webircgateway config.conf as follows (note: this is NOT a complete configuration file): // WebIRC passwords enabled for this server [upstream.1] webirc = "ThisIsMySecretWebIRCPassword"

UnrealIRCd-side
Then, in your unrealircd.conf you add a webirc block:

proxy { type webirc; mask 127.0.0.1; password "ThisIsMySecretWebIRCPassword"; };

except ban { mask 127.0.0.1; type { connect-flood; handshake-data-flood; blacklist; }; };

The Except ban block block is highly recommended. This will ensure your webirc gateway is not seen as connection flooding and the blacklist exception will make it connect faster. If you don't have an except ban block for your webirc gateway then users will not be able to connect during peak hours or after a server restart.

NGINX reverse proxy for websockets
In this example we use a reverse proxy in NGINX to proxy websocket connections via NGINX to your UnrealIRCd. We choose to use the "forwarded" type which is less common but standardized.

Note that UnrealIRCd also supports  header, but this is NOT used in the example below (we set the   header).

UnrealIRCd configuration
First, set up websockets on port 8000 with SSL/TLS: loadmodule "websocket"; loadmodule "webserver";

listen { ip *; port 8000; options { websocket { type text; } tls; } }

Then add the proxy block: proxy { type forwarded; match { ip 6.6.6.6; } // IP of your reverse proxy }

NGINX configuration
This is based on NGINX docs plus the addition of $proxy_protocol from ourselves

Add this to your config so the  variable becomes available: map $https $proxy_protocol { "^on$" "proto=https"; default "proto=http"; }

map $remote_addr $proxy_forwarded_elem { # IPv4 addresses can be sent as-is ~^[0-9.]+$         "for=$remote_addr;$proxy_protocol";

# IPv6 addresses need to be bracketed and quoted ~^[0-9A-Fa-f:.]+$  "for=\"[$remote_addr]\";$proxy_protocol";

# Unix domain socket names cannot be represented in RFC 7239 syntax default            "for=unknown;$proxy_protocol"; }

map $http_forwarded $proxy_add_forwarded { # If the incoming Forwarded header is syntactically valid, append to it   "~^(,[ \\t]*)*([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|\"([\\t \\x21\\x23-\\x5B\\x5D-\\x7E\\x80-\\xFF]|\\\\[\\t \\x21-\\x7E\\x80-\\xFF])*\"))?(([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|\"([\\t \\x21\\x23-\\x5B\\x5D-\\x7E\\x80-\\xFF]|\\\\[\\t \\x21-\\x7E\\x80-\\xFF])*\"))?)*([ \\t]*,([ \\t]*([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|\"([\\t \\x21\\x23-\\x5B\\x5D-\\x7E\\x80-\\xFF]|\\\\[\\t \\x21-\\x7E\\x80-\\xFF])*\"))?(([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|\"([\\t \\x21\\x23-\\x5B\\x5D-\\x7E\\x80-\\xFF]|\\\\[\\t \\x21-\\x7E\\x80-\\xFF])*\"))?)*)?)*$" "$http_forwarded, $proxy_forwarded_elem";

# Otherwise, replace it   default "$proxy_forwarded_elem"; }

And then add something like this in your site block: location /websocket { proxy_set_header Forwarded $proxy_add_forwarded; proxy_pass https://5.5.5.5:8000/; } This assumes your UnrealIRCd is running at 5.5.5.5 with websockets enabled at port 8000 and it is a SSL/TLS port, as we configured earlier above.

Test
Be sure to REHASH the IRCd and your NGINX or whatever proxy you use, and then connect with a websocket to

Your websocket client should pop up on IRC with the end-user IP address (and not the IP address of the proxy). If it doesn't work, then also connect as IRCOp via normal (non-websocket) IRC and see if there is anything logged by the IRCd, UnrealIRCd log messages such as "proxy did not send a valid forwarded header".


 * If you see the "proxy did not send a valid forwarded header" warning then it means your proxy is not sending the  header. For example it could be using the wrong headers such as   or  :
 * Either reconfigure the proxy to send the modern  header instead.
 * Or, if you want to use  instead of , then in UnrealIRCd use