Skip to content

Commit

Permalink
fix: permissions issues
Browse files Browse the repository at this point in the history
Breaking change! Added the ability to change the user ID and group ID of the user running the server process via environment variables UID and GID, requiring a different configuration file location to avoid overriding the '/etc' directory inside the Docker container with the mounted directory.
  • Loading branch information
qx6ghqkz committed Dec 14, 2024
1 parent 1b8e9c1 commit 42e2191
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 24 deletions.
8 changes: 4 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ FROM python:3.12-alpine
RUN apk add --no-cache \
bash \
ffmpeg \
shadow \
su-exec \
tzdata

WORKDIR /usr/src/app
Expand All @@ -26,12 +28,10 @@ ENV GROUP=appgroup
ENV UID=1000
ENV GID=1000

RUN addgroup --gid $GID $GROUP \
&& adduser --disabled-password --gecos "" --home $(pwd) --no-create-home --ingroup $GROUP --uid $UID $USER \
RUN groupadd --gid $GID $GROUP \
&& useradd --home-dir $(pwd) --no-create-home --shell /bin/sh --gid $GID --uid $UID $USER \
&& mkdir -p /.cache/pip /.local \
&& chown -R $UID:$GID . /.cache/pip /.local \
&& chmod +x ./start.sh

USER $USER

CMD ["./start.sh"]
31 changes: 18 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ This example uses the `docker run` command to create the container to run the ap
```shell
docker run -d \
--name gallery-dl-server \
--user 1000:1000 \
-p 9080:9080 \
--mount type=bind,source="/path/to/data",target=/etc \
-e UID=1000 \
-e GID=1000 \
--mount type=bind,source="/path/to/config",target=/config \
--mount type=bind,source="/path/to/downloads",target=/gallery-dl \
--restart unless-stopped \
--restart on-failure \
qx6ghqkz/gallery-dl-server:latest
```

Expand All @@ -37,25 +38,29 @@ services:
image: qx6ghqkz/gallery-dl-server:latest
container_name: gallery-dl-server
network_mode: container:vpn
user: 1000:1000
environment:
- UID=1000
- GID=1000
volumes:
- type: bind
source: "/path/to/data"
target: /etc
source: "/path/to/config"
target: /config
- type: bind
source: "/path/to/downloads"
target: /gallery-dl
restart: unless-stopped
restart: on-failure
```
**Important**: Make sure to mount the directory containing the config file rather than the file itself. This ensures changes to the config file will be picked up without having to restart the Docker container. The server loads all changes made to the config file before each download, but if the file is mounted directly, in order to ensure modifications are propagated to the Docker container while it is still running, you need to make sure your text editor saves changes to the file directly instead of using a temp-replace method (nano should work). More information on this issue [here](https://github.com/moby/moby/issues/15793#issuecomment-135411504).
**Important**: Make sure you mount the directory containing the config file rather than the file itself. This ensures changes to the config file are propagated to the running Docker container and you will not need to restart the container. More information on this issue [here](https://github.com/moby/moby/issues/15793#issuecomment-135411504).
You can use the environment variables `UID` and `GID` to change the user ID and group ID of the user running the server process. This is important because downloaded files will be owned by this user. Make sure the IDs match those of the user on your host system. The default `UID:GID` is `1000:1000` when left unspecified.

### Python

If you have Python ^3.6.0 installed in your PATH you can simply run like this.
If you have Python ^3.6.0 installed in your PATH you can simply run like so. The -u flag is necessary to catch the output immediately.

```shell
python3 -m uvicorn gallery-dl-server:app --port 9080
python3 -u -m uvicorn gallery-dl-server:app --port 9080
```

### Port Mapping
Expand Down Expand Up @@ -101,15 +106,15 @@ services:

Configuration of gallery-dl is as documented in the [official documentation](https://github.com/mikf/gallery-dl#configuration).

The configuration file must be mounted inside the Docker container in one of the locations where gallery-dl will check for the config file (gallery-dl.conf or config.json depending on the location).
The configuration file must be mounted inside the Docker container in one of the locations where gallery-dl will check for the config file.

The target config location used in the examples is `/etc/gallery-dl.conf`. A default configuration file for use with gallery-dl-server has been provided ([gallery-dl.conf](https://github.com/qx6ghqkz/gallery-dl-server/blob/main/gallery-dl.conf)).
The server uses a custom target config location of `/config/gallery-dl.conf`. A [default configuration file](https://github.com/qx6ghqkz/gallery-dl-server/blob/main/gallery-dl.conf) for use with gallery-dl-server has been provided.

For more information on configuration file options, see [gallery-dl/docs/configuration.rst](https://github.com/mikf/gallery-dl/blob/master/docs/configuration.rst).

Any additional directories specified in the configuration file must also be mounted inside the Docker container, for example if you specify a cookies file location then make sure that location is accessible from within the Docker container.

It is recommended to place any additional files such as archive, cache and cookies files inside the same `data` directory as the config file.
It is recommended you place any additional files such as archive, cache and cookies files inside the same `config` directory as `gallery-dl.conf` and then mount that directory to `/config` inside the container, as in the examples.

## Usage

Expand Down
8 changes: 4 additions & 4 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#
# Docker Compose template using gluetun as a VPN in the same container stack.
# In this example, `gallery-dl.conf` is located inside the `data` folder in the same directory as the Compose file.
# In this example, `gallery-dl.conf` is located inside the `config` folder in the same directory as the Compose file.
# The environment variables for your VPN configuration can go in this file or a separate `.env` file in the same directory,
# or specify the location with `docker compose --env-file <location> up -d`.
#
Expand All @@ -17,12 +17,12 @@ services:
- GID=1000
volumes:
- type: bind
source: ./data
target: /etc
source: ./config
target: /config
- type: bind
source: ~/Downloads/gallery-dl
target: /gallery-dl
restart: unless-stopped
restart: on-failure

gluetun:
image: qmcgaw/gluetun:latest
Expand Down
2 changes: 1 addition & 1 deletion gallery-dl-server.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ def download(url, request_options):
"Requested download with the following overriding options: %s", request_options
)

cmd = ["gallery-dl", url]
cmd = ["gallery-dl", "--config", "/config/gallery-dl.conf", url]
process = subprocess.Popen(
cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True
)
Expand Down
98 changes: 96 additions & 2 deletions start.sh
Original file line number Diff line number Diff line change
@@ -1,2 +1,96 @@
#!/bin/sh
exec uvicorn gallery-dl-server:app --host 0.0.0.0 --port $CONTAINER_PORT --log-level info --no-access-log
#!/usr/bin/env bash

check_etc () {
if [[ ! -f /etc/passwd ]]; then
exit 1
fi
}

get_ids () {
UID_OG="$(id -u appuser)"
GID_OG="$(id -g appuser)"

UID="${UID:-$UID_OG}"
GID="${GID:-$GID_OG}"
}

mod_ids () {
groupmod --non-unique --gid "$GID" appgroup >/dev/null 2>&1
usermod --non-unique --gid "$GID" --uid "$UID" appuser >/dev/null 2>&1

chown --quiet -R "$UID:$GID" /usr/src/app /.cache/pip /.local
}

init () {
if [[ $UID -eq $(id -u appuser) && $GID -eq $(id -g appuser) ]]; then
log 0
if [[ $(id -u) -eq $(id -u root) ]]; then
start 0
elif [[ $(id -u) -eq $(id -u appuser) ]]; then
start 1
else
exit 0
fi
else
log 1
if [[ $(id -u) -eq $(id -u root) ]]; then
start 0
elif [[ $(id -u) -eq $(id -u appuser) ]]; then
start 1
else
exit 0
fi
fi
}

log() {
if [[ $1 -eq 0 ]]; then
echo "INFO: Starting process with UID=$UID and GID=$GID ($(getent passwd $UID | cut -d: -f1))"
elif [[ $1 -eq 1 ]]; then
echo "INFO: Starting process with UID=$(id -u) and GID=$(id -g) ($(id -u -n))"
else
exit 0
fi
}

start() {
if [[ $1 -eq 0 ]]; then
exec su-exec appuser uvicorn gallery-dl-server:app --host 0.0.0.0 --port "$CONTAINER_PORT" --log-level info --no-access-log
elif [[ $1 -eq 1 ]]; then
exec uvicorn gallery-dl-server:app --host 0.0.0.0 --port "$CONTAINER_PORT" --log-level info --no-access-log
else
exit 0
fi
}

exit() {
if [[ $1 -eq 0 ]]; then
echo "error: fatal error"
elif [[ $1 -eq 1 ]]; then
echo "error: config mount location has changed from /etc to /config; please mount the directory containing gallery-dl.conf to /config" \
"and make sure to update any paths specified inside your config file, e.g. /etc/cookies.txt --> /config/cookies.txt"
elif [[ $1 -eq 2 ]]; then
echo "error: invalid permissions; use the environment variables UID and GID to set the user ID and group ID" \
"(defaults: UID=$UID_OG, GID=$GID_OG)"
fi
command exit 0
}

check_etc
get_ids
if [[ $UID -ne $UID_OG || $GID -ne $GID_OG ]]; then
if [[ $(id -u -n 2>/dev/null) == root ]]; then
mod_ids
init
elif [[ $(id -u -n 2>/dev/null) == appuser ]]; then
init
else
exit 2
fi
elif [[ $(id -u -n 2>/dev/null) == root ]]; then
init
elif [[ $(id -u -n 2>/dev/null) == appuser ]]; then
init
else
exit 2
fi

0 comments on commit 42e2191

Please sign in to comment.