Skip to content

Fix non-root permissions and allow custom UID & GID - #484

Open
misch7 wants to merge 3 commits into
haiwen:masterfrom
misch7:fix-non-root
Open

Fix non-root permissions and allow custom UID & GID#484
misch7 wants to merge 3 commits into
haiwen:masterfrom
misch7:fix-non-root

Conversation

@misch7

@misch7 misch7 commented Mar 19, 2026

Copy link
Copy Markdown
Contributor

Motivation

Hi,

I'm new to Seafile, have been using it for about a week now and I'm quite satisfied with it :-)

There were some issues setting up the non-root environment with the seafile-docker container, for which I aim to provide a fix with this PR.

Issues

Starting the container with NON_ROOT=true always failed on my machine due to an indefinitely hanging call to chown:

chown -R seafile:seafile /opt/seafile/$SEAFILE_SERVER-$SEAFILE_VERSION/

While following the official docs for Running Seafile as non root user inside docker somehow I expected the startup script to securely adjust permissions after preparing them manually before with chmod -R a+rwx /opt/seafile-data/.

However, since they never got adjusted, I began inspecting the scripts, leading me to identify the following issues (if I did not miss anything anywhere else):

  • The bootstrap.py script (called by start.py) contains the following snippet at the end of its function init_seafile_server():

    # non root
    non_root = os.getenv('NON_ROOT', default='') == 'true'
    if non_root:
    call('chmod -R a+rwx /shared/')

    But enterpoint.sh expects those exact permissions already to be set and terminates prior to invoking the aforementioned function, causing the bootstrap code for setting permissions never to be called.

  • The permissions never get properly adjusted later and just stay overly permissive with 777, which I confirmed running the container for a while. Also with restarts nothing changes.
    Additionally the current scripts also set the owner of the whole Seafile app binary directories to the seafile user. In my understanding one advantage of the whole NON_ROOT procedure would have been to leave the app binaries owned by root but called by seafile, who owns just the data and runtime folders it needs write access for.

    My wild guess is that these permissions were chosen for ease of use?

Issues #22 and #86 have been closed but never were fully resolved, as it seems.

To address all those issues I propose the following changes in this PR and leave them up to discussion:

Changes

  • The chmod code block in bootstrap.py gets removed.

  • enterpoint.sh now:

    • creates missing directories, if needed
    • allows the user to set custom NON_ROOT_UID and NON_ROOT_GID for the container-user seafile via optional parameters (default remains 8000:8000)
    • (re)sets the same secure permissions the volume folders initially had with the standard root-user setup
    • only changes the owner recursively if the main folders have another owner, to avoid unnecessary overhead with large storages
    • leaves the app folders and binaries untouched but grants write access to /opt/seafile (e.g. for creating the pids folder) and the runtime folder, in the container
  • Dockerfile removes the standard user ubuntu with UID 1000 to avoid conflicts with custom non-root UIDs.

  • In .env the following can now be specified:

    NON_ROOT=true
    NON_ROOT_UID=8000
    NON_ROOT_GID=8000
    

    This would also require a change within seafile-server.yml:

        environment:
          - NON_ROOT=${NON_ROOT:-false}
          - NON_ROOT_UID=${NON_ROOT_UID:-8000}
          - NON_ROOT_GID=${NON_ROOT_GID:-8000}
    

    Side note: I did not name the new variables UID/GID in .env because users might expect a different behavior then. Since there are other services like nginx still running with higher privileges, naming them NON_ROOT_UID and NON_ROOT_GID allows to easily distinguish this special non-root use case until these other services eventually get sourced-out into their own containers.

    Please also note that I only modified the code for Seafile 13 CE for now by intention, to ease the review.

    Suggestions and tips for improvements are welcome.

Questions

As stated in this Forum Post, the Docker sources for the Seadoc container are not available publicly yet.

I assume the sources for seafile-server.yml etc. are also not yet available for patching in a repository? At least I did not manage to find them.

Of course the Seadoc container's enterpoint.sh script would need patching as well.

Has the plan changed to publish the missing scripts? I would gladly help to apply the patches to other containers like Seadoc, if they get accepted.

Testing

For anyone interested in testing the changes, here's how I applied them locally:

  • Fetch the files of this PR and store them in a folder or modify them on your target machine
  • Create a custom Dockerfile based on the official image to apply your patches:
     FROM seafileltd/seafile-mc:13.0-latest

     RUN deluser --remove-home ubuntu

     COPY bootstrap.py /scripts/
     COPY enterpoint.sh /scripts/
  • Build your image with something like: docker build -t seafile-mc-13-patched .
  • Modify .env with your desired NON_ROOT parameters, comment out the SEAFILE_IMAGE and specify the custom image, like:
     # SEAFILE_IMAGE=seafileltd/seafile-mc:13.0-latest

     SEAFILE_IMAGE=seafile-mc-13-patched

     NON_ROOT=true
     NON_ROOT_UID=1000
     NON_ROOT_GID=1000
  • Finally spin up your instance like stated in the Official Docs:
     # e.g. on the Docker host machine:

     cd /opt/seafile
     docker compose up -d
  • Needless to say but: Create backups of your data first, don't blame me, I don't take any responsibility.

Log Output

The output of docker logs seafile should then look like:

     *** Running /etc/my_init.d/01_create_data_links.sh...
     *** Booting runit daemon...
     *** Runit started as PID 15
     *** Running /scripts/enterpoint.sh...
     2026-03-18 03:53:15 Nginx ready 
     2026-03-18 03:53:15 Setting up non-root user seafile in container, please wait. 
     2026-03-18 03:53:15 Creating group seafile with GID 1000. 
     2026-03-18 03:53:16 Creating user seafile with UID 1000. 
     2026-03-18 03:53:17 Adjusting ownership of /shared/seafile -> seafile 
     2026-03-18 03:53:17 Adjusting ownership of /shared/seafile/conf -> seafile 
     2026-03-18 03:53:17 Adjusting permissions of /shared/seafile/conf -> 700 
     2026-03-18 03:53:17 Adjusting ownership of /shared/seafile/logs -> seafile 
     2026-03-18 03:53:17 Adjusting permissions of /shared/seafile/logs -> 700 
     2026-03-18 03:53:17 Adjusting permissions of /shared/seafile/pro-data -> 700 
     2026-03-18 03:53:17 Adjusting permissions of /shared/seafile/seafile-data -> 700 
     2026-03-18 03:53:17 Adjusting permissions of /shared/seafile/seahub-data -> 755 
     2026-03-18 03:53:17 Adjusting ownership of /opt/seafile -> seafile 
     2026-03-18 03:53:17 Adjusting permissions of /opt/seafile -> 1755 
     2026-03-18 03:53:17 Adjusting ownership of /opt/seafile/seafile-server-13.0.19/runtime -> seafile 
     2026-03-18 03:53:17 Adjusting permissions of /opt/seafile/seafile-server-13.0.19/runtime -> 1755 
     2026-03-18 03:53:17 Finished non-root setup. 
     2026-03-18 03:53:18 This is an idle script (infinite loop) to keep container running. 

Offtopic

notification-server.yml has restart: always but should have restart: unless-stopped like the other containers.

misch7 added 3 commits March 19, 2026 00:26
 enterpoint.sh:
 - create missing directories, if needed
 - allow the user to set custom `UID` and `GID` for the container-user `seafile` via optional parameters (default remains 8000:8000)
 - (re)set the same secure permissions the volume folders initially had with the standard root-user setup
 - only change the owner recursively if the main folders have another owner, to avoid unnecessary overhead with large storages
 - leave the app folders and binaries untouched but grant write access to `/opt/seafile` (e.g. for creating the `pids` folder) and the `runtime` folder, in the container

 bootstrap.py:
  - remove the chmod code block in init_seafile_server()
@freeplant freeplant self-assigned this Mar 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants