Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .github/workflows/container.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ jobs:
mkdir -p ${{ runner.temp }}/tachidesk_env_vars
chmod -R 777 ${{ runner.temp }}/tachidesk_env_vars
docker run -d -p 127.0.0.1:4568:4567 -v ${{ runner.temp }}/tachidesk_env_vars:/home/suwayomi/.local/share/Tachidesk \
-e PUID=1050 \
-e PGID=1050 \
-e BIND_IP=0.0.0.0 \
-e BIND_PORT=4567 \
-e SOCKS_PROXY_ENABLED=false \
Expand Down Expand Up @@ -205,6 +207,8 @@ jobs:
${{ env.test_image_tag }}
sleep 15
curl -s http://manga:hello123@127.0.0.1:4568/api/v1/settings/about/ && val_env_vars=$(curl -s http://manga:hello123@127.0.0.1:4568/api/v1/settings/about/ | grep -o "Suwayomi-Server" | sort --unique)
# server.conf is created by the server side of the PUID/PGID privilege drop, so its owner shows the UID/GID the server ran as
data_owner=$(docker exec suwayomi_test stat -c '%u:%g' /home/suwayomi/.local/share/Tachidesk/server.conf || echo "docker exec failed")
docker stop suwayomi_test
docker logs suwayomi_test > ${{ runner.temp }}/tachidesk_env_vars.log
docker rm suwayomi_test
Expand All @@ -222,6 +226,20 @@ jobs:
fi
exit 1
fi
if [[ $data_owner != "1050:1050" ]]; then
echo "Container logs:"
echo "=============================="
cat ${{ runner.temp }}/tachidesk_env_vars.log
echo "=============================="
echo "PUID/PGID remapping failed: server.conf is owned by '${data_owner}', expected '1050:1050'"
if [[ $DO_UPLOAD == "true" ]]; then
curl \
-F 'payload_json={"username": "Github", "content": "<@199705443789045771>\nDocker ${{ inputs.tachidesk_release_type }} image dry run failed! 😢 Version - ${{ steps.get_latest_release_metadata.outputs.release_tag }}. [See the full run log](${{ env.this_actions_run_url }})"}' \
-F "file1=@${{ runner.temp }}/tachidesk_env_vars.log" \
"https://discord.com/api/webhooks/${{ secrets.DISCORD_TACHIDESK_WEBHOOK_ID }}/${{ secrets.DISCORD_TACHIDESK_TOKEN }}"
fi
exit 1
fi

# Now we build for all the platforms we support here. NB: the amd64
# won't be rebuilt since the local docker daemon has that still cached
Expand Down
11 changes: 9 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,16 @@ RUN userdel -r ubuntu && \

COPY scripts/create_server_conf.sh /home/suwayomi/create_server_conf.sh
COPY scripts/startup_script.sh /home/suwayomi/startup_script.sh
# the entrypoint runs as root, so keep it outside of the world-writable /home/suwayomi
COPY scripts/docker_entrypoint.sh /usr/local/bin/docker_entrypoint.sh

ARG TACHIDESK_RELEASE_DOWNLOAD_URL
# Copy the app into the container
# then update permissions of files.
# we grant o+rwx because we need to allow non default UIDs (eg via docker run ... --user)
# to write to the directory to generate the server.conf
RUN curl -s --create-dirs -L $TACHIDESK_RELEASE_DOWNLOAD_URL -o /home/suwayomi/startup/tachidesk_latest.jar && \
chmod 755 /usr/local/bin/docker_entrypoint.sh && \
chmod 777 -R /home/suwayomi && \
chown -R suwayomi:suwayomi /home/suwayomi

Expand All @@ -91,10 +94,14 @@ LABEL maintainer="suwayomi" \

ENV HOME=/home/suwayomi
WORKDIR /home/suwayomi
USER suwayomi
# No USER here: the container starts as root and docker_entrypoint.sh remaps
# the suwayomi user to PUID/PGID (default 1000:1000), fixes the ownership of
# the data directory and then drops privileges before starting the server.
# Starting the container with an explicit user (eg docker run --user) skips
# the remapping and runs the server directly as that user, like it used to.
EXPOSE 4567

ENTRYPOINT ["tini", "--"]
ENTRYPOINT ["tini", "--", "/usr/local/bin/docker_entrypoint.sh"]
CMD ["/home/suwayomi/startup_script.sh"]

# vim: set ft=dockerfile:
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------------------------------------------------------------------------------:|
| [![Build Docker Images](https://github.com/Suwayomi/Suwayomi-Server-docker/actions/workflows/build_container_images.yml/badge.svg)](https://github.com/Suwayomi/Suwayomi-Server-docker/actions/workflows/build_container_images.yml) | [![Latest](https://img.shields.io/badge/dynamic/json?url=https://github.com/Suwayomi/Suwayomi-Server-docker/raw/main/scripts/tachidesk_version.json&label=version&query=$.stable&color=blue)](https://github.com/orgs/suwayomi/packages/container/package/suwayomi-server/) | [![Preview](https://ghcr-badge.egpl.dev/suwayomi/suwayomi-server/latest_tag?color=%231183c3&ignore=preview&label=version&trim=)](https://github.com/orgs/suwayomi/packages/container/package/suwayomi-server) | [![Discord](https://img.shields.io/discord/801021177333940224.svg?label=discord&labelColor=7289da&color=2c2f33&style=flat)](https://discord.gg/DDZdqZWaHA) |

Run [Suwayomi-Server](https://github.com/Suwayomi/Suwayomi-Server) inside docker container as non-root user. The server will be running on http://localhost:4567 open this url in your browser.
Run [Suwayomi-Server](https://github.com/Suwayomi/Suwayomi-Server) inside docker container as non-root user (by default UID/GID `1000:1000`, configurable via [PUID/PGID](#running-as-a-different-user-puid--pgid)). The server will be running on http://localhost:4567 open this url in your browser.

Docker Releases - https://github.com/Suwayomi/Suwayomi-Server-docker/pkgs/container/suwayomi-server

Expand Down Expand Up @@ -45,6 +45,8 @@ There are a number of environment variables available to configure Suwayomi:
| Variable | Server Default | Description |
|:---------------------------------------:|:--------------------------------------:|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|
| **TZ** | `Etc/UTC` | What time zone the container thinks it is. |
| **PUID** | `1000` | UID to run the server as, see [Running as a different user](#running-as-a-different-user-puid--pgid). Ignored when the container user is overridden (eg `docker run --user`). |
| **PGID** | `1000` | GID to run the server as, see [Running as a different user](#running-as-a-different-user-puid--pgid). Ignored when the container user is overridden (eg `docker run --user`). |
| **BIND_IP** | `0.0.0.0` | The interface to listen on, inside the container. You almost never want to change this. |
| **BIND_PORT** | `4567` | Which port Suwayomi will listen on |
| **SOCKS_PROXY_ENABLED** | `false` | Whether Suwayomi will connect through a SOCKS5 proxy |
Expand Down Expand Up @@ -127,6 +129,20 @@ There are a number of environment variables available to configure Suwayomi:
| **SYNC_INTERVAL** | `0s` | Interval between automatic sync operations in ISO-8601 Duration format. Use `0s` to disable. |


### Running as a different user (PUID / PGID)

By default the server runs as the built-in `suwayomi` user with UID/GID `1000:1000`. Set the `PUID` and `PGID` environment variables to run it as a different UID/GID, e.g. to match the owner of a bind-mounted data directory:

```yaml
environment:
- PUID=1050
- PGID=1050
```

To make this possible the container starts as root: it remaps the `suwayomi` user to the requested IDs, updates the ownership of the data directory to match (only files with a wrong owner are touched, so startups with large libraries stay fast) and then drops privileges - the server itself never runs as root.

Alternatively, the container user can still be forced from the outside (`docker run --user`, `user:` in a compose file or `runAsUser` in Kubernetes). In that case nothing runs as root at any point, `PUID`/`PGID` are ignored and no ownership fixing takes place - the mounted data directory must then already be writable by that user.

> [!CAUTION]
> This docker image is known to occasionally fail to work. This seems to be caused by problems in the download. If the logs simply end with `LD_PRELOAD=/opt/catch_abort.so /home/suwayomi/.local/share/Tachidesk/bin/kcef/libcef.so`, please remove the downloaded image and pull again. If this does not help, open a [new issue](https://github.com/Suwayomi/Suwayomi-Server-docker/issues/new).

Expand Down
5 changes: 5 additions & 0 deletions docker-compose-postgresql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@
services:
suwayomi:
image: ghcr.io/suwayomi/suwayomi-server:preview
# Forcing the container user disables the PUID/PGID remapping below; the data
# directory must then already be writable by that user. Prefer PUID/PGID.
# user: 1000:1000
environment:
- TZ=${TZ:-Etc/UTC} # Add a TZ variable to .env to change it
# UID/GID to run the server as; the data directory ownership is updated to match (default 1000:1000)
# - PUID=1000
# - PGID=1000
- DATABASE_TYPE=POSTGRESQL
- DATABASE_URL=postgresql://postgresql:5432/${POSTGRES_DB}
- DATABASE_USERNAME=${POSTGRES_USER}
Expand Down
5 changes: 5 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@
services:
suwayomi:
image: ghcr.io/suwayomi/suwayomi-server:preview
# Forcing the container user disables the PUID/PGID remapping below; the data
# directory must then already be writable by that user. Prefer PUID/PGID.
# user: 1000:1000
environment:
- TZ=Etc/UTC # Use TZ database name from https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
# UID/GID to run the server as; the data directory ownership is updated to match (default 1000:1000)
# - PUID=1000
# - PGID=1000
# Comment these out if you do not use the flaresolverr container at the bottom of this file
- FLARESOLVERR_ENABLED=true
- FLARESOLVERR_URL=http://flaresolverr:8191
Expand Down
56 changes: 56 additions & 0 deletions scripts/docker_entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/bin/sh

# The container starts as root so that the suwayomi user can be remapped to the
# UID/GID requested via the PUID/PGID environment variables (following the
# pattern established by the LinuxServer.io images). After remapping and fixing
# the ownership of the data directory, privileges are dropped and the actual
# command runs as the suwayomi user.

set -e

# When the container is started with an explicit user (eg "docker run --user"
# or "user:" in a compose file) there are no root privileges to remap with,
# so behave exactly like before PUID/PGID support existed and just run the
# command as that user.
if [ "$(id -u)" -ne 0 ]; then
if [ -n "$PUID" ] || [ -n "$PGID" ]; then
echo "WARNING: ignoring PUID/PGID because the container user was overridden (--user), which prevents remapping" >&2
fi
exec "$@"
fi

PUID="${PUID:-1000}"
PGID="${PGID:-1000}"

case "${PUID}${PGID}" in
*[!0-9]*)
echo "ERROR: PUID and PGID must be non-negative integers, got PUID='${PUID}' PGID='${PGID}'" >&2
exit 1
;;
esac

# groupmod also updates the primary group of the suwayomi user in /etc/passwd,
# usermod also updates the owner of files inside /home/suwayomi that are owned
# by the old UID. When PUID/PGID match the current IDs (the default), nothing
# is modified, which keeps eg read-only containers working.
if [ "$PGID" -ne "$(id -g suwayomi)" ]; then
groupmod -o -g "$PGID" suwayomi
fi
if [ "$PUID" -ne "$(id -u suwayomi)" ]; then
usermod -o -u "$PUID" suwayomi
fi

echo "Starting Suwayomi as UID:GID $(id -u suwayomi):$(id -g suwayomi)"

# Hand anything left that is not owned by the (possibly remapped) user over to
# it, most importantly the mounted data directory. Only files with a wrong
# owner are touched so that startups with big libraries stay fast. A failed
# chown (eg rootless podman with the ID not mapped) is only a warning, since
# the server may still have access through the file mode bits.
find /home/suwayomi \( ! -user suwayomi -o ! -group suwayomi \) -print0 \
| xargs -0 -r chown -h suwayomi:suwayomi \
|| echo "WARNING: could not fix the ownership of some files in /home/suwayomi" >&2

# setpriv is the util-linux equivalent of gosu/su-exec; --init-groups keeps
# the supplementary audio/video group memberships of the suwayomi user.
exec setpriv --reuid=suwayomi --regid=suwayomi --init-groups "$@"
7 changes: 7 additions & 0 deletions suwayomi-server.container
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ Environment=TZ=Etc/UTC # Use TZ database name from https://en.wikipedia.org/wiki
Image=ghcr.io/suwayomi/suwayomi-server:preview
PublishPort=4567:4567

# Environment=PUID=1000
# Environment=PGID=1000
# The container starts as (namespaced) root and drops to PUID/PGID, default 1000:1000.
# With UserNS=keep-id below and a host UID of 1000 the defaults are already correct;
# if your host user has a different UID/GID, set PUID/PGID to it so that the server
# runs as the container UID that keep-id maps to your host user.

UserNS=keep-id
# Without UserNS=keep-id, the container's UID 1000 would map to a diffferent host UID which probably doesn't own the bind-mounted directory below

Expand Down