rust-server
rust-server copied to clipboard
RCON over secure websocket (wss)
Is your feature request related to a problem? Please describe.
Currently the rcon web frontend has hardcoded ws://
protocol and thus does not support secure websockets (wss://
protocol)
I got it working and wanted to share my solution here so that it may help in finding a clean and permanent solution or at least help those who might encounter this problem as well.
The problematic line of code is in container /usr/share/nginx/html/js/rconService.js
Service.Connect = function(addr, pass) {
this.Socket = new WebSocket("ws://" + addr + "/" + pass); // <-- here
this.Address = addr;
Describe the solution you'd like
I used a solution with a custom subdomain specificly for the websocket. (ws.rcon.rust.example.com
)
It should also be possible with rcon.rust.example.com:28016
if you fix a few things here. (Shouldn't be that much of a problem, but if it is, just ask and I'll provide a working example here)
Create sub domains
I used the following domains
-
rcon.rust.example.com
for the web frontend -
www.rcon.rust.example.com
for the web frontend (CNAME =>rcon.rust.example.com
) -
ws.rcon.rust.example.com
for the websocket
Fix the rcon web client
- start Rust container and download
/usr/share/nginx/html/js/rconService.js
:docker-compose up -d # you may have to wait for startup before the file becomes available (since some stuff is downloaded at container startup) docker cp <container>:/usr/share/nginx/html/js/rconService.js rconService.js
- edit local
rconService.js
:Service.Connect = function(addr, pass) { addr = addr.replace(/^www./i, '').split(':')[0] // trimPrefix "www" and remove port var wsurl = "wss://ws." + addr + "/"; console.log("Websocket url:", wsurl); this.Socket = new WebSocket(wsurl + pass); this.Address = addr;
- add
rconService.js
as volume mount in Rust'sdocker-compose.yml
:volumes: - ./rconService.js:/usr/share/nginx/html/js/rconService.js
Full docker-compose
setup
- Traefik docker network:
docker network create --attachable traefik
- Full Traefik
docker-compose.yml
(with letsencrypt): NOTE: Change[email protected]
!version: "3.3" networks: traefik: external: true services: traefik: image: traefik:v2.5 command: - "--log.level=INFO" - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" - "--certificatesresolvers.letsencrypt.acme.httpchallenge=true" - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web" - "[email protected]" - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" networks: - traefik ports: - 80:80 - 443:443 volumes: - ./letsencrypt:/letsencrypt - /var/run/docker.sock:/var/run/docker.sock:ro
- Full Rust
docker-compose.yml
: NOTE: Changeexample.com
to your domain!version: "3.3" networks: default: traefik: external: true services: rust: image: didstopia/rust-server volumes: - ./rust_data:/steamcmd/rust - ./rconService.js:/usr/share/nginx/html/js/rconService.js # fixed secure websocket (wss://) networks: - default - traefik ports: - 0.0.0.0:28015:28015 - 0.0.0.0:28015:28015/udp - 0.0.0.0:28016:28016 #- 0.0.0.0:8080:8080 # portforwarding using traefik (see last labels) environment: # ... omitted ... labels: - traefik.enable=true - traefik.docker.network=traefik # rcon web (:8080 => rcon.rust.example.com or www.rcon.rust.example.com) - traefik.http.routers.game-rust-rcon.rule=Host(`rcon.rust.example.com`) || Host(`www.rcon.rust.example.com`) - traefik.http.routers.game-rust-rcon.entrypoints=websecure - traefik.http.routers.game-rust-rcon.tls.certresolver=letsencrypt - traefik.http.routers.game-rust-rcon.service=game-rust-rcon - traefik.http.services.game-rust-rcon.loadbalancer.server.port=8080 # rcon websocket (:28016 => ws.rcon.rust.example.com) - traefik.http.routers.game-rust-rcon-ws.rule=Host(`ws.rcon.rust.example.com`) - traefik.http.routers.game-rust-rcon-ws.entrypoints=websecure - traefik.http.routers.game-rust-rcon-ws.tls.certresolver=letsencrypt - traefik.http.routers.game-rust-rcon-ws.service=game-rust-rcon-ws - traefik.http.services.game-rust-rcon-ws.loadbalancer.server.port=28016
Hope it helps
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Thanks for this. I originally played around with this as well, but never got it to work.
For now, I pushed an update that adds RUST_RCON_SECURE_WEBSOCKET
as a new environment variable, defaulting to 0
, but if you set it to 1
it will replace the insecure protocol (ws://
) protocol with the secure one (wss://
).
Hopefully this helps!
Took me a while to get this working...
There was no situation where the secure websocket setting worked, in fact it broke accessing rcon locally. Just set it to 0
in docker-compose.yml
for rust.
RUST_RCON_SECURE_WEBSOCKET=0
Next, I applied similar, but different Iyashi's edits to rconService.js
// remove port - we want to go through the default ssl entrypoint in traefik (443).
addr = addr.split(':')[0];
// infer websocket protocol from current http/s protocol (if you're on https, you are forbidden from using ws:// anyway).
if (window.location.protocol === "https:")
this.Socket = new WebSocket("wss://" + addr + "/" + pass);
else
this.Socket = new WebSocket("ws://" + addr + "/" + pass);
// unchanged
this.Address = addr;
finally, in traefik:
http:
services:
rust-rcon-web:
loadBalancer:
servers:
- url: http://192.168.2.98:28080
rust-rcon-ws:
loadBalancer:
servers:
- url: http://192.168.2.98:28016 # notice we're not pointing at https... traefik is ssl offloading.
routers:
rust-rcon-web-rtr:
service: rust-rcon-web
rule: Host(`rust.domain.com`)
entryPoints:
- https
rust-rcon-ws-rtr:
service: rust-rcon-ws
rule: Host(`rust.domain.com`) && Headers(`X-Forwarded-Proto`, `wss`) # adding a rule looking for the forwarded proto means we don't need a new subdomain for websocket.
entryPoints:
- https
I think the only change that should happen to this image is in rconService.js
Ideally, add my conditional logic for selecting web socket protocol.
In the docker config, there should be two settings for rcon port...
RUST_RCON_SERVER_PORT=28016
RUST_RCON_CLIENT_PORT=443
this could default to RUST_RCON_SERVER_PORT
if not provided. Then, the client port needs to be what is used when calling `rconService.js Service.Connect()
Honestly, this setting should be deleted (it doesn't work, and adds confusion).
RUST_RCON_SECURE_WEBSOCKET
I may try to get a PR together for you.
I miserably failed to get the rcon Web to work with my nginx setup...
The main problem seems to be, that the websocket and the web port are different... If the websocket connection would be built on the web port, a simple reverse proxy could get things running without any problems.
My first approach to get the Web Interface onto the Web worked, however connecting to the Websocket failed because of "https and ws can't be mixed up".
Simply activating RUST_RCON_SECURE_WEBSOCKET also didn't help, since then the intern websocket call expects certificates and stuff. Simply changing ws to wss doesn't work with the same reason why changing http to https without providing the necessary certs wont work.
If anyone managed to get the rcon stuff to work with nginx, please help. Until then, I'm pretty much forced to use rcon in my local network only.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.