├── Dockerfile ├── .github └── workflows │ └── docker.yml ├── entrypoint.sh └── README.md /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:bullseye-slim 2 | LABEL org.opencontainers.image.authors="Kyle Wilcox " \ 3 | org.opencontainers.image.url="https://github.com/axiom-data-science/rsync-server" 4 | ENV DEBIAN_FRONTEND noninteractive 5 | ENV LANG C.UTF-8 6 | ENV NOTVISIBLE "in users profile" 7 | 8 | RUN apt-get update && \ 9 | apt-get install -y --no-install-recommends openssh-server rsync && \ 10 | apt-get clean && \ 11 | mkdir /var/run/sshd && \ 12 | sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config && \ 13 | sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd && \ 14 | echo "export VISIBLE=now" >> /etc/profile && \ 15 | rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 16 | 17 | COPY entrypoint.sh /entrypoint.sh 18 | 19 | EXPOSE 22 20 | EXPOSE 873 21 | 22 | ENTRYPOINT ["/entrypoint.sh"] 23 | CMD ["rsync_server"] 24 | -------------------------------------------------------------------------------- /.github/workflows/docker.yml: -------------------------------------------------------------------------------- 1 | name: Docker 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | release: 8 | types: 9 | - published 10 | 11 | jobs: 12 | docker: 13 | 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | 18 | - name: Checkout 19 | uses: actions/checkout@v3 20 | 21 | - name: Docker meta 22 | id: meta 23 | uses: docker/metadata-action@v4 24 | with: 25 | images: | 26 | axiom/rsync-server 27 | tags: | 28 | type=raw,value=latest,enable=${{ github.ref_name == 'main' }} 29 | type=ref,event=branch,enable=${{ github.ref_name != 'main' }} 30 | type=ref,event=tag 31 | 32 | - name: Set up QEMU 33 | uses: docker/setup-qemu-action@v2 34 | 35 | - name: Set up Docker Buildx 36 | uses: docker/setup-buildx-action@v2 37 | 38 | - name: Login to Docker Hub 39 | if: success() && github.event_name != 'pull_request' 40 | uses: docker/login-action@v2 41 | with: 42 | username: ${{ secrets.DOCKERHUB_USERNAME }} 43 | password: ${{ secrets.DOCKERHUB_TOKEN }} 44 | 45 | - name: Build and push 46 | uses: docker/build-push-action@v4 47 | with: 48 | platforms: linux/amd64,linux/arm64 49 | push: ${{ github.event_name != 'pull_request' }} 50 | tags: ${{ steps.meta.outputs.tags }} 51 | labels: ${{ steps.meta.outputs.labels }} 52 | 53 | - name: Update repo description 54 | uses: peter-evans/dockerhub-description@v4 55 | with: 56 | username: ${{ secrets.DOCKERHUB_USERNAME }} 57 | password: ${{ secrets.DOCKERHUB_TOKEN }} 58 | repository: axiom/rsync-server 59 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | # AUTHORIZED_KEYS 4 | USERNAME=${USERNAME:-user} 5 | VOLUME=${VOLUME:-/data} 6 | PUID=${PUID:-root} 7 | GUID=${GUID:-root} 8 | DENY=${DENY:-"*"} 9 | ALLOW=${ALLOW:-10.0.0.0/8 192.168.0.0/16 172.16.0.0/12 127.0.0.1/32} 10 | RO=${RO:-false} 11 | # CUSTOMCONFIG 12 | 13 | # PASSWORD (required, specified directly with PASSWORD or via file contents with PASSWORD_FILE) 14 | if [ -n "$PASSWORD_FILE" ]; then 15 | if [ ! -f "$PASSWORD_FILE" ]; then 16 | echo "PASSWORD_FILE $PASSWORD_FILE doesn't exist" >&2 17 | exit 1 18 | fi 19 | PASSWORD=$(cat "$PASSWORD_FILE") 20 | fi 21 | if [ -z "$PASSWORD" ]; then 22 | echo "Must provide rsync password using env var PASSWORD or PASSWORD_FILE (path to file containing password)" >&2 23 | exit 1 24 | fi 25 | 26 | check_permissions(){ 27 | # Make sure target has uid 0, gid 0, and provided octal permissions 28 | TARGET_PATH="$1" 29 | TARGET_PERMISSIONS="$2" 30 | 31 | EXISTING_UID=$(stat -c "%u" "$TARGET_PATH") 32 | EXISTING_GID=$(stat -c "%g" "$TARGET_PATH") 33 | EXISTING_PERMISSIONS=$(stat -c "%a" "$TARGET_PATH") 34 | 35 | if [ "$EXISTING_UID" -ne "0" ] || [ "$EXISTING_GID" -ne "0" ]; then 36 | echo "$TARGET_PATH should have owner and group root, attempting chown" >&2 37 | chown root:root "$TARGET_PATH" 38 | fi 39 | 40 | if [ "$EXISTING_PERMISSIONS" -ne "$TARGET_PERMISSIONS" ]; then 41 | echo "$TARGET_PATH should have $TARGET_PERMISSIONS permissions (currently $EXISTING_PERMISSIONS), attempting chmod" >&2 42 | chmod "$TARGET_PERMISSIONS" "$TARGET_PATH" 43 | fi 44 | } 45 | 46 | setup_sshd(){ 47 | SSH_DIR="/root/.ssh" 48 | AUTH_KEYS_PATH="${SSH_DIR}/authorized_keys" 49 | 50 | if [ ! -d "$SSH_DIR" ]; then 51 | install -d -m 700 "$SSH_DIR" 52 | fi 53 | check_permissions "$SSH_DIR" "700" 54 | 55 | if [ ! -z "$AUTHORIZED_KEYS" ]; then 56 | install -m 400 <(echo "$AUTHORIZED_KEYS") "$AUTH_KEYS_PATH" 57 | fi 58 | if [ -e "$AUTH_KEYS_PATH" ]; then 59 | check_permissions "$AUTH_KEYS_PATH" "400" 60 | fi 61 | 62 | echo "root:$PASSWORD" | chpasswd 63 | } 64 | 65 | setup_rsyncd(){ 66 | echo "$USERNAME:$PASSWORD" > /etc/rsyncd.secrets 67 | chmod 0400 /etc/rsyncd.secrets 68 | [ -f /etc/rsyncd.conf ] || cat > /etc/rsyncd.conf <> /etc/rsyncd.conf 88 | fi 89 | } 90 | 91 | 92 | if [ "$1" = 'rsync_server' ]; then 93 | setup_sshd 94 | exec /usr/sbin/sshd & 95 | mkdir -p $VOLUME 96 | setup_rsyncd 97 | exec /usr/bin/rsync --no-detach --daemon --config /etc/rsyncd.conf "$@" 98 | else 99 | setup_sshd 100 | exec /usr/sbin/sshd & 101 | fi 102 | 103 | exec "$@" 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # THIS PROJECT IS UNMAINTAINED AND ARCHIVED. USE AT YOUR OWN RISK. 2 | 3 | # rsync-server 4 | 5 | A `rsyncd`/`sshd` server in Docker. You know, for moving files. 6 | 7 | ## Quickstart 8 | 9 | Start a server (both `sshd` and `rsyncd` are supported) 10 | 11 | ```shell 12 | docker run \ 13 | --name rsync-server \ 14 | -p 8000:873 \ 15 | -p 9000:22 \ 16 | -e USERNAME=user \ 17 | -e PASSWORD=someSecurePassword_NOT_THIS \ 18 | -v /your/public.key:/root/.ssh/authorized_keys \ 19 | axiom/rsync-server:latest 20 | ``` 21 | 22 | **You must set a password via `PASSWORD` or `PASSWORD_FILE`, even if you are using key authentication.** 23 | 24 | ### `rsyncd` 25 | 26 | Please note that `/volume` is the `rsync` volume pointing to `/data`. The data 27 | will be at `/data` in the container. Use the `VOLUME` parameter to change the 28 | destination path in the container. Even when changing `VOLUME`, you will still 29 | `rsync` to `/volume`. 30 | 31 | ```shell 32 | rsync -av /your/folder/ rsync://user@localhost:8000/volume 33 | Password: pass 34 | 35 | sending incremental file list 36 | ./ 37 | foo/ 38 | foo/bar/ 39 | foo/bar/hi.txt 40 | 41 | sent 166 bytes received 39 bytes 136.67 bytes/sec 42 | total size is 0 speedup is 0.00 43 | ``` 44 | 45 | ### `sshd` 46 | 47 | Please note that you are connecting as the `root` and not the user specified in 48 | the `USERNAME` variable. If you don't supply a key file you will be prompted 49 | for the `PASSWORD`. 50 | 51 | ```shell 52 | rsync -av -e "ssh -i /your/private.key -p 9000 -l root" /your/folder/ localhost:/data 53 | 54 | sending incremental file list 55 | ./ 56 | foo/ 57 | foo/bar/ 58 | foo/bar/hi.txt 59 | 60 | sent 166 bytes received 31 bytes 131.33 bytes/sec 61 | total size is 0 speedup is 0.00 62 | ``` 63 | 64 | ## Usage 65 | 66 | Variable options (on run) 67 | 68 | | Parameter | Function | 69 | | :---------------: | -------- | 70 | | `USERNAME` | the `rsync` username. defaults to `user`| 71 | | `PASSWORD` | the `rsync` password. **One of `PASSWORD` or `PASSWORD_FILE` is required.**| 72 | | `PASSWORD_FILE` | path to a file containing the `rsync` password. **One of `PASSWORD` or `PASSWORD_FILE` is required.**| 73 | | `AUTHORIZED_KEYS` | the `ssh` key (for root user). defaults empty | 74 | | `VOLUME` | the path for `rsync`. defaults to `/data`| 75 | | `PUID` | UserID used to transfer files when running the rsync . defaults to `root`| 76 | | `GUID` | GroupID used to transfer files when running the rsync . defaults to `root`| 77 | | `DENY` | space separated list of allowed sources. defaults to `*`| 78 | | `ALLOW` | space separated list of allowed sources. defaults to `10.0.0.0/8 192.168.0.0/16 172.16.0.0/12 127.0.0.1/32`.| 79 | | `RO` | `rsync` volume read only. defaults to `false`| 80 | | `CUSTOMCONFIG` | rsyncd.conf custom config for subsection volume (`\n\t` for new line ex: `uid = root\n\tgid = root`). defaults empty | 81 | 82 | ### Simple server on port 873 83 | 84 | ```shell 85 | docker run -p 873:873 -e PASSWORD=changeme axiom/rsync-server:latest 86 | ``` 87 | 88 | ### Use a volume for the default `/data` 89 | 90 | ```shell 91 | docker run -p 873:873 -e PASSWORD=seriouslychangeme -v /your/folder:/data axiom/rsync-server:latest 92 | ``` 93 | 94 | ### Set a username and password 95 | 96 | ```shell 97 | docker run \ 98 | -p 873:873 \ 99 | -v /your/folder:/data \ 100 | -e USERNAME=admin \ 101 | -e PASSWORD=imnotkidding \ 102 | axiom/rsync-server:latest 103 | ``` 104 | 105 | ### Set password via file 106 | 107 | ```shell 108 | docker run \ 109 | -p 873:873 \ 110 | -v /your/folder:/data \ 111 | -v ./password-file-with-secure-permissions:/etc/rsyncd/password:ro \ 112 | -e USERNAME=admin \ 113 | -e PASSWORD_FILE=/etc/rsyncd/password \ 114 | axiom/rsync-server:latest 115 | ``` 116 | 117 | ### Run on a custom port 118 | 119 | ```shell 120 | docker run \ 121 | -p 9999:873 \ 122 | -v /your/folder:/data \ 123 | -e USERNAME=admin \ 124 | -e PASSWORD=plzchng \ 125 | axiom/rsync-server:latest 126 | ``` 127 | 128 | ```shell 129 | rsync rsync://admin@localhost:9999 130 | 131 | volume /data directory 132 | ``` 133 | 134 | ### Modify the default volume location 135 | 136 | ```shell 137 | docker run \ 138 | -p 9999:873 \ 139 | -v /your/folder:/myvolume \ 140 | -e USERNAME=admin \ 141 | -e PASSWORD=yougetitnow \ 142 | -e VOLUME=/myvolume \ 143 | axiom/rsync-server:latest 144 | ``` 145 | 146 | ```shell 147 | rsync rsync://admin@localhost:9999 148 | 149 | volume /myvolume directory 150 | ``` 151 | 152 | ### Allow specific client IPs 153 | 154 | ```shell 155 | docker run \ 156 | -p 9999:873 \ 157 | -v /your/folder:/myvolume \ 158 | -e USERNAME=admin \ 159 | -e PASSWORD=hopesoanyway \ 160 | -e VOLUME=/myvolume \ 161 | -e ALLOW=192.168.24.0/24 \ 162 | axiom/rsync-server:latest 163 | ``` 164 | 165 | ### Over SSH 166 | 167 | If you would like to connect over ssh, you may mount your public key or 168 | `authorized_keys` file to `/root/.ssh/authorized_keys`. This file 169 | must have owner root, group root, and 400 octal permissions. 170 | 171 | Alternatively, you may specify the `AUTHORIZED_KEYS` environment variable. 172 | 173 | Without setting up an `authorized_keys` file, you will be propted for the 174 | password (which was specified in the `PASSWORD` variable). 175 | 176 | Please note that when using `sshd` **you will be specifying the actual folder 177 | destination as you would when using SSH.** On the contrary, when using the 178 | `rsyncd` daemon, you will always be using `/volume`, which maps to `VOLUME` 179 | inside of the container. 180 | 181 | ```shell 182 | docker run \ 183 | -v /your/folder:/myvolume \ 184 | -e USERNAME=admin \ 185 | -e PASSWORD=2manyp455w0rd5 \ 186 | -e VOLUME=/myvolume \ 187 | -e ALLOW=10.0.0.0/8 192.168.0.0/16 172.16.0.0/12 127.0.0.1/32 \ 188 | -v /my/authorized_keys:/root/.ssh/authorized_keys \ 189 | -p 9000:22 \ 190 | axiom/rsync-server:latest 191 | ``` 192 | 193 | ```shell 194 | rsync -av -e "ssh -i /your/private.key -p 9000 -l root" /your/folder/ localhost:/data 195 | ``` 196 | --------------------------------------------------------------------------------