├── .travis.yml ├── run.sh ├── LICENSE ├── Makefile ├── Dockerfile └── README.md /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | 3 | services: 4 | - docker 5 | 6 | before_install: 7 | - make build 8 | - make run 9 | - docker ps -a 10 | - make setup-bob 11 | 12 | script: 13 | - make test-bob 14 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # build up flags passed to this file on run + env flag for additional flags 4 | # e.g. -e "ADDED_FLAGS=--tls=2" 5 | PURE_FTPD_FLAGS="$@ $ADDED_FLAGS " 6 | 7 | # start rsyslog 8 | if [[ "$PURE_FTPD_FLAGS" == *" -d "* ]] || [[ "$PURE_FTPD_FLAGS" == *"--verboselog"* ]] 9 | then 10 | echo "Log enabled, see /var/log/messages" 11 | rsyslogd 12 | fi 13 | 14 | # Load in any existing db from volume store 15 | if [ -e /etc/pure-ftpd/passwd/pureftpd.passwd ] 16 | then 17 | pure-pw mkdb /etc/pure-ftpd/pureftpd.pdb -f /etc/pure-ftpd/passwd/pureftpd.passwd 18 | fi 19 | 20 | # detect if using TLS (from volumed in file) but no flag set, set one 21 | if [ -e /etc/ssl/private/pure-ftpd.pem ] && [[ "$PURE_FTPD_FLAGS" != *"--tls"* ]] 22 | then 23 | echo "TLS Enabled" 24 | PURE_FTPD_FLAGS="$PURE_FTPD_FLAGS --tls=1 " 25 | fi 26 | 27 | # let users know what flags we've ended with (useful for debug) 28 | echo "Starting Pure-FTPd:" 29 | echo " pure-ftpd $PURE_FTPD_FLAGS" 30 | 31 | # start pureftpd with requested flags 32 | exec /usr/sbin/pure-ftpd $PURE_FTPD_FLAGS 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Andrew Stilliard 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: build run kill enter setup-bob test-bob push pull 2 | 3 | build: 4 | sudo docker build --rm -t pure-ftp-demo . 5 | 6 | run: kill 7 | sudo docker run -d --name ftpd_server -p 21:21 -p 30000-30009:30000-30009 -e "PUBLICHOST=localhost" -e "ADDED_FLAGS=-d -d" pure-ftp-demo 8 | 9 | kill: 10 | -sudo docker kill ftpd_server 11 | -sudo docker rm ftpd_server 12 | 13 | enter: 14 | sudo docker exec -it ftpd_server sh -c "export TERM=xterm && bash" 15 | 16 | # Setup test "bob" user with "test" as password 17 | setup-bob: 18 | sudo docker exec -it ftpd_server sh -c "(echo test; echo test) | pure-pw useradd bob -f /etc/pure-ftpd/passwd/pureftpd.passwd -m -u ftpuser -d /home/ftpusers/bob" 19 | @echo "User bob setup with password: test" 20 | 21 | # simple test to list files, upload a file, download it to a new name, delete it via ftp and read the new local one to make sure it's in tact 22 | test-bob: 23 | echo "Test file was read successfully!" > test-orig-file.txt 24 | echo "user bob test\n\ 25 | ls -alh\n\ 26 | put test-orig-file.txt\n\ 27 | ls -alh\n\ 28 | get test-orig-file.txt test-new-file.txt\n\ 29 | delete test-orig-file.txt\n\ 30 | ls -alh" | ftp -n -v -p localhost 21 31 | cat test-new-file.txt 32 | rm test-orig-file.txt test-new-file.txt 33 | 34 | 35 | # git commands for quick chaining of make commands 36 | push: 37 | git push --all 38 | git push --tags 39 | 40 | pull: 41 | git pull 42 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | FROM debian:jessie 3 | 4 | # feel free to change this ;) 5 | MAINTAINER Andrew Stilliard 6 | 7 | # properly setup debian sources 8 | ENV DEBIAN_FRONTEND noninteractive 9 | RUN echo "deb http://http.debian.net/debian jessie main\n\ 10 | deb-src http://http.debian.net/debian jessie main\n\ 11 | deb http://http.debian.net/debian jessie-updates main\n\ 12 | deb-src http://http.debian.net/debian jessie-updates main\n\ 13 | deb http://security.debian.org jessie/updates main\n\ 14 | deb-src http://security.debian.org jessie/updates main\n\ 15 | " > /etc/apt/sources.list 16 | RUN apt-get -y update 17 | 18 | # install package building helpers 19 | RUN apt-get -y --force-yes --fix-missing install dpkg-dev debhelper 20 | 21 | # install dependancies 22 | RUN apt-get -y build-dep pure-ftpd 23 | 24 | # build from source 25 | RUN mkdir /tmp/pure-ftpd/ && \ 26 | cd /tmp/pure-ftpd/ && \ 27 | apt-get source pure-ftpd && \ 28 | cd pure-ftpd-* && \ 29 | ./configure --with-tls && \ 30 | sed -i '/^optflags=/ s/$/ --without-capabilities/g' ./debian/rules && \ 31 | dpkg-buildpackage -b -uc 32 | 33 | # install the new deb files 34 | RUN dpkg -i /tmp/pure-ftpd/pure-ftpd-common*.deb 35 | RUN apt-get -y install openbsd-inetd 36 | RUN dpkg -i /tmp/pure-ftpd/pure-ftpd_*.deb 37 | 38 | # Prevent pure-ftpd upgrading 39 | RUN apt-mark hold pure-ftpd pure-ftpd-common 40 | 41 | # setup ftpgroup and ftpuser 42 | RUN groupadd ftpgroup 43 | RUN useradd -g ftpgroup -d /home/ftpusers -s /dev/null ftpuser 44 | 45 | # rsyslog for logging (ref https://github.com/stilliard/docker-pure-ftpd/issues/17) 46 | RUN apt-get install -y rsyslog && \ 47 | echo "" >> /etc/rsyslog.conf && \ 48 | echo "#PureFTP Custom Logging" >> /etc/rsyslog.conf && \ 49 | echo "ftp.* /var/log/pure-ftpd/pureftpd.log" >> /etc/rsyslog.conf && \ 50 | echo "Updated /etc/rsyslog.conf with /var/log/pure-ftpd/pureftpd.log" 51 | 52 | # setup run/init file 53 | COPY run.sh /run.sh 54 | RUN chmod u+x /run.sh 55 | 56 | # default publichost, you'll need to set this for passive support 57 | ENV PUBLICHOST localhost 58 | 59 | # couple available volumes you may want to use 60 | VOLUME ["/home/ftpusers", "/etc/pure-ftpd/passwd"] 61 | 62 | # startup 63 | CMD /run.sh -c 5 -C 5 -l puredb:/etc/pure-ftpd/pureftpd.pdb -E -j -R -P $PUBLICHOST -p 30000:30009 64 | 65 | EXPOSE 21 30000-30009 66 | 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Docker Pure-ftpd Server 3 | ============================ 4 | https://hub.docker.com/r/stilliard/pure-ftpd/ 5 | 6 | [![Build Status](https://travis-ci.org/stilliard/docker-pure-ftpd.svg?branch=master)](https://travis-ci.org/stilliard/docker-pure-ftpd) 7 | [![Docker Build Status](https://img.shields.io/docker/build/stilliard/pure-ftpd.svg)](https://hub.docker.com/r/stilliard/pure-ftpd/) 8 | [![Docker Pulls](https://img.shields.io/docker/pulls/stilliard/pure-ftpd.svg)](https://hub.docker.com/r/stilliard/pure-ftpd/) 9 | 10 | Pull down with docker: 11 | ```bash 12 | docker pull stilliard/pure-ftpd:hardened 13 | ``` 14 | 15 | **Often needing to run as `sudo`, e.g. `sudo docker pull stilliard/pure-ftpd`** 16 | 17 | ---------------------------------------- 18 | 19 | **My advice is to extend this image to make any changes.** 20 | This is because rebuilding the entire docker image via a fork can be slow as it rebuilds the entire pure-ftpd package from source. 21 | 22 | Instead you can create a new project with a `DOCKERFILE` like so: 23 | 24 | ``` 25 | FROM stilliard/pure-ftpd 26 | 27 | # e.g. you could change the defult command run: 28 | CMD /run.sh -c 30 -C 10 -l puredb:/etc/pure-ftpd/pureftpd.pdb -E -j -R -P $PUBLICHOST -p 30000:30059 29 | ``` 30 | 31 | *Then you can build your own image, `docker build --rm -t my-pure-ftp .`, where my-pure-ftp is the name you want to build as* 32 | 33 | ---------------------------------------- 34 | 35 | Starting it 36 | ------------------------------ 37 | 38 | `docker run -d --name ftpd_server -p 21:21 -p 30000-30009:30000-30009 -e "PUBLICHOST=localhost" stilliard/pure-ftpd:hardened` 39 | 40 | *Or for your own image, replace stilliard/pure-ftpd with the name you built it with, e.g. my-pure-ftp* 41 | 42 | You can also pass ADDED_FLAGS as an env variable to add additional options such as --tls to the pure-ftpd command. 43 | e.g. ` -e "ADDED_FLAGS=--tls=2" ` 44 | 45 | 46 | Operating it 47 | ------------------------------ 48 | 49 | `docker exec -it ftpd_server /bin/bash` 50 | 51 | Example usage once inside 52 | ------------------------------ 53 | 54 | Create an ftp user: `e.g. bob with chroot access only to /home/ftpusers/bob` 55 | ```bash 56 | pure-pw useradd bob -f /etc/pure-ftpd/passwd/pureftpd.passwd -m -u ftpuser -d /home/ftpusers/bob 57 | ``` 58 | *No restart should be needed.* 59 | 60 | *If you have any trouble with volume permissions due to the **uid** or **gid** of the created user you can change the **-u** flag for the uid you would like to use and/or specify **-g** with the group id as well. For more information see issue [#35](https://github.com/stilliard/docker-pure-ftpd/issues/35#issuecomment-325583705).* 61 | 62 | More info on usage here: https://download.pureftpd.org/pure-ftpd/doc/README.Virtual-Users 63 | 64 | 65 | Test your connection 66 | ------------------------- 67 | From the host machine: 68 | ```bash 69 | ftp -p localhost 21 70 | ``` 71 | 72 | Max clients 73 | ------------------------- 74 | By default we set 5 max clients at once, but you can increase this by increasing `-c 5`, e.g. to `-c 50` and then also increasing the number of public ports opened from `-p 30000:30009` `-p 30000:30099`. You'll also want to open those ports when running docker run. 75 | 76 | 77 | Logs 78 | ------------------------- 79 | To get verbose logs add the following to your `docker run` command: 80 | ``` 81 | -e "ADDED_FLAGS=-d -d" 82 | ``` 83 | 84 | Then if you exec into the container you could watch over the log with `tail -f /var/log/messages` 85 | 86 | Want a transfer log file? add the following to your `docker run` command: 87 | ```bash 88 | -e "ADDED_FLAGS=-O w3c:/var/log/pure-ftpd/transfer.log" 89 | ``` 90 | 91 | ---------------------------------------- 92 | 93 | Tags available for different versions 94 | -------------------------------------- 95 | 96 | **Latest versions** 97 | 98 | - `latest` - latest working version 99 | - `jessie-latest` - latest but will always remain on debian jessie 100 | - `hardened` - latest + [more secure/hardened defaults](https://github.com/stilliard/docker-pure-ftpd/issues/10) 101 | 102 | **Previous version before tags were introduced** 103 | 104 | - `wheezy-1.0.36` - incase you want to roll back to before we started using debian jessie 105 | 106 | **Specific pure-ftpd versions** 107 | 108 | - `jessie-1.x.x` - jessie + specific versions, e.g. jessie-1.0.36 109 | - `hardened-1.x.x` - hardened + specific versions 110 | 111 | *Check the tags on github for available versions, feel free to submit issues and/or pull requests for newer versions* 112 | 113 | Usage of specific tags: 114 | `sudo docker pull stilliard/pure-ftpd:hardened-1.0.36` 115 | 116 | ---------------------------------------- 117 | 118 | Our default pure-ftpd options explained 119 | ---------------------------------------- 120 | 121 | ``` 122 | /usr/sbin/pure-ftpd # path to pure-ftpd executable 123 | -c 5 # --maxclientsnumber (no more than 5 people at once) 124 | -C 5 # --maxclientsperip (no more than 5 requests from the same ip) 125 | -l puredb:/etc/pure-ftpd/pureftpd.pdb # --login (login file for virtual users) 126 | -E # --noanonymous (only real users) 127 | -j # --createhomedir (auto create home directory if it doesnt already exist) 128 | -R # --nochmod (prevent usage of the CHMOD command) 129 | -P $PUBLICHOST # IP/Host setting for PASV support, passed in your the PUBLICHOST env var 130 | -p 30000:30009 # PASV port range (10 ports for 5 max clients) 131 | -tls 1 # Enables optional TLS support 132 | ``` 133 | 134 | For more information please see `man pure-ftpd`, or visit: https://www.pureftpd.org/ 135 | 136 | Why so many ports opened? 137 | --------------------------- 138 | This is for PASV support, please see: [#5 PASV not fun :)](https://github.com/stilliard/docker-pure-ftpd/issues/5) 139 | 140 | ---------------------------------------- 141 | 142 | Docker Volumes 143 | -------------- 144 | There are a few spots onto which you can mount a docker volume to configure the 145 | server and persist uploaded data. It's recommended to use them in production. 146 | 147 | - `/home/ftpusers/` The ftp's data volume (by convention). 148 | - `/etc/pure-ftpd/passwd` A directory containing the single `pureftps.passwd` 149 | file which contains the user database (i.e., all virtual users, their 150 | passwords and their home directories). This is read on startup of the 151 | container and updated by the `pure-pw useradd -f /etc/pure- 152 | ftpd/passwd/pureftpd.passwd ...` command. 153 | - `/etc/ssl/private/` A directory containing a single `pure-ftpd.pem` file 154 | with the server's SSL certificates for TLS support. Optional TLS is 155 | automatically enabled when the container finds this file on startup. 156 | 157 | Keep user database in a volume 158 | ------------------------------ 159 | You may want to keep your user database through the successive image builds. It is possible with Docker volumes. 160 | 161 | Create a named volume: 162 | ``` 163 | docker volume create --name my-db-volume 164 | ``` 165 | 166 | Specify it when running the container: 167 | ``` 168 | docker run -d --name ftpd_server -p 21:21 -p 30000-30009:30000-30009 -e "PUBLICHOST=localhost" -v my-db-volume:/etc/pure-ftpd/passwd stilliard/pure-ftpd:hardened 169 | ``` 170 | 171 | When an user is added, you need to use the password file which is in the volume: 172 | ``` 173 | pure-pw useradd bob -f /etc/pure-ftpd/passwd/pureftpd.passwd -m -u ftpuser -d /home/ftpusers/bob 174 | ``` 175 | (Thanks to the -m option, you don't need to call *pure-pw mkdb* with this syntax). 176 | 177 | 178 | Changing a password 179 | --------------------- 180 | e.g. to change the password for user "bob": 181 | ``` 182 | pure-pw passwd bob -f /etc/pure-ftpd/passwd/pureftpd.passwd -m 183 | ``` 184 | 185 | ---------------------------------------- 186 | Development (via git clone) 187 | ```bash 188 | # Clone the repo 189 | git clone https://github.com/stilliard/docker-pure-ftpd.git 190 | cd docker-pure-ftpd 191 | # Build the image 192 | make build 193 | # Run container in background: 194 | make run 195 | # enter a bash shell insdie the container: 196 | make enter 197 | ``` 198 | 199 | TLS 200 | ---- 201 | 202 | If you want to enable tls (for ftps connections), you need to have a valid 203 | certificate. You can get one from one of the certificate authorities that you'll 204 | find when googling this topic. The certificate (containing private key and 205 | certificate) needs to be at: 206 | 207 | ``` 208 | /etc/ssl/private/pure-ftpd.pem 209 | ``` 210 | 211 | Use docker volumes to get the certificate there at runtime. The container will 212 | automatically enable optional TLS when it detect the file at this location. 213 | 214 | You can also self-sign a certificate, which is certainly the easiest way to 215 | start out. Self signed certificates come with certain drawbacks, but it might 216 | be better to have a self signed one than none at all. 217 | 218 | Here's how to create a self-signed certificate from within the container: 219 | 220 | ```bash 221 | mkdir -p /etc/ssl/private 222 | openssl dhparam -out /etc/ssl/private/pure-ftpd-dhparams.pem 2048 223 | openssl req -x509 -nodes -newkey rsa:2048 -sha256 -keyout \ 224 | /etc/ssl/private/pure-ftpd.pem \ 225 | -out /etc/ssl/private/pure-ftpd.pem 226 | chmod 600 /etc/ssl/private/*.pem 227 | ``` 228 | 229 | 230 | Credits 231 | ------------- 232 | Thanks for the help on stackoverflow with this! 233 | https://stackoverflow.com/questions/23930167/installing-pure-ftpd-in-docker-debian-wheezy-error-421 234 | 235 | --------------------------------------------------------------------------------