← Back to Wiki
Game Servers / Docker

Self-Hosting Enshrouded: A Docker Networking Gotcha That Looks Like a Tunnel Problem

A public Enshrouded dedicated server in Docker, tunneled to hide the home IP, with a split-horizon DNS setup so LAN players connect directly instead of round-tripping through the internet. It works great. Then a container that has been perfectly healthy the entire time turns out to have never had its port open to the host, and only one of the two ways in ever noticed.

Share on X

The setup

Enshrouded's dedicated server runs happily under Docker on a plain Linux container. No Windows requirement, no special hardware. The community sknnr/enshrouded-dedicated-server image handles the Wine layer needed to run enshrouded_server.exe on Linux, listening on a single UDP port, 15637 by default.

To expose it publicly without leaking a home IP, an frpc sidecar container runs alongside it on its own Docker bridge network, tunneling out to a relay server. Both containers share that private bridge, so frpc reaches the game process over Docker's own internal DNS at enshrouded:15637 rather than dialing 127.0.0.1. Worth knowing. That is exactly what let the bug below hide as long as it did.

Split-horizon DNS: fast for LAN players, free performance win

Public traffic routing through a tunnel is fine. There is no reason a player on the same LAN as the server should take that detour. A local DNS override on the router resolves the server's public hostname straight to its real LAN IP for anyone inside the network, while everyone outside still routes through the tunnel. Same hostname, two different paths depending on where the client is.

This is a real, worthwhile optimization with a sharp edge, covered below. The LAN path and the tunnel path are genuinely different network routes. One working is no proof the other does.

The bug: a container that looked completely healthy, with no open port

BE WARNED: the server "went down", and the tunnel and the process were both fine. The game stopped appearing at all. Not in the in-game server browser, not by connecting directly to the LAN IP. docker inspect on the game container showed a bare {} for its published ports. The compose file put it on a private bridge network with the frpc sidecar and never published its port to the host. A host-level port scan confirmed nothing was listening there.

Here is the catch. frpc could still reach the game container fine, because they share the same private Docker network and talk over Docker's internal DNS. The public tunnel path kept working the entire time. Only the LAN-direct path was broken, and that one needs the port published to the host's own network stack. A player connecting from outside the LAN would never have noticed.

That is also why it looks like a sudden break with nothing changed. A client with a cached DNS answer pointing at the public tunnel address keeps working until that cache expires. Then a fresh lookup resolves to the LAN IP via the split-horizon override and hits a port that was never open. From the player's side that looks exactly like a random outage.

The fix

Publish the port explicitly in the compose file. Being reachable over the tunnel's internal Docker network is a completely different claim from being reachable on the host's network stack:

services:
  enshrouded:
    # ...
    ports:
      - "15637:15637/udp"
    networks:
      - gamenet

Recreate the container with docker compose up -d. Then confirm a real listener exists at the host level, not inside the container's own namespace. Those are not the same check:

# from inside the LXC or host itself. Checks the host's own network stack
ss -ulnp | grep 15637

# from inside the container. Checks whether the process is listening at all,
# useful on minimal images with no ss or netstat installed
docker exec enshrouded cat /proc/net/udp
The generalizable lesson. For any Docker-based game server paired with a split-horizon LAN DNS override, publish the container's port to the host explicitly. A sidecar tunnel client reaching it over Docker's internal network proves nothing about whether a LAN client hitting the host's IP can reach it too. Genuinely separate network paths. Testing one is not testing the other. Check that explicitly on every Docker-based tunneled game server you run, not just the one that happened to break.

A smaller gotcha: the in-game search box

Enshrouded's server browser lists a discoverable dedicated server automatically, at the top, with no manual "add server" step. Type the server's name into the browser's own search box, though, and you reliably get zero results. That is expected behaviour, not a broken tunnel or DNS entry. The server is already visible without searching. The search field just does not match against it. Connecting straight from the list works fine.

Modding: a known open question, not yet resolved

Enshrouded has no official mod support. This server runs the game under Wine inside Docker rather than natively, and most mod loaders require setting a WINEDLLOVERRIDES environment variable on the actual Wine process invocation. That is unconfirmed against this image's entrypoint. Other people running the same base image have hit the identical wall with no documented fix. Verify it against a disposable test instance, with a fresh backup on hand, before you try it on a server real players are connected to.