From d022d08c19a43139eca1b0260d19a8b848af1daf Mon Sep 17 00:00:00 2001 From: pradip Date: Tue, 10 Feb 2026 08:27:36 +0545 Subject: [PATCH 1/7] implement s3webdav proxy --- Dockerfile | 39 +++++++++++++++++++++++++++++++++++++++ docker/auth-proxy.py | 24 ++++++++++++++++++++++++ docker/startup | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 Dockerfile create mode 100644 docker/auth-proxy.py create mode 100644 docker/startup diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8ea9bac --- /dev/null +++ b/Dockerfile @@ -0,0 +1,39 @@ +FROM rclone/rclone:latest AS binaries + +# final image +FROM alpine:latest + +# copy the rclone binary from the official image +COPY --from=binaries /usr/local/bin/rclone /usr/local/bin/rclone + +# copy startup and auth proxy scripts +COPY ["./docker/startup", "/startup"] +COPY ["./docker/auth-proxy.py", "/usr/local/bin/auth-proxy.py"] + +# add python for the auth proxy script +RUN apk --no-cache add \ + python3 \ + ca-certificates \ + fuse3 \ + tzdata \ + && apk cache clean + +# make scripts executable +RUN echo "user_allow_other" >> /etc/fuse.conf && \ + chmod +x /startup /usr/local/bin/auth-proxy.py + +WORKDIR /data + +ENV XDG_CONFIG_HOME=/config + +# remote configs (used by auth-proxy.py) +ENV REMOTE_URL="" +ENV REMOTE_VENDOR="" + +# s3 proxy configs +# a space separated list of options +ENV PROXY_ARGS="" + +ENTRYPOINT [ "/startup" ] + +EXPOSE 8080 \ No newline at end of file diff --git a/docker/auth-proxy.py b/docker/auth-proxy.py new file mode 100644 index 0000000..c789036 --- /dev/null +++ b/docker/auth-proxy.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +""" +A proxy for rclone serve s3 +""" + +import sys +import json +import os + + +def main(): + i = json.load(sys.stdin) + o = { + "type": "webdav", # type of backend + "_root": "", # root of the fs + "bearer_token": i["pass"], + "url": os.getenv("REMOTE_URL", "https://localhost:9200/remote.php/webdav"), + "vendor": os.getenv("REMOTE_VENDOR", "owncloud"), + } + json.dump(o, sys.stdout, indent="\t") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/docker/startup b/docker/startup new file mode 100644 index 0000000..b8b95a1 --- /dev/null +++ b/docker/startup @@ -0,0 +1,37 @@ +#!/bin/sh + +RCLONE_CONFIG=/config/rclone/rclone.conf + +if [ -z "$REMOTE_NAME" ]; then + echo "REMOTE_NAME is not set" + exit 1 +fi +if [ -z "$REMOTE_URL" ]; then + echo "REMOTE_URL is not set" + exit 1 +fi +if [ -z "$REMOTE_VENDOR" ]; then + echo "REMOTE_VENDOR is not set" + exit 1 +fi + +mkdir -p "$(dirname "$RCLONE_CONFIG")" + +cat <"$RCLONE_CONFIG" +[$REMOTE_NAME] +type = webdav +url = $REMOTE_URL +vendor = $REMOTE_VENDOR +nextcloud_chunk_size = 0 +EOF + +# Check if --auth-proxy is part of PROXY_ARGS +if echo " $PROXY_ARGS " | grep -q ' --auth-proxy '; then + # Auth-proxy mode for per-user access. + # Do not pass the remote name as an argument. + exec rclone serve s3 $PROXY_ARGS +else + # Anonymous or single-user mode. + # Pass the remote name as an argument. + exec rclone serve s3 $PROXY_ARGS "$REMOTE_NAME:" +fi \ No newline at end of file From 0d5552da34305a320ed4e1fd7aeb983aa20033d7 Mon Sep 17 00:00:00 2001 From: pradip Date: Tue, 10 Feb 2026 18:21:14 +0545 Subject: [PATCH 2/7] implement ability to use custom auth script --- README.md | 242 +++++++++++++++++++++++++++++++++++++++++++++++++ docker/startup | 7 +- 2 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..0606569 --- /dev/null +++ b/README.md @@ -0,0 +1,242 @@ +# S3-WebDAV Proxy + +A Docker-based proxy that exposes WebDAV storage as an S3-compatible interface using [rclone](https://rclone.org/). + +## Features + +- **Two modes of operation:** + - **Per-user mode (`--auth-proxy`)**: Each S3 request uses the client's credentials to access their own WebDAV backend + - **Anonymous mode**: Single static WebDAV remote for public access without credentials +- **S3-compatible**: Works with any S3 client (e.g., `mc`) +- **Docker-ready**: Simple containerized deployment +- **Customizable auth-proxy**: Override the auth-proxy script for custom authentication logic + +## Quick Start + +### Build the image + +```bash +docker build -t jankari/rclone-webdav-proxy . +``` + +### Run the container + +```bash +docker run --rm --network=host \ + -e REMOTE_NAME=ocis \ + -e REMOTE_URL="https://your-webdav-server.com/remote.php/webdav" \ + -e REMOTE_VENDOR=owncloud \ + -e PROXY_ARGS="--auth-proxy --auth-key ,12345678 --no-check-certificate -vv" \ + jankari/rclone-webdav-proxy +``` + +The S3-compatible server will be available at `http://localhost:8080`. Access it using an S3 client (e.g., `mc`). + +## Configuration + +### Environment Variables + +| Variable | Required | Description | +|----------|----------|-------------| +| `REMOTE_NAME` | Yes | Name for the rclone remote (e.g., `ocis`) | +| `REMOTE_URL` | Yes | WebDAV server URL | +| `REMOTE_VENDOR` | Yes | WebDAV vendor (`owncloud`, `nextcloud`, `webdav`, etc.) | +| `PROXY_ARGS` | No | Additional rclone arguments | +| `AUTH_PROXY_PATH` | No | Path to custom auth-proxy script (default: `/usr/local/bin/auth-proxy.py`) | + +### PROXY_ARGS Options + +Common rclone options for `serve s3`: + +| Option | Description | +|--------|-------------| +| `--auth-proxy ` | Enable per-user authentication (see modes below) | +| `--auth-key ,` | Validate SigV4 signatures with fixed secret (wildcard access key) | +| `--no-check-certificate` | Disable SSL certificate verification | +| `-vv` | Verbose logging (debug level) | + +## Usage Modes + +### Per-User Mode (Private Access) + +Use `--auth-proxy` to enable per-request authentication. Each S3 client uses their own credentials to access their WebDAV storage. + +**1. Start the proxy:** + +```bash +docker run --rm --network=host \ + -e REMOTE_NAME=ocis \ + -e REMOTE_URL="https://your-server.com/remote.php/webdav" \ + -e REMOTE_VENDOR=owncloud \ + -e PROXY_ARGS="--auth-proxy --auth-key ,12345678 --no-check-certificate" \ + jankari/rclone-webdav-proxy +``` + +**2. Configure S3 client (MinIO Client - `mc`):** + +```bash +mc alias set myproxy http://localhost:8080 12345678 +``` + +- ``: Your WebDAV/OCIS access token +- `12345678`: The access key ID (matches `--auth-key` prefix) + +**3. Access your files:** + +```bash +mc ls myproxy +``` + +### Anonymous Mode (Public Access) + +Omit `--auth-proxy` to enable anonymous access to a single static WebDAV remote. + +**1. Start the proxy:** + +```bash +docker run --rm --network=host \ + -e REMOTE_NAME=ocis \ + -e REMOTE_URL="https://your-server.com/dav/public-files/" \ + -e REMOTE_VENDOR=owncloud \ + -e PROXY_ARGS="--no-check-certificate" \ + jankari/rclone-webdav-proxy +``` + +**2. Configure S3 client with empty credentials:** + +```bash +mc alias set myproxy http://localhost:8080 "" "" +``` + +**3. Access public files:** + +```bash +mc ls myproxy +``` + +## Custom Auth-Proxy Script + +The auth-proxy script enables dynamic backend configuration per request. You can customize it in two ways: + +### Option 1: Volume Mount + +Mount your custom script over the bundled one: + +```bash +docker run --rm --network=host \ + -e REMOTE_NAME=ocis \ + -e REMOTE_URL="https://your-server.com/remote.php/webdav" \ + -e REMOTE_VENDOR=owncloud \ + -e PROXY_ARGS="--auth-proxy --auth-key ,12345678" \ + -v /path/to/custom-auth-proxy.py:/usr/local/bin/auth-proxy.py \ + jankari/rclone-webdav-proxy +``` + +### Option 2: Environment Variable + +Use a custom path with `AUTH_PROXY_PATH`: + +```bash +docker run --rm --network=host \ + -e REMOTE_NAME=ocis \ + -e REMOTE_URL="https://your-server.com/remote.php/webdav" \ + -e REMOTE_VENDOR=owncloud \ + -e PROXY_ARGS="--auth-proxy --auth-key ,12345678" \ + -e AUTH_PROXY_PATH="/my/custom/script.py" \ + -v /my/custom/script.py:/my/custom/script.py \ + jankari/rclone-webdav-proxy +``` + +### Auth-Proxy Protocol + +The auth-proxy script must: + +1. **Read from stdin**: JSON with user credentials + ```json + {"pass": "", "user": ""} + ``` + +2. **Write to stdout**: JSON with WebDAV backend config + ```json + { + "type": "webdav", + "_root": "", + "bearer_token": "", + "url": "https://server.com/remote.php/webdav", + "vendor": "owncloud" + } + ``` + +Example implementation (`auth-proxy.py`): + +```python +#!/usr/bin/env python3 +import sys +import json +import os + +def main(): + i = json.load(sys.stdin) + o = { + "type": "webdav", + "_root": "", + "bearer_token": i["pass"], + "url": os.getenv("REMOTE_URL", "https://localhost:9200/remote.php/webdav"), + "vendor": os.getenv("REMOTE_VENDOR", "owncloud"), + } + json.dump(o, sys.stdout, indent="\t") + +if __name__ == "__main__": + main() +``` + +## Example: OwnCloud OCIS Setup + +### Prerequisites + +1. Start OCIS server: + ```bash + OCIS_LOG_LEVEL=debug PROXY_ENABLE_BASIC_AUTH=true \ + IDM_CREATE_DEMO_USERS=true OCIS_INSECURE=true ./ocis/bin/ocis server + ``` + +2. Get an access token from OCIS web interface + +### Per-User Access + +```bash +docker run --rm --network=host \ + -e REMOTE_NAME=ocis \ + -e REMOTE_URL="https://localhost:9200/remote.php/webdav" \ + -e REMOTE_VENDOR=owncloud \ + -e PROXY_ARGS="--auth-proxy --auth-key ,12345678 --no-check-certificate -vv" \ + jankari/rclone-webdav-proxy +``` + +```bash +mc alias set myproxy http://localhost:8080 12345678 +mc ls myproxy +``` + +### Anonymous Public Access + +1. Create a public link in OCIS +2. Use the unique ID from the public link: + +```bash +docker run --rm --network=host \ + -e REMOTE_NAME=ocis \ + -e REMOTE_URL="https://localhost:9200/dav/public-files/A1b2C3d4E5f6G7h8I9j0" \ + -e REMOTE_VENDOR=owncloud \ + -e PROXY_ARGS="--no-check-certificate" \ + jankari/rclone-webdav-proxy +``` + +```bash +mc alias set myproxy http://localhost:8080 "" "" +mc ls myproxy +``` + +## License + +MIT diff --git a/docker/startup b/docker/startup index b8b95a1..bdef107 100644 --- a/docker/startup +++ b/docker/startup @@ -25,10 +25,15 @@ vendor = $REMOTE_VENDOR nextcloud_chunk_size = 0 EOF +AUTH_PROXY_PATH="${AUTH_PROXY_PATH:-/usr/local/bin/auth-proxy.py}" + # Check if --auth-proxy is part of PROXY_ARGS if echo " $PROXY_ARGS " | grep -q ' --auth-proxy '; then # Auth-proxy mode for per-user access. - # Do not pass the remote name as an argument. + # Auto-append AUTH_PROXY_PATH if --auth-proxy has no path + if echo " $PROXY_ARGS " | grep -qE ' --auth-proxy$| --auth-proxy --| --auth-proxy -'; then + PROXY_ARGS=$(echo "$PROXY_ARGS" | sed "s|--auth-proxy|& $AUTH_PROXY_PATH|") + fi exec rclone serve s3 $PROXY_ARGS else # Anonymous or single-user mode. From 6ac29cc007fbd15c266161c0c3a129fe1a0b20ea Mon Sep 17 00:00:00 2001 From: pradip Date: Thu, 12 Feb 2026 08:16:52 +0545 Subject: [PATCH 3/7] Update image name in README --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 0606569..b18c5d0 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ A Docker-based proxy that exposes WebDAV storage as an S3-compatible interface u ### Build the image ```bash -docker build -t jankari/rclone-webdav-proxy . +docker build -t jankaritech/s3-webdav-proxy . ``` ### Run the container @@ -27,7 +27,7 @@ docker run --rm --network=host \ -e REMOTE_URL="https://your-webdav-server.com/remote.php/webdav" \ -e REMOTE_VENDOR=owncloud \ -e PROXY_ARGS="--auth-proxy --auth-key ,12345678 --no-check-certificate -vv" \ - jankari/rclone-webdav-proxy + jankaritech/s3-webdav-proxy ``` The S3-compatible server will be available at `http://localhost:8080`. Access it using an S3 client (e.g., `mc`). @@ -69,7 +69,7 @@ docker run --rm --network=host \ -e REMOTE_URL="https://your-server.com/remote.php/webdav" \ -e REMOTE_VENDOR=owncloud \ -e PROXY_ARGS="--auth-proxy --auth-key ,12345678 --no-check-certificate" \ - jankari/rclone-webdav-proxy + jankaritech/s3-webdav-proxy ``` **2. Configure S3 client (MinIO Client - `mc`):** @@ -99,7 +99,7 @@ docker run --rm --network=host \ -e REMOTE_URL="https://your-server.com/dav/public-files/" \ -e REMOTE_VENDOR=owncloud \ -e PROXY_ARGS="--no-check-certificate" \ - jankari/rclone-webdav-proxy + jankaritech/s3-webdav-proxy ``` **2. Configure S3 client with empty credentials:** @@ -129,7 +129,7 @@ docker run --rm --network=host \ -e REMOTE_VENDOR=owncloud \ -e PROXY_ARGS="--auth-proxy --auth-key ,12345678" \ -v /path/to/custom-auth-proxy.py:/usr/local/bin/auth-proxy.py \ - jankari/rclone-webdav-proxy + jankaritech/s3-webdav-proxy ``` ### Option 2: Environment Variable @@ -144,7 +144,7 @@ docker run --rm --network=host \ -e PROXY_ARGS="--auth-proxy --auth-key ,12345678" \ -e AUTH_PROXY_PATH="/my/custom/script.py" \ -v /my/custom/script.py:/my/custom/script.py \ - jankari/rclone-webdav-proxy + jankaritech/s3-webdav-proxy ``` ### Auth-Proxy Protocol @@ -210,7 +210,7 @@ docker run --rm --network=host \ -e REMOTE_URL="https://localhost:9200/remote.php/webdav" \ -e REMOTE_VENDOR=owncloud \ -e PROXY_ARGS="--auth-proxy --auth-key ,12345678 --no-check-certificate -vv" \ - jankari/rclone-webdav-proxy + jankaritech/s3-webdav-proxy ``` ```bash @@ -229,7 +229,7 @@ docker run --rm --network=host \ -e REMOTE_URL="https://localhost:9200/dav/public-files/A1b2C3d4E5f6G7h8I9j0" \ -e REMOTE_VENDOR=owncloud \ -e PROXY_ARGS="--no-check-certificate" \ - jankari/rclone-webdav-proxy + jankaritech/s3-webdav-proxy ``` ```bash From d1bb0ab7068b6ea7d2783756fba76120bb47fc11 Mon Sep 17 00:00:00 2001 From: pradip Date: Thu, 12 Feb 2026 08:17:57 +0545 Subject: [PATCH 4/7] Add docker hub ci workflow --- .github/workflows/docker-publish.yml | 42 ++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 .github/workflows/docker-publish.yml diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 0000000..0f545bb --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,42 @@ +name: Publish to Docker Hub + +on: + push: + branches: [ main ] + tags: [ 'v*' ] + +jobs: + build-and-push: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Extract metadata for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: jankaritech/s3-webdav-proxy + tags: | + type=ref,event=branch + type=ref,event=tag + type=sha + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} From 12daa0f48f4e6e0036f127f6bef8b6dd37449eca Mon Sep 17 00:00:00 2001 From: pradip Date: Thu, 12 Feb 2026 18:20:23 +0545 Subject: [PATCH 5/7] refactor --auth-proxy option and update readme accordingly --- README.md | 19 +++++++++++++++---- docker/auth-proxy.py | 16 ++++++++++++---- docker/startup | 6 +++--- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index b18c5d0..68288ad 100644 --- a/README.md +++ b/README.md @@ -177,12 +177,20 @@ import os def main(): i = json.load(sys.stdin) + url = os.getenv("REMOTE_URL") + vendor = os.getenv("REMOTE_VENDOR") + if not url: + print("REMOTE_URL is not set", file=sys.stderr) + sys.exit(1) + if not vendor: + print("REMOTE_VENDOR is not set", file=sys.stderr) + sys.exit(1) o = { "type": "webdav", "_root": "", "bearer_token": i["pass"], - "url": os.getenv("REMOTE_URL", "https://localhost:9200/remote.php/webdav"), - "vendor": os.getenv("REMOTE_VENDOR", "owncloud"), + "url": url, + "vendor": vendor, } json.dump(o, sys.stdout, indent="\t") @@ -194,13 +202,13 @@ if __name__ == "__main__": ### Prerequisites -1. Start OCIS server: +1. Start OCIS server (ocis binary is used here for demonstration, but you can use your own OCIS setup): ```bash OCIS_LOG_LEVEL=debug PROXY_ENABLE_BASIC_AUTH=true \ IDM_CREATE_DEMO_USERS=true OCIS_INSECURE=true ./ocis/bin/ocis server ``` -2. Get an access token from OCIS web interface +2. Get an access token from OCIS (Follow [this instruction](https://github.com/jankariTech/rclone?tab=readme-ov-file#3-obtain-a-bearer-token-from-the-webdav-server) to get token or you can just get access token from network tab in browser dev tools when you log in to OCIS web interface) ### Per-User Access @@ -237,6 +245,9 @@ mc alias set myproxy http://localhost:8080 "" "" mc ls myproxy ``` +> [!INFORMATION] +> More details can be found [here](https://github.com/jankariTech/rclone?tab=readme-ov-file#3-obtain-a-bearer-token-from-the-webdav-server) + ## License MIT diff --git a/docker/auth-proxy.py b/docker/auth-proxy.py index c789036..a808a4c 100644 --- a/docker/auth-proxy.py +++ b/docker/auth-proxy.py @@ -10,12 +10,20 @@ def main(): i = json.load(sys.stdin) + url = os.getenv("REMOTE_URL") + vendor = os.getenv("REMOTE_VENDOR") + if not url: + print("REMOTE_URL is not set", file=sys.stderr) + sys.exit(1) + if not vendor: + print("REMOTE_VENDOR is not set", file=sys.stderr) + sys.exit(1) o = { - "type": "webdav", # type of backend - "_root": "", # root of the fs + "type": "webdav", + "_root": "", "bearer_token": i["pass"], - "url": os.getenv("REMOTE_URL", "https://localhost:9200/remote.php/webdav"), - "vendor": os.getenv("REMOTE_VENDOR", "owncloud"), + "url": url, + "vendor": vendor, } json.dump(o, sys.stdout, indent="\t") diff --git a/docker/startup b/docker/startup index bdef107..c5bbb45 100644 --- a/docker/startup +++ b/docker/startup @@ -28,10 +28,10 @@ EOF AUTH_PROXY_PATH="${AUTH_PROXY_PATH:-/usr/local/bin/auth-proxy.py}" # Check if --auth-proxy is part of PROXY_ARGS -if echo " $PROXY_ARGS " | grep -q ' --auth-proxy '; then +if echo " $PROXY_ARGS " | grep -q -- '--auth-proxy'; then # Auth-proxy mode for per-user access. - # Auto-append AUTH_PROXY_PATH if --auth-proxy has no path - if echo " $PROXY_ARGS " | grep -qE ' --auth-proxy$| --auth-proxy --| --auth-proxy -'; then + # If --auth-proxy has no path after it, use the default AUTH_PROXY_PATH + if echo " $PROXY_ARGS " | grep -qE ' --auth-proxy($| )'; then PROXY_ARGS=$(echo "$PROXY_ARGS" | sed "s|--auth-proxy|& $AUTH_PROXY_PATH|") fi exec rclone serve s3 $PROXY_ARGS From 7a3180c08a1c7b0329a3e3ff601b291f90a94e86 Mon Sep 17 00:00:00 2001 From: pradip Date: Mon, 16 Feb 2026 08:41:30 +0545 Subject: [PATCH 6/7] update README file --- README.md | 171 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 97 insertions(+), 74 deletions(-) diff --git a/README.md b/README.md index 68288ad..ef2ed8b 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,22 @@ A Docker-based proxy that exposes WebDAV storage as an S3-compatible interface u ## Features - **Two modes of operation:** - - **Per-user mode (`--auth-proxy`)**: Each S3 request uses the client's credentials to access their own WebDAV backend + - **Per-user mode (`--auth-proxy`)**: Each S3 request uses the client's access token (passed as the S3 access key ID) and a fixed secret key for SigV4 authentication to access their WebDAV backend - **Anonymous mode**: Single static WebDAV remote for public access without credentials - **S3-compatible**: Works with any S3 client (e.g., `mc`) - **Docker-ready**: Simple containerized deployment - **Customizable auth-proxy**: Override the auth-proxy script for custom authentication logic +## Purpose + +This proxy allows accessing WebDAV backends through the S3 protocol. As a developer of an app that can talk to S3 backends, you can access WebDAV servers through the S3 protocol without having to implement and maintain two protocols in your code. + +## How It Works + +The proxy is based on [rclone](https://rclone.org/), a powerful tool for managing files on cloud storage. Rclone can serve storage over various protocols, including S3. + +The key innovation is handling per-user authentication: each S3 request uses the client's access token (passed as the S3 access key ID) as a Bearer token to authenticate against the WebDAV server. This allows accessing data from different WebDAV users through the S3 protocol. + ## Quick Start ### Build the image @@ -23,37 +33,55 @@ docker build -t jankaritech/s3-webdav-proxy . ```bash docker run --rm --network=host \ - -e REMOTE_NAME=ocis \ - -e REMOTE_URL="https://your-webdav-server.com/remote.php/webdav" \ - -e REMOTE_VENDOR=owncloud \ - -e PROXY_ARGS="--auth-proxy --auth-key ,12345678 --no-check-certificate -vv" \ + -e REMOTE_NAME= \ + -e REMOTE_URL="https://your-webdav-server.com/" \ + -e REMOTE_VENDOR= \ + -e PROXY_ARGS="--auth-proxy --auth-key , --no-check-certificate -vv" \ jankaritech/s3-webdav-proxy ``` The S3-compatible server will be available at `http://localhost:8080`. Access it using an S3 client (e.g., `mc`). +> **Note:** +> - `` is the **secret key** for SigV4 signature validation (format: `,`). +> - `--no-check-certificate` disables SSL verification. **Do not use in production** - use a valid certificate instead. + ## Configuration ### Environment Variables -| Variable | Required | Description | -|----------|----------|-------------| -| `REMOTE_NAME` | Yes | Name for the rclone remote (e.g., `ocis`) | -| `REMOTE_URL` | Yes | WebDAV server URL | -| `REMOTE_VENDOR` | Yes | WebDAV vendor (`owncloud`, `nextcloud`, `webdav`, etc.) | -| `PROXY_ARGS` | No | Additional rclone arguments | -| `AUTH_PROXY_PATH` | No | Path to custom auth-proxy script (default: `/usr/local/bin/auth-proxy.py`) | +| Variable | Required | Description | +|-------------------|----------|----------------------------------------------------------------------------| +| `REMOTE_NAME` | Yes | Name for the rclone remote (e.g., `ocis`) | +| `REMOTE_URL` | Yes | WebDAV server URL | +| `REMOTE_VENDOR` | Yes | WebDAV vendor (`owncloud`, `nextcloud`, `webdav`, etc.) | +| `PROXY_ARGS` | No | Additional rclone arguments | +| `AUTH_PROXY_PATH` | No | Path to custom auth-proxy script (default: `/usr/local/bin/auth-proxy.py`) | ### PROXY_ARGS Options Common rclone options for `serve s3`: -| Option | Description | -|--------|-------------| -| `--auth-proxy ` | Enable per-user authentication (see modes below) | -| `--auth-key ,` | Validate SigV4 signatures with fixed secret (wildcard access key) | -| `--no-check-certificate` | Disable SSL certificate verification | -| `-vv` | Verbose logging (debug level) | +| Option | Description | +|---------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------| +| `--auth-proxy ` | Enable per-user authentication (see modes below) | +| `--auth-key ,` | Validate SigV4 signatures with fixed secret (wildcard access key) | +| `--no-check-certificate` | Disable SSL certificate verification | +| `-vv` | Verbose logging (debug level) | +| `--vfs-cache-max-age` | Max time since last access of objects in the cache (default 1h0m0s) | +| `--vfs-cache-max-size` | Max total size of objects in the cache (default off) | +| `--vfs-cache-mode` | Cache mode off\|minimal\|writes\|full (default off) | +| `--vfs-cache-poll-interval` | Interval to poll the cache for stale objects (default 1m0s) | +| `--vfs-case-insensitive` | If a file name not found, find a case insensitive match | +| `--vfs-disk-space-total-size` | Specify the total space of disk (default off) | +| `--vfs-fast-fingerprint` | Use fast (less accurate) fingerprints for change detection | +| `--vfs-read-ahead` | Extra read ahead over `--buffer-size` when using cache-mode full | +| `--vfs-read-chunk-size` | Read the source objects in chunks (default 128Mi) | +| `--vfs-read-chunk-size-limit` | If greater than `--vfs-read-chunk-size`, double the chunk size after each chunk read, until the limit is reached ('off' is unlimited) (default off) | +| `--vfs-read-wait` | Time to wait for in-sequence read before seeking (default 20ms) | +| `--vfs-used-is-size` | rclone size Use the rclone size algorithm for Used size | +| `--vfs-write-back` | Time to writeback files after last use when using cache (default 5s) | +| `--vfs-write-wait` | Time to wait for in-sequence write before giving error (default 1s) | ## Usage Modes @@ -63,23 +91,16 @@ Use `--auth-proxy` to enable per-request authentication. Each S3 client uses the **1. Start the proxy:** -```bash -docker run --rm --network=host \ - -e REMOTE_NAME=ocis \ - -e REMOTE_URL="https://your-server.com/remote.php/webdav" \ - -e REMOTE_VENDOR=owncloud \ - -e PROXY_ARGS="--auth-proxy --auth-key ,12345678 --no-check-certificate" \ - jankaritech/s3-webdav-proxy -``` +See [Quick Start](#quick-start) for the docker command. **2. Configure S3 client (MinIO Client - `mc`):** ```bash -mc alias set myproxy http://localhost:8080 12345678 +mc alias set myproxy http://localhost:8080 ``` -- ``: Your WebDAV/OCIS access token -- `12345678`: The access key ID (matches `--auth-key` prefix) +- ``: Your WebDAV access token +- ``: The secret key (must match the value specified in `--auth-key ,`) **3. Access your files:** @@ -95,9 +116,9 @@ Omit `--auth-proxy` to enable anonymous access to a single static WebDAV remote. ```bash docker run --rm --network=host \ - -e REMOTE_NAME=ocis \ - -e REMOTE_URL="https://your-server.com/dav/public-files/" \ - -e REMOTE_VENDOR=owncloud \ + -e REMOTE_NAME= \ + -e REMOTE_URL="https://your-server.com/" \ + -e REMOTE_VENDOR= \ -e PROXY_ARGS="--no-check-certificate" \ jankaritech/s3-webdav-proxy ``` @@ -124,10 +145,10 @@ Mount your custom script over the bundled one: ```bash docker run --rm --network=host \ - -e REMOTE_NAME=ocis \ - -e REMOTE_URL="https://your-server.com/remote.php/webdav" \ - -e REMOTE_VENDOR=owncloud \ - -e PROXY_ARGS="--auth-proxy --auth-key ,12345678" \ + -e REMOTE_NAME= \ + -e REMOTE_URL="https://your-server.com/" \ + -e REMOTE_VENDOR= \ + -e PROXY_ARGS="--auth-proxy --auth-key ," \ -v /path/to/custom-auth-proxy.py:/usr/local/bin/auth-proxy.py \ jankaritech/s3-webdav-proxy ``` @@ -138,10 +159,10 @@ Use a custom path with `AUTH_PROXY_PATH`: ```bash docker run --rm --network=host \ - -e REMOTE_NAME=ocis \ - -e REMOTE_URL="https://your-server.com/remote.php/webdav" \ - -e REMOTE_VENDOR=owncloud \ - -e PROXY_ARGS="--auth-proxy --auth-key ,12345678" \ + -e REMOTE_NAME= \ + -e REMOTE_URL="https://your-server.com/" \ + -e REMOTE_VENDOR= \ + -e PROXY_ARGS="--auth-proxy --auth-key ," \ -e AUTH_PROXY_PATH="/my/custom/script.py" \ -v /my/custom/script.py:/my/custom/script.py \ jankaritech/s3-webdav-proxy @@ -169,34 +190,7 @@ The auth-proxy script must: Example implementation (`auth-proxy.py`): -```python -#!/usr/bin/env python3 -import sys -import json -import os - -def main(): - i = json.load(sys.stdin) - url = os.getenv("REMOTE_URL") - vendor = os.getenv("REMOTE_VENDOR") - if not url: - print("REMOTE_URL is not set", file=sys.stderr) - sys.exit(1) - if not vendor: - print("REMOTE_VENDOR is not set", file=sys.stderr) - sys.exit(1) - o = { - "type": "webdav", - "_root": "", - "bearer_token": i["pass"], - "url": url, - "vendor": vendor, - } - json.dump(o, sys.stdout, indent="\t") - -if __name__ == "__main__": - main() -``` +See [docker/auth-proxy.py](docker/auth-proxy.py) for the complete example implementation. ## Example: OwnCloud OCIS Setup @@ -204,11 +198,43 @@ if __name__ == "__main__": 1. Start OCIS server (ocis binary is used here for demonstration, but you can use your own OCIS setup): ```bash - OCIS_LOG_LEVEL=debug PROXY_ENABLE_BASIC_AUTH=true \ - IDM_CREATE_DEMO_USERS=true OCIS_INSECURE=true ./ocis/bin/ocis server + OCIS_LOG_LEVEL=debug IDM_CREATE_DEMO_USERS=true \ + OCIS_INSECURE=true ./ocis/bin/ocis server ``` -2. Get an access token from OCIS (Follow [this instruction](https://github.com/jankariTech/rclone?tab=readme-ov-file#3-obtain-a-bearer-token-from-the-webdav-server) to get token or you can just get access token from network tab in browser dev tools when you log in to OCIS web interface) +2. Get an access token from OCIS: + + **Option A: Using browser (simplest)** + - Log in to OCIS web interface with your credentials + - Open browser DevTools (F12) → Network tab + - Make any request to OCIS + - Find the request with `Authorization: Bearer ` header + - Copy the bearer token + + **Option B: Using app-password (Nextcloud only)** + - Go to Personal Settings → Security + - Generate a new app password + - Use the app password as your bearer token + + **Option C: Using oauth2 (advanced)** + - Install oauth2 app in OCIS + - Create oauth2 client with redirect URL `http://localhost:9876/` + - Create a JSON file `oauth.json` with the client credentials: + ```json + { + "installed": { + "client_id": "", + "auth_uri": "/index.php/apps/oauth2/authorize", + "token_uri": "/index.php/apps/oauth2/api/v1/token", + "client_secret": "", + "redirect_uris": ["http://localhost:9876"] + } + } + ``` + - Use [oauth2l](https://github.com/google/oauth2l) to fetch token: + ```bash + ./oauth2l fetch --credentials oauth.json --scope all --refresh --output_format bare + ``` ### Per-User Access @@ -245,9 +271,6 @@ mc alias set myproxy http://localhost:8080 "" "" mc ls myproxy ``` -> [!INFORMATION] -> More details can be found [here](https://github.com/jankariTech/rclone?tab=readme-ov-file#3-obtain-a-bearer-token-from-the-webdav-server) - ## License MIT From a15c07b0b34d0f2e431e3c2a5bab2cac1afa1603 Mon Sep 17 00:00:00 2001 From: pradip Date: Wed, 18 Feb 2026 18:42:03 +0545 Subject: [PATCH 7/7] use nextcloud as an example --- README.md | 103 ++++++++++++++++++------------------------- docker/auth-proxy.py | 4 ++ 2 files changed, 48 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index ef2ed8b..00c171d 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ A Docker-based proxy that exposes WebDAV storage as an S3-compatible interface using [rclone](https://rclone.org/). +💰 [PointCab GmbH](https://pointcab-software.com/) is providing finances for this project. + ## Features - **Two modes of operation:** @@ -15,6 +17,8 @@ A Docker-based proxy that exposes WebDAV storage as an S3-compatible interface u This proxy allows accessing WebDAV backends through the S3 protocol. As a developer of an app that can talk to S3 backends, you can access WebDAV servers through the S3 protocol without having to implement and maintain two protocols in your code. +**Note:** So far we have tested it with [ownCloud](https://github.com/owncloud/ocis) and [Nextcloud](https://github.com/nextcloud/server). + ## How It Works The proxy is based on [rclone](https://rclone.org/), a powerful tool for managing files on cloud storage. Rclone can serve storage over various protocols, including S3. @@ -32,11 +36,11 @@ docker build -t jankaritech/s3-webdav-proxy . ### Run the container ```bash -docker run --rm --network=host \ +docker run --rm -p 8080:8080 \ -e REMOTE_NAME= \ -e REMOTE_URL="https://your-webdav-server.com/" \ -e REMOTE_VENDOR= \ - -e PROXY_ARGS="--auth-proxy --auth-key , --no-check-certificate -vv" \ + -e PROXY_ARGS="--auth-proxy --auth-key , -vv" \ jankaritech/s3-webdav-proxy ``` @@ -44,7 +48,8 @@ The S3-compatible server will be available at `http://localhost:8080`. Access it > **Note:** > - `` is the **secret key** for SigV4 signature validation (format: `,`). -> - `--no-check-certificate` disables SSL verification. **Do not use in production** - use a valid certificate instead. +> - For development/testing with self-signed certificates, add `--no-check-certificate` to `PROXY_ARGS` to disable SSL verification. **Do not use in production** - use a valid certificate instead. +> - If you want to use a WebDAV server running on localhost, add `--network=host` to the docker run command. ## Configuration @@ -54,7 +59,7 @@ The S3-compatible server will be available at `http://localhost:8080`. Access it |-------------------|----------|----------------------------------------------------------------------------| | `REMOTE_NAME` | Yes | Name for the rclone remote (e.g., `ocis`) | | `REMOTE_URL` | Yes | WebDAV server URL | -| `REMOTE_VENDOR` | Yes | WebDAV vendor (`owncloud`, `nextcloud`, `webdav`, etc.) | +| `REMOTE_VENDOR` | Yes | WebDAV vendor (Tested vendors are nextcloud and owncloud.) | | `PROXY_ARGS` | No | Additional rclone arguments | | `AUTH_PROXY_PATH` | No | Path to custom auth-proxy script (default: `/usr/local/bin/auth-proxy.py`) | @@ -115,11 +120,10 @@ Omit `--auth-proxy` to enable anonymous access to a single static WebDAV remote. **1. Start the proxy:** ```bash -docker run --rm --network=host \ +docker run --rm -p 8080:8080 \ -e REMOTE_NAME= \ -e REMOTE_URL="https://your-server.com/" \ -e REMOTE_VENDOR= \ - -e PROXY_ARGS="--no-check-certificate" \ jankaritech/s3-webdav-proxy ``` @@ -144,7 +148,7 @@ The auth-proxy script enables dynamic backend configuration per request. You can Mount your custom script over the bundled one: ```bash -docker run --rm --network=host \ +docker run --rm -p 8080:8080 \ -e REMOTE_NAME= \ -e REMOTE_URL="https://your-server.com/" \ -e REMOTE_VENDOR= \ @@ -158,7 +162,7 @@ docker run --rm --network=host \ Use a custom path with `AUTH_PROXY_PATH`: ```bash -docker run --rm --network=host \ +docker run --rm -p 8080:8080 \ -e REMOTE_NAME= \ -e REMOTE_URL="https://your-server.com/" \ -e REMOTE_VENDOR= \ @@ -192,77 +196,58 @@ Example implementation (`auth-proxy.py`): See [docker/auth-proxy.py](docker/auth-proxy.py) for the complete example implementation. -## Example: OwnCloud OCIS Setup +## Example: Nextcloud Setup ### Prerequisites -1. Start OCIS server (ocis binary is used here for demonstration, but you can use your own OCIS setup): - ```bash - OCIS_LOG_LEVEL=debug IDM_CREATE_DEMO_USERS=true \ - OCIS_INSECURE=true ./ocis/bin/ocis server - ``` +1. Start Nextcloud server (or use your existing Nextcloud instance) -2. Get an access token from OCIS: +2. Get an access token from Nextcloud: - **Option A: Using browser (simplest)** - - Log in to OCIS web interface with your credentials - - Open browser DevTools (F12) → Network tab - - Make any request to OCIS - - Find the request with `Authorization: Bearer ` header - - Copy the bearer token - - **Option B: Using app-password (Nextcloud only)** + **Using app-password** - Go to Personal Settings → Security - Generate a new app password - Use the app password as your bearer token - **Option C: Using oauth2 (advanced)** - - Install oauth2 app in OCIS - - Create oauth2 client with redirect URL `http://localhost:9876/` - - Create a JSON file `oauth.json` with the client credentials: - ```json - { - "installed": { - "client_id": "", - "auth_uri": "/index.php/apps/oauth2/authorize", - "token_uri": "/index.php/apps/oauth2/api/v1/token", - "client_secret": "", - "redirect_uris": ["http://localhost:9876"] - } - } - ``` - - Use [oauth2l](https://github.com/google/oauth2l) to fetch token: - ```bash - ./oauth2l fetch --credentials oauth.json --scope all --refresh --output_format bare - ``` - -### Per-User Access +### Configuration + +- `REMOTE_NAME=nextcloud` +- `REMOTE_URL=https://your-nextcloud.com/remote.php/webdav` (for per-user access) +- `REMOTE_VENDOR=nextcloud` + +> **Note:** For per-user access, you can use the simpler `/remote.php/webdav` endpoint since authentication is handled by the auth-proxy. For anonymous public access, you must use `/public.php/dav/files//` format since the share token needs to be embedded in the URL. + +### Per-User Access Example ```bash -docker run --rm --network=host \ - -e REMOTE_NAME=ocis \ - -e REMOTE_URL="https://localhost:9200/remote.php/webdav" \ - -e REMOTE_VENDOR=owncloud \ - -e PROXY_ARGS="--auth-proxy --auth-key ,12345678 --no-check-certificate -vv" \ - jankaritech/s3-webdav-proxy +docker run --rm -p 8080:8080 \ + -e REMOTE_NAME=nextcloud \ + -e REMOTE_URL="https://your-nextcloud.com/remote.php/webdav" \ + -e REMOTE_VENDOR=nextcloud \ + -e PROXY_ARGS="--auth-proxy --auth-key , -vv" \ + jankari/rclone-webdav-proxy ``` ```bash -mc alias set myproxy http://localhost:8080 12345678 +mc alias set myproxy http://localhost:8080 mc ls myproxy ``` -### Anonymous Public Access +### Anonymous Public Access Example + +1. Create a public share in Nextcloud +2. Use the share token in the URL: -1. Create a public link in OCIS -2. Use the unique ID from the public link: + > **Note:** The share token is the part after `/s/` in your Nextcloud share link. + > For example, if your share link is `https://nextcloud.local/index.php/s/sXtwtoMdjcWwk85`, + > then your share token is `sXtwtoMdjcWwk85`. + > **Note:** For anonymous public access, the share token must be embedded in the URL using the `/public.php/dav/files//` format. This differs from per-user access which can use the simpler `/remote.php/webdav` endpoint. ```bash -docker run --rm --network=host \ - -e REMOTE_NAME=ocis \ - -e REMOTE_URL="https://localhost:9200/dav/public-files/A1b2C3d4E5f6G7h8I9j0" \ - -e REMOTE_VENDOR=owncloud \ - -e PROXY_ARGS="--no-check-certificate" \ +docker run --rm -p 8080:8080 \ + -e REMOTE_NAME=nextcloud \ + -e REMOTE_URL="https://your-nextcloud.com/public.php/dav/files//" \ + -e REMOTE_VENDOR=nextcloud \ jankaritech/s3-webdav-proxy ``` diff --git a/docker/auth-proxy.py b/docker/auth-proxy.py index a808a4c..8e38b13 100644 --- a/docker/auth-proxy.py +++ b/docker/auth-proxy.py @@ -25,6 +25,10 @@ def main(): "url": url, "vendor": vendor, } + # Disable chunked uploads for Nextcloud to avoid issues with /webdav endpoint + # Nextcloud chunked uploads require /dav/files/USER endpoint instead of /webdav + if vendor.lower() == "nextcloud": + o["nextcloud_chunk_size"] = "0" json.dump(o, sys.stdout, indent="\t")