18 Commits

Author SHA1 Message Date
d50d74505c Ignore .env* 2025-05-08 22:57:08 +02:00
8d310e4e59 Bump version to 2.1 2025-05-08 22:53:43 +02:00
d81f3fe81b Fix FTP_PASV_ADDRESS setting 2025-05-08 22:52:04 +02:00
b85c56d67e add compose project name 2025-05-06 22:41:34 +02:00
846f492187 update README 2025-05-06 22:30:26 +02:00
1345bbd50e update base image; add compose file 2025-05-06 22:15:57 +02:00
Andrew Cutler
19008464f4 dont always tag latest 2019-12-02 15:21:27 +11:00
Andrew Cutler
dcb7216288 update year 2019-12-02 15:21:20 +11:00
Tim Robinson
e6b8e74659 Update makefile to use with panubuild 2019-07-02 14:44:42 +10:00
Tim Robinson
d8edba35d2 Merge pull request #14 from yjpa7145/MakePasvAddressConfigurable
Add ability to set passive address
2019-07-01 20:47:47 +10:00
Marc Huffnagle
01184880cd Add ability to set passive address 2018-10-29 15:13:32 -04:00
Tim
cc1a8954ce Merge pull request #9 from panubo/update_to_stretch
Major update to stretch and many improvements
2018-05-02 12:11:33 +10:00
Tim Robinson
07b4a555ff Major update to stretch and many improvements
Improvements:
* Update to debian stretch
* Fix Dockerfile style
* Add FTP UID/GID Docker build args
* Add run-ssl to Makefile for testing SSL config
* Fix scripts style
* Fix scripts issues reported by shellcheck
* Add FTP_CHOWN_ROOT function to chown /srv in the container
* Add allow_writeable_chroot=YES to vsftpd_ssl.conf to match vsftpd.conf
* Update README.md
2018-05-01 22:01:08 +10:00
Tim
8140d6f5af Merge pull request #7 from panubo/makefile_default_user
Add default user to Makefile run and mount /srv externally
2018-05-01 16:48:37 +10:00
Tim
5ac7734d7f Merge pull request #3 from RichardBronosky/issue_2_fix
Fix https://github.com/panubo/docker-vsftpd/issues/2
2018-05-01 16:47:18 +10:00
Andrew Cutler
8fd338b0a3 Remove quay.io references, use full path to docker reg 2018-03-06 15:18:35 +11:00
Tim Robinson
d1ef03b7f6 Add default user to Makefile run and mount /srv externally 2017-07-29 13:09:39 +10:00
Bruno Bronosky
41fa3d7f07 Fix https://github.com/panubo/docker-vsftpd/issues/2
The combination of IFS and an unquoted Here String was causing `read` to
put both values into the first variable (name).
2017-07-14 01:36:37 -04:00
11 changed files with 201 additions and 76 deletions

7
.gitignore vendored Normal file
View File

@@ -0,0 +1,7 @@
*.swp
srv/
config/
logs/
data/
.env*
vsftpd.pem

View File

@@ -1,24 +1,36 @@
FROM debian:jessie FROM debian:stable
RUN groupadd -g 48 ftp && \ LABEL maintainer="Luca Derderian <luca@wululu.de>"
useradd --no-create-home --home-dir /srv -s /bin/false --uid 48 --gid 48 -c 'ftp daemon' ftp LABEL version="${VERSION:-2.1}"
RUN apt-get update \ ARG FTP_UID=48
&& apt-get install -y --no-install-recommends vsftpd db5.3-util whois \ ARG FTP_GID=48
&& apt-get clean \ RUN set -x \
&& rm -rf /var/lib/apt/lists/* && groupadd -g ${FTP_GID} ftp \
&& useradd --no-create-home --home-dir /srv -s /bin/false --uid ${FTP_UID} --gid ${FTP_GID} -c 'ftp daemon' ftp \
;
RUN mkdir -p /var/run/vsftpd/empty /etc/vsftpd/user_conf /var/ftp /srv && \ RUN set -x \
touch /var/log/vsftpd.log && \ && apt-get update \
rm -rf /srv/ftp && apt-get -y full-upgrade \
&& apt-get install -y --no-install-recommends vsftpd db-util whois gettext-base \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
;
COPY vsftpd*.conf /etc/ RUN set -x \
&& mkdir -p /var/run/vsftpd/empty /etc/vsftpd/user_conf /var/ftp /srv /templates \
&& touch /var/log/vsftpd.log \
&& rm -rf /srv/ftp \
;
COPY vsftpd*.conf /templates/
COPY vsftpd_virtual /etc/pam.d/ COPY vsftpd_virtual /etc/pam.d/
COPY *.sh / COPY *.sh /
VOLUME ["/etc/vsftpd", "/srv"] VOLUME ["/etc/vsftpd", "/srv"]
EXPOSE 21 4559 4560 4561 4562 4563 4564 EXPOSE 21
ENTRYPOINT ["/entry.sh"] ENTRYPOINT ["/entry.sh"]
CMD ["vsftpd"] CMD ["vsftpd"]

View File

@@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015 Volt Grid Pty Ltd Copyright (c) 2015-2019 Volt Grid Pty Ltd
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -19,4 +19,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.

View File

@@ -1,22 +1,43 @@
docker_tag = panubo/vsftpd NAME := vsftpd
TAG := latest
IMAGE_NAME := panubo/$(NAME)
UNAME_S := $(shell uname -s) .PHONY: build build-local bash run run-ssl help push clean
ifeq ($(UNAME_S),Linux) help:
APP_HOST := localhost @printf "$$(grep -hE '^\S+:.*##' $(MAKEFILE_LIST) | sed -e 's/:.*##\s*/:/' -e 's/^\(.\+\):\(.*\)/\\x1b[36m\1\\x1b[m:\2/' | column -c2 -t -s :)\n"
endif
ifeq ($(UNAME_S),Darwin)
APP_HOST := $(shell docker-machine ip default)
endif
build: build: ## Build for publishing
docker build -t $(docker_tag) . docker build --pull -t $(IMAGE_NAME):$(TAG) .
build-local: ## Builds with local users UID and GID
docker build --build-arg FTP_UID=$(shell id -u) --build-arg FTP_GID=$(shell id -g) -t $(IMAGE_NAME):$(TAG) .
bash: bash:
docker run --rm -it $(docker_tag) bash docker run --rm -it $(IMAGE_NAME):$(TAG) bash
run: env:
$(eval ID := $(shell docker run -d ${docker_tag})) @echo "FTP_USER=ftp" >> .env
@echo "FTP_PASSWORD=ftp" >> .env
vsftpd.pem:
openssl req -new -newkey rsa:2048 -days 365 -nodes -sha256 -x509 -keyout vsftpd.pem -out vsftpd.pem -subj '/CN=self_signed'
run: env
$(eval ID := $(shell docker run -d --env-file .env -v $(shell pwd)/srv:/srv ${IMAGE_NAME}:${TAG}))
$(eval IP := $(shell docker inspect --format '{{ .NetworkSettings.IPAddress }}' ${ID})) $(eval IP := $(shell docker inspect --format '{{ .NetworkSettings.IPAddress }}' ${ID}))
@echo "Running ${ID} @ ftp://${IP}" @echo "Running ${ID} @ ftp://${IP}"
@docker attach ${ID} @docker attach ${ID}
@docker kill ${ID} @docker kill ${ID}
run-ssl: env vsftpd.pem
$(eval ID := $(shell docker run -d --env-file .env -v $(shell pwd)/srv:/srv -v $(PWD)/vsftpd.pem:/etc/ssl/certs/vsftpd.crt -v $(PWD)/vsftpd.pem:/etc/ssl/private/vsftpd.key ${IMAGE_NAME}:${TAG} vsftpd /etc/vsftpd_ssl.conf))
$(eval IP := $(shell docker inspect --format '{{ .NetworkSettings.IPAddress }}' ${ID}))
@echo "Running ${ID} @ ftp://${IP}"
@docker attach ${ID}
@docker kill ${ID}
push: ## Pushes the docker image to hub.docker.com
docker push $(IMAGE_NAME):$(TAG)
clean: ## Remove built images
docker rmi $(IMAGE_NAME):$(TAG)

View File

@@ -1,38 +1,63 @@
# VSFTPD Docker Image # VSFTPD Docker Image
[![Docker Repository on Quay.io](https://quay.io/repository/panubo/vsftpd/status "Docker Repository on Quay.io")](https://quay.io/repository/panubo/vsftpd)
[![](https://badge.imagelayers.io/panubo/vsftpd:latest.svg)](https://imagelayers.io/?images=panubo/vsftpd:latest)
This is a micro-service image for VSFTPD. This is a micro-service image for VSFTPD.
It is a fork from [panubo's docker-vsftpd](https://github.com/panubo/docker-vsftpd) (thanks!) and slightly modified to suit my needs:
* Update base image to `debian:latest`
* Support for configurable min and max port in passive mode
by templating the config files (via envsubst)
There are a few limitations but it will work if you are using host networking There are a few limitations but it will work if you are using host networking
`--net host` or have a direct/routed network between the Docker container and `--net host` or have a direct/routed network between the Docker container and
the client. the client.
## Virtual User ## Virtual Users
The FTP user has been set to uid 48 and gid 48. This VSFTPD container uses virtual users. Each user that logs in will have the same system UID and GID. The real users has UID and GID of 48:48 by default, however using build-args this can be changed when building the container.
For example use `--build-arg FTP_UID=1000 --build-arg FTP_GID=1000` to set the UID and GID to 1000:1000.
## Options ## Options
The following environment variables are accepted. The following environment variables are accepted.
- `FTP_USER`: Sets the default FTP user - `FTP_USER`: Sets the default FTP user
- `FTP_PASSWORD`: Plain text password, or - `FTP_PASSWORD`: Plain text password (not recommended), or
- `FTP_PASSWORD_HASH`: Sets the password for the user specified above. This - `FTP_PASSWORD_HASH`: Sets the password for the user specified by `FTP_USER`. This
requires a hashed password such as the ones created with `mkpasswd -m sha-512` requires a hashed password such as the ones created with `mkpasswd -m sha-512`
which is in the _whois_ debian package. which is in the _whois_ debian package.
- `FTP_USER_*`: Adds mutliple users. Value must be in the form of `username:hash`. Should not be used in conjunction with `FTP_USER` and `FTP_PASSWORD(_HASH)`. - `FTP_USER_*`: Adds multiple users. Value must be in the form of `username:hash`. Should not be used in conjunction with `FTP_USER` and `FTP_PASSWORD(_HASH)`.
- `FTP_USERS_ROOT`: sets `local_root=/srv/$USER` so each user is chrooted to their own directory instead of a shared one. - `FTP_USERS_ROOT`: if set the vsftpd `local_root` will be set to `/srv/$USER` so each user is chrooted to their own directory instead of a shared one.
- `FTP_CHOWN_ROOT`: if set `chown` will be run against `/srv` setting the FTP user and group as owner and group of the directory. _Note: chown is run non-recursively ie. will only chown the root`_
- `FTP_PASV_ADDRESS`: override the IP address that vsftpd will advertise in
response to the PASV command
- `FTP_PASV_MIN_PORT`: Minimum port for passive mode (remember to bind the ports if not used with compose file)
- `FTP_PASV_MAX_PORT`: Maximum port for passive mode (remember to bind the ports if not used with compose file)
## Usage Example ## Usage Example
### Docker Compose
First, setup your .env file by copying the sample file and modifying it to suit your needs.
``` ```
docker run --rm -it -p 21:21 -p 4559:4559 -p 4560:4560 -p 4561:4561 -p 4562:4562 -p 4563:4563 -p 4564:4564 -e FTP_USER=panubo -e FTP_PASSWORD=panubo panubo/vsftpd cp env.sample .env
vi .env
```
Then run the stack
```
docker compose up -d
```
### Docker
```
docker run --rm -it -p 21:21 -p 4559-4564:4559-4564 -e FTP_USER=ftp -e FTP_PASSWORD=ftp docker.io/panubo/vsftpd:latest
``` ```
## SSL Usage ## SSL Usage
@@ -45,5 +70,19 @@ This example assumes the ssl cert and key are in the same file and are mounted
into the container read-only. into the container read-only.
``` ```
docker run --rm -it -e FTP_USER=panubo -e FTP_PASSWORD_HASH='$6$XWpu...DwK1' -v `pwd`/server.pem:/etc/ssl/certs/vsftpd.crt:ro -v `pwd`/server.pem:/etc/ssl/private/vsftpd.key:ro panubo/vsftpd vsftpd /etc/vsftpd_ssl.conf docker run --rm -it \
-e FTP_USER=panubo -e FTP_PASSWORD_HASH='$6$XWpu...DwK1' \
-v `pwd`/server.pem:/etc/ssl/certs/vsftpd.crt:ro \
-v `pwd`/server.pem:/etc/ssl/private/vsftpd.key:ro \
docker.io/panubo/vsftpd vsftpd /etc/vsftpd_ssl.conf
``` ```
## Security
Currently `allow_writeable_chroot` is turned ON, however this isn't recommended as a security precaution. We might look at making this configurable in the future. The main consequence of turning this off is that the `local_root` can not be writable by the FTP user.
See [serverfault: vsftp: whu is allow_writable_chroot=YES a bad idea?](https://serverfault.com/q/743949/259651)
## Logs
To get the FTP logs mount `/var/log` outside of the container. For example add `-v /var/log/ftp:/var/log` to your `docker run ...` command or use `docker compose`.

View File

@@ -1,23 +1,24 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Adds a virtual ftp user to /etc/vsftpd/virtual-users.db
set -e set -e
[ "$DEBUG" == 'true' ] && set -x [[ "${DEBUG}" == "true" ]] && set -x
DB=/etc/vsftpd/virtual-users.db DB="/etc/vsftpd/virtual-users.db"
if [ "$#" -lt 2 ] || [ "$#" -gt 3 ]; then if [[ "${#}" -lt 2 ]] || [[ "${#}" -gt 3 ]]; then
echo "Usage: $0 [-d] <user> <password>" >&2 echo "Usage: $0 [-d] <user> <password>" >&2
echo >&2 echo >&2
echo "[ -d ] Delete the database first" >&2 echo "[ -d ] Delete the database first" >&2
exit 1 exit 1
fi fi
if [ "$1" == "-d" ]; then if [[ "${1}" == "-d" ]]; then
if [ -f $DB ]; then if [[ -f "${DB}" ]]; then
rm $DB rm "${DB}"
fi fi
shift shift
fi fi
echo -e "$1\n$2" | db5.3_load -T -t hash $DB printf '%s\n%s\n' "${1}" "${2}" | db_load -T -t hash "${DB}"

16
compose.yml Normal file
View File

@@ -0,0 +1,16 @@
services:
vsftpd:
container_name: vsftpd
image: wululu/vsftpd:${VERSION:-2.1}
build:
context: .
args:
VERSION: ${VERSION:-2.1}
volumes:
- ./data:/srv
- ./config:/etc/vsftpd
- ./logs:/var/log
ports:
- "${FTP_PORT:-21}:21"
- "${FTP_PASV_MIN_PORT:-4559}-${FTP_PASV_MAX_PORT:-4564}:${FTP_PASV_MIN_PORT:-4559}-${FTP_PASV_MAX_PORT:-4564}"
env_file: .env

View File

@@ -1,34 +1,50 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# vsftpd container entrypoint script
set -e set -e
[ "$DEBUG" == 'true' ] && set -x [[ "${DEBUG}" == "true" ]] && set -x
# Replace variables in config files
for file in /templates/*; do
if [[ -f "$file" ]]; then
filename=$(basename "$file")
envsubst < "$file" > "/etc/$filename"
echo "Created /etc/${filename}"
fi
done
# Generate password if hash not set # Generate password if hash not set
if [ ! -z "$FTP_PASSWORD" -a -z "$FTP_PASSWORD_HASH" ]; then if [[ -n "${FTP_PASSWORD}" ]] && [[ -z "${FTP_PASSWORD_HASH}" ]]; then
FTP_PASSWORD_HASH=$(echo "$FTP_PASSWORD" | mkpasswd -s -m sha-512) FTP_PASSWORD_HASH="$(echo "${FTP_PASSWORD}" | mkpasswd -s -m sha-512)"
fi fi
if [ ! -z "$FTP_USER" -a ! -z "$FTP_PASSWORD_HASH" ]; then if [[ -n "${FTP_USER}" ]] || [[ -n "${FTP_PASSWORD_HASH}" ]]; then
/add-virtual-user.sh -d "$FTP_USER" "$FTP_PASSWORD_HASH" /add-virtual-user.sh -d "${FTP_USER}" "${FTP_PASSWORD_HASH}"
fi fi
# Support multiple users # Support multiple users
while read user; do while read -r user; do
IFS=: read name pass <<< ${!user} IFS=: read -r name pass <<< "${!user}"
echo "Adding user $name" echo "Adding user ${name}"
/add-virtual-user.sh "$name" "$pass" /add-virtual-user.sh "${name}" "${pass}"
done < <(env | grep "FTP_USER_" | sed 's/^\(FTP_USER_[a-zA-Z0-9]*\)=.*/\1/') done < <(env | grep "FTP_USER_" | sed 's/^\(FTP_USER_[a-zA-Z0-9]*\)=.*/\1/')
# Support user directories # Support user directories
if [ ! -z "$FTP_USERS_ROOT" ]; then if [[ -n "${FTP_USERS_ROOT}" ]]; then
sed -i 's/local_root=.*/local_root=\/srv\/$USER/' /etc/vsftpd*.conf # shellcheck disable=SC2016
sed -i 's/local_root=.*/local_root=\/srv\/$USER/' /etc/vsftpd*.conf
fi fi
function vsftpd_stop { # Manage /srv permissions
if [[ -n "${FTP_CHOWN_ROOT}" ]]; then
chown ftp:ftp /srv
fi
vsftpd_stop() {
echo "Received SIGINT or SIGTERM. Shutting down vsftpd" echo "Received SIGINT or SIGTERM. Shutting down vsftpd"
# Get PID # Get PID
pid=$(cat /var/run/vsftpd/vsftpd.pid) pid="$(cat /var/run/vsftpd/vsftpd.pid)"
# Set TERM # Set TERM
kill -SIGTERM "${pid}" kill -SIGTERM "${pid}"
# Wait for exit # Wait for exit
@@ -37,13 +53,13 @@ function vsftpd_stop {
echo "Done" echo "Done"
} }
if [ "$1" == "vsftpd" ]; then if [[ "${1}" == "vsftpd" ]]; then
trap vsftpd_stop SIGINT SIGTERM trap vsftpd_stop SIGINT SIGTERM
echo "Running $@" echo "Running ${*}"
$@ & "${@}" &
pid="$!" pid="${!}"
echo "${pid}" > /var/run/vsftpd/vsftpd.pid echo "${pid}" > /var/run/vsftpd/vsftpd.pid
wait "${pid}" && exit $? wait "${pid}" && exit ${?}
else else
exec "$@" exec "${@}"
fi fi

11
env.sample Normal file
View File

@@ -0,0 +1,11 @@
COMPOSE_PROJECT_NAME=vsftpd
VERSION=2.1
FTP_USER=
FTP_PASSWORD=
FTP_PORT=
FTP_PASV_ADDRESS=
FTP_PASV_MIN_PORT=
FTP_PASV_MAX_PORT=

View File

@@ -34,5 +34,6 @@ hide_ids=YES
connect_from_port_20=YES connect_from_port_20=YES
listen=YES listen=YES
tcp_wrappers=YES tcp_wrappers=YES
pasv_min_port=4559 pasv_address=${FTP_PASV_ADDRESS}
pasv_max_port=4564 pasv_min_port=${FTP_PASV_MIN_PORT}
pasv_max_port=${FTP_PASV_MAX_PORT}

View File

@@ -15,6 +15,7 @@ user_sub_token=$USER
#local_root=/srv/$USER #local_root=/srv/$USER
local_root=/srv/ local_root=/srv/
userlist_enable=NO userlist_enable=NO
allow_writeable_chroot=YES
# Logging # Logging
log_ftp_protocol=YES log_ftp_protocol=YES
@@ -33,8 +34,9 @@ hide_ids=YES
connect_from_port_20=YES connect_from_port_20=YES
listen=YES listen=YES
tcp_wrappers=YES tcp_wrappers=YES
pasv_min_port=4559 pasv_address=${FTP_PASV_ADDRESS}
pasv_max_port=4564 pasv_min_port=${FTP_PASV_MIN_PORT}
pasv_max_port=${FTP_PASV_MAX_PORT}
# SSL # SSL
ssl_enable=Yes ssl_enable=Yes