Setting UID/GID/USER is broken
We had an issue where the docker image gameservermanagers/gameserver:css was setting UID and GID to 1000 which was the wrong user (even if user linuxgsm existed for example on id 1006) on our server and the volume (dir) would get chowned for the wrong user.
After noticing that it's set through ENV we added variable overrides to docker-compose.yml (some data is redacted):
version: "3.8"
services:
linuxgsm-css-bind:
image: gameservermanagers/gameserver:css
volumes:
- /home/combat/combat-css-server:/data
environment:
- USER=combat
- UID=1005
- GID=1005
But the docker image would still fail with:
combat-css-server | Switch to user combat
combat-css-server | =================================
combat-css-server | error: failed switching to "combat": unable to find user combat: no matching entries in passwd file
combat-css-server |
combat-css-server | Check Permissions
combat-css-server | =================================
combat-css-server | setting UID to 1005
combat-css-server | setting GID to 1005
combat-css-server | updating permissions for /data
combat-css-server | chown: invalid user: ‘combat:combat’
combat-css-server | updating permissions for /app
combat-css-server | chown: invalid user: ‘combat:combat’
The problem is that the user exists
# combat@noil:~$ id
uid=1005(combat) gid=1005(combat) groups=1005(combat),100(users),994(docker)
We are not and will not run docker or any other similar daemons or commands with sudo. The combat user is part of the docker group and is able to run docker images without sudo.
How should we proceed to start the linuxgsm (gameserver) on our combat user, so that the volume and the start scripts would get the correct UID/GID ?
Or is it only possible to start as non-root is with linuxgsm user and then deal with dir/file permissions so that combat user could modify files owned by linuxgam user ? (As it worked to start the docker image with user=linuxgsm,id=1006,gid=1006)
chmod 775 is not a solution, as everytime the docker container is started it overrides all ownerships and permissions
I tried to make a user with the same UID and GID as the ones it was chowning the files to and then added my user to that group. Unfortunately when it detected that the user existed it would then chown all the files to a different UID and GID, I believe this is similar to what you are saying? I wish there was a flag to just make it run as root instead of linuxgsm user to bypass all this trouble because honestly I just start it when I want to play l4d2 (not CSS like in your case but it should still be similar) so I don't really care about how secure it is or not
~~Try using a bind mount as per https://docs.docker.com/storage/bind-mounts/#mount-into-a-non-empty-directory-on-the-container, this seemed to work for me and it sets the UID/GID I specified~~ Bind mount didn't actually work nevermind
Maybe I'm a bit lost here, but I'm confused what you've done outside and what you've done inside the container.
Care to elaborate, why do you need another user besides linuxgsm? Why isn't the linuxgsm user enough? Where/how have you exactly determined, it is setting the wrong UID/GID? When running inside the container, or are you trying to access the files outside the container (on the host)?
It seems like you have created a user "combat" inside the container, want to run the container as user "combat", and expect the UIDs and GIDs to match?
Please note that the idea of a container is that it has a totally different namespace. The whole point is that the UIDs, GIDs don't match with anything on the host. The user accounts are separate.
Bind mounts have nothing to do with UID nor GID management, really.
Or, sorry if I'm misinterpreting totally what you have done and asking help for =).
Maybe I'm a bit lost here, but I'm confused what you've done outside and what you've done inside the container.
Care to elaborate, why do you need another user besides linuxgsm? Why isn't the linuxgsm user enough? Where/how have you exactly determined, it is setting the wrong UID/GID? When running inside the container, or are you trying to access the files outside the container (on the host)?
It seems like you have created a user "combat" inside the container, want to run the container as user "combat", and expect the UIDs and GIDs to match?
Please note that the idea of a container is that it has a totally different namespace. The whole point is that the UIDs, GIDs don't match with anything on the host. The user accounts are separate.
Bind mounts have nothing to do with UID nor GID management, really.
Or, sorry if I'm misinterpreting totally what you have done and asking help for =).
Forgetting the bind mounts as I said it didn't make a difference, as I said I tried to set the UID and GID to the same thing the container was chowning the mounted folders to but when the container starts it then picks a different UID/GID. It's nice that linuxgsm thinks it needs to chown all mounted files/folders every time the container starts (which is completely unnecessary but it still does it). Thing is I need to be able to edit the files that are mounted or I can't set up the server, call me crazy. None of the https://www.linuxserver.io/ images have this issue and they allow the user to run the image with whatever permissions they want for the mounted files/folders. For some reason all L4D2/srcds images think they need to chown everything. In fact I run most docker containers with root UID/GID 0 (within the container not on the host system) to avoid permission issues so that the container can access the mounted files without issues (spare me the speech about this being a bad idea I do it anyway), but this image thinks it needs to chmod/chown my files every time to some random user no matter which UID/GID I specify.
I spent hours trying different things with no luck so it's nice the namespaces are separate but when I can't edit the files for the server or add new things to the server, that's a problem. Either there is a permissions issue like this with all the srcds/steamcmd images I tried or the server simply doesn't start and says some error which won't resolve no matter what you try. Because of all this I gave up running srcds servers with docker images and on Linux as a whole and moved to Windows server within proxmox where I don't have to deal with this. It's nicer too because with RDP I can just drag and drop files into the server. Wish the others best of luck though. Maybe some day the container will not chown every file when it isn't necessary, who knows.
I am also having the same issue, I can't actually create a backup of Palworld server because the user doesn't have permissions to create directories in the host directory.
the issue seems to stem from the linuxgsm userid of 1000 and the default/first user created on the host gets userid 1000.
what is the best of changing this to prevent issues moving forward?
I am also having the same issue, I can't actually create a backup of Palworld server because the user doesn't have permissions to create directories in the host directory.
the issue seems to stem from the linuxgsm userid of 1000 and the default/first user created on the host gets userid 1000.
what is the best of changing this to prevent issues moving forward?
Not running it in a docker container and just running it on host is the only real option I can see unless they fix this (which I doubt will happen any time soon, if ever), but I opted to run my server on windows host instead of linux
The issue is in the linuxgsm dependency container I think which docker-gameserver depends on as shown in the Dockerfile, and it's just not worth the time for me to fuss with it.
I fixed it by creating the linuxgsm user on the host and adding my user account to the linuxgsm group, container starts fine now, but I am unable to run backups using podman exec -it --user linuxgsm pwserver ./pwserver b
podman exec -it --user linuxgsm pwserver ./pwserver b [ INFO ] Backing up pwserver: Starting backup: Previous backups found
- Previous backup was created less than 1 day ago, total size 0 [ WARN ] Backing up pwserver: pwserver will be restarted [ OK ] Stopping pwserver: Graceful: CTRL+c: 3: OK [ .... ] Backing up pwserver: Backup (3.1G) pwserver-2024-08-09-125907.tar.gz, in progress.../bin/sh: 1: pigz: not found tar: /app/lgsm/backup/pwserver-2024-08-09-125907.tar.gz: Cannot write: Broken pipe tar: Child returned status 127 tar: Error is not recoverable: exiting now FAIL [ FAIL ] Backing up pwserver: Starting backup [ OK ] Updating pwserver: Checking for update: SteamCMD
No update available
- Local build: 15237740
- Remote build: 15237740
- Branch: public https://steamdb.info/app/2394010/
[ OK ] Backing up pwserver: Palword Server
This is very frustrating for me as well. I run a ton of containers on this host and this container essentially requiring UID 1000 is making a mess. I'm not sure what the solution is, but maybe something like a config check it can reference on start to switch the UID/GID would be very welcome.
Yes it is broken. Stop trying to change the container's internal username. You CANNOT DO IT.
- The docker container itself is built with a hardcoded user named linuxgsm. That's just there forever in the core container image itself.
https://github.com/GameServerManagers/docker-linuxgsm/blob/main/Dockerfile.ubuntu-2204
- The entrypoint code itself is completely bugged. It changes the uid/gid of the hardcoded linuxgsm user (which makes sense since it's the only username that exists). But then it tries to change the ownership of the home and app directories to the provided
$USERvariable which is a totally non-existent user/group if it's notlinuxgsmanymore:
https://github.com/GameServerManagers/docker-linuxgsm/blob/07a5f31da01c2145dfce1e36acb8da3022258f38/entrypoint.sh#L56-L64
In other words. Trying to set a custom USER= variable is breaking the UID/GID updating of the data directories. It must remain at the default linuxgsm value to work.
TL;DR: Leave it on the default USER=linuxgsm. Setting UID= and GID= works, and that's the only thing you need to do for proper permission mapping anyway.
And no, you don't need to create a user on the host like someone said. That's total nonsense.
Oh and somebody mentioned using Podman.
You cannot use podman as-is. It has a very complicated system for mapping host-owned files to container-owned files. Because technically, it wants to run the container process as a random, isolated UID such as "100999". Therefore all mapped volumes will automatically become owned by "100999:100999".
The only way to avoid that is to use the "userns=keep-id" option to tell Podman to keep the UID and GID of the host user that started the rootless container. But then the next issue is that the container process actually runs as your host user/gid on the host. It's sandboxed, but if it ever escapes the sandbox, it can read/write all files owned by your user (the entire home directory).
So to fix that, you should have SELinux, AppArmor or similar enabled (for example on Fedora, it's on by default), meaning that your containerized server process can only access files that have been labeled.
And when SELinux/AppArmor is enabled, you must then also tell the mounted volume that you want :z which means "shared volume" (a volume that can be accessed by any container and the host user). Because :Z would mean it's only accessible by the container (not by the host user at all).
And to make matters even worse, the LinuxGSM container is written in a pretty bad way which means it's very rigid and cannot adapt to UID/GID being anything other than 1000. I explain the reason in more detail in the code comments below.
So, to avoid errors like chown: cannot read directory '/data': Permission denied, and to ensure that the host user can read/write all server files, and that they are owned by the host user, you need to do a complicated "dance" of settings to make it all come together.
Here's an example of a working container compose.yml for 7 Days to Die running via podman compose up:
name: server-7days
services:
linuxgsm:
image: ghcr.io/gameservermanagers/gameserver:sdtd
# Force a specific container name to easily control it later.
container_name: sdtdserver
# Tell Podman to keep the host user's UID:GID, to easily mount files.
# NOTE: If we don't do this, the mapped volume will be owned by a virtual
# uid such as "100999" instead of the host user, which is tedious.
# NOTE: This means the container process runs with the user's privileges
# on the host, if it ever escapes the container sandbox, which is why
# it's important to have SELinux/AppArmor labeling (it's on by default).
# NOTE: This is the ONLY way to make Podman preserve the user's ownership
# on the host. But it's not perfect. It only works well if your host UID
# and GID are already 1000, since LinuxGSM pre-creates a "linuxgsm" user
# inside the container at build-time with those IDs, so when the "keep-id"
# mapping happens, Podman sees that a user/group with those IDs already
# exists inside the container, and preserves the "linuxgsm" name. But if
# the host UID/GID are different, Podman would instead create a new user
# and group inside the container with the exact same names as the host user,
# and then the LinuxGSM entrypoint script would fail to change the UID and
# GID of the internal "linuxgsm" user to the desired IDs, since those are
# already taken by the user injected via "keep-id". There's no other way
# to make Podman preserve IDs though. Because methods such as the "uidmap"
# parameter doesn't allow mapping to user IDs on the host, only to virtual
# ranges such as "100999".
# NOTE: This also makes the container start as non-root internally.
userns_mode: "keep-id"
# Tell container to start as root (UID 0) internally. Entrypoint needs it,
# since it adjusts some container permissions internally and then drops to
# the chosen UID/GID internally.
user: "0"
# Tell the container to map its internal "linuxgsm" user to the host's
# UID/GID, so that the container process runs with the same privileges
# as the mapped "userns=keep-id" user, thus ensuring that files on the host
# remain owned by the host user.
# NOTE: This must be manually adjusted to match the host user, but
# for most single-user machines, both values are 1000. Check on the host
# by running "id -u" and "id -g".
# NOTE: As mentioned in the "userns" notes, this will almost certainly fail
# if the host UID/GID aren't 1000, since the target UID/GID will then be
# taken by the injected "keep-id" user. See "userns" note for details.
environment:
- UID=1000
- GID=1000
# Persistent server data directory.
# NOTE: The ":z" suffix tells Podman to label all files with a "shared"
# context, meaning that the container process can access these files but
# cannot access anything else on the host if it ever escapes.
volumes:
- ./data:/data:z
# External ports.
ports:
# https://7dtd.illy.bz/wiki/Ports
- "26900:26900/tcp" # Game (Game details query port)
- "26900-26902:26900-26902/udp" # Game (0: Steam's master server list interface, 1: Steam communication, 2: networking via LiteNetLib)
- "127.0.0.1:26903:8080/tcp" # Web based control panel (localhost only)
- "127.0.0.1:26904:8081/tcp" # Telnet control interface (localhost only)
# Automatically restart if the server process crashes.
restart: unless-stopped