proftpd-docker

Requirements

  • docker
  • (docker-compose)
  • PostgreSQL instance
  • Creating the necessary tables on the PostgreSQL instance using the included migration: sql/proftp_tables.sql.
  • openssl (for creating passwords)

Running with docker-compose, building image

  • Create a .env containing the requirements environnement variables

This file should be located next to the provided docker-compose.yml file. The .env.tpl file can be used to bootstrap the .env file.

The required/optional parameters are described here after:

  • FTP_DB_HOST: db hostname or ip address, required
  • FTP_DB_NAME: db name, required
  • FTP_DB_USER: db user, required
  • FTP_DB_PASS: db password, required
  • FTP_DB_ADMIN: db admin user, required if FTP_PG_MIGRATE=ON
  • FTP_DB_ADMIN_PASS: db admin password, required if FTP_PG_MIGRATE=ON
  • FTP_PG_MIGRATE: ON/OFF, activate/deactivate automatic creation of tables required by proftpd in postgresql database
  • FTP_VERBOSE: ON/UNDEF, activate/deactivate logging to files
  • FTP_ROOT: /path/to/ftp/root, optional, defaults to /data/ftp_root
  • LOGS: /path/to/log/dir, optional, defaults to /var/log/proftpd
  • SALT: /path/to/salt/file, optional, defaults to ./.salt
  • MOD_TLS: ON/OFF, activate/deactivate module mod_tls, optional, defaults to OFF
  • MOD_TLS_CONF: /path/to/mod_tls.conf, optional, defaults to included tls.conf
  • CERTS: /path/to/tls/certs/dir, optional, defaults to ./certs
  • MOD_EXEC: ON/OFF, activate/deactivate module mod_exec, optional, defaults to OFF
  • MOD_EXEC_DIR: /path/to/mod/exec/dir, optional, defaults to ./exec
  • MOD_VROOT: ON/OFF, activate/desactivate module_vroot, optional, default to OFF
  • MOD_VROOT_CONF: /path/to/mod_vroot.conf, optional, defaults to included vroot.conf
  • Build and run the container as follows:
docker-compose build
docker-compose up -d

Configuring postgreSQL connection

Refer to this link and on sql/proftpd_tables.sql file for detailed information on required SQL data model.

The migration should be run by a user with owner privilege on the designated database. The script supposes a second user exists beforehand, whose privileges are managed by the migration.

The FTP_DB_HOST, FTP_DB_NAME, FTP_DB_USER and FTP_DB_PASS env vars should be provided to the container to configure proftpd's connection with the postgreSQL instance.

Automatic migration

Env vars FTP_DB_ADMIN and FTP_DB_ADMIN_PASS can also be provided combined with option FTP_PG_MIGRATE=ON to automatically create the tables required by proftpd in the postgreSQL database.

Create users and groups

First create a group, or make sure an appropriate group already exists. The main attributes for groups are:

  • groupname (unique)
  • gid (unique, in [999-65533] as per the server config)
INSERT INTO ftp.groups
(groupname, gid)
VALUES('users', 999);

Then create the user. The required attributes are:

  • userid (unique)
  • passwd (salted sh256/512 hash, covered in next section)
  • uid (unique, in [999-65533] as per the server config)
  • gid (referencing an existing group id)
  • home (absolute path to user's home /srv/ftp/... , created at first connection if required)
INSERT INTO ftp.users
(userid, passwd, uid, gid, homedir)
VALUES('JonDoe', 'am4Q3ukBh...QXg2UeRms=', 999, 999, '/srv/ftp/homes/jon_doe');

User's passwords

Passwords are stored in the db as salted SHA256/512 digests, in hex64 encoding.

A random crypto string, known as salt, is used to mitigate dictionnary attacks and should be provided to the ftp server using the SALT env var.

The SALT env var let you define the path to a salt file mounted as a bound volume in the docker container. By default the container will look at a .salt file stored along the Dockerfile.

To generate an encrypted password use the following command:

{ echo -n myPassword; echo -n $(cat .salt); } | openssl dgst -binary -sha256 | openssl enc -base64 -A

where .salt is a file containing the salt.

The helper script genpass.sh is also provided in this distribution: The usage is as follows:

package -s path/to/salt password

Server address masquerading

The server can be instructed to send back to the client a specified IP address, or hostname. This is useful when dealing with NAT gateways, or boad balancers where passive mode is required.

The env var MASQ_ADDR can be set to either a given IP address or hostame, or to the value AWS in which case the server the server public ip will be automatically retrieved (if available) from AWS EC2 instance's metadata to set the env var.

Configuring ftp root directory

The ftp root (home for all user's directories) can be configured using the FTP_ROOT env variable. Otherwise it default to the directory /data/ftp_root of the docker's host.

Configuring proftpd logs directory

When setting verbose mode ON with env var FTP_VERBOSE, the log directory can be configured using the LOGS env variable. Otherwise it default to the directory /var/log/proftpd of the docker's host.

Module mod_tls

When enabling the module with env var MOD_TLS=ON, a module configuration file and associated certificates should be provided as binded volumes. Default included configuration expects a self-signed TLS certificate proftpd.cert.pem and it's key file proftpd.key.pem.

A custom mod_tls configuration can be provided as a bound volume whose path is defined by the MOD_TLS_CONF env var.

Certificates should be stored in a directory accessible by the docker image, whose path is to be provided as the CERTS env var.

Module mod_exec

When enabling the module with env var MOD_EXEC=ON, a exec.conf file containing the module configuration should be provided, as per the module's documentation.

This file should be stored in a directory accessible by the docker image, whose path is to be provided as the MOD_EXEC_CONF env var.

Module mod_vroot

When enabling the module with env var MOD_VROOT=ON, a vroot.conf file containing the module configuration should be provided, as per the module's documentation

This file can be provided as a bound volume whose path is defined by the MOD_VROOT_CONF env var.

Running with docker-compose, pulling image from docker hub

With docker-compose-image.yml an example is provided on how to integrate the proftpd-docker image hosted on docker hub inside a larger set-up, orchestrated with docker-compose.

Literally the main point is to declare the volume attachments inside the docker-compose.yml file as in:

volumes:
  - type: bind
    source: "${LOGS:-/var/log/proftpd}"
    target: /var/log/proftpd

The example relies on bound volumes but again any kind of volume you do.

Just mind:

  • covering all required volumes as described in the Running with docker section,
  • exposing any required port (or dropping network_mode: host)
  • passing the env vars (with env_file or environment directive, or plain env vars)

when ok, run docker-compose -f docker-compose-image.yml run ...and you're all set!

Running with docker

Following the previous sections, a number a env vars and volumes needs to be specified right to the cli when running the server with docker:

  • Env vars:
    • FTP_DB_HOST
    • FTP_DB_NAME
    • FTP_DB_USER
    • FTP_DB_PASS
    • FTP_DB_ADMIN
    • FTP_DB_ADMIN_PASS
    • FTP_PG_MIGRATE
    • FTP_VERBOSE
    • MASQ_ADDR
    • MOD_TLS
    • MOD_EXEC
    • MOD_VROOT
  • Volumes:
    • /srv/ftp (ftp root containing users' homes)
    • /var/log/proftpd (server's logs)
    • /etc/proftpd/.salt (.salt file)
    • /etc/proftpd/tls.conf (mod_tls config file)
    • /etc/proftpd/certs (dir containing server's certificates)
    • /etc/proftpd/exec (dir containing server's mod_exec conf and scripts)
    • /etc/proftpd/vroot.conf (mod_vroot config file)

The following docker run example assumes bound volumes, but the anykind of docker volume config can be used.

  • Build image:
docker build -t proftpd .
  • Start container and provide the necessary env vars and volume information:
docker run --name proftpd --net=host \
  -e FTP_DB_HOST=mydb.com -e FTP_DB_NAME=db_name -e FTP_DB_USER=db_user -e FTP_DB_PASS=db_password \
  -e MASQ_ADDR:AWS \
  -v /data/ftp_root:/srv/ftp \
  -v /var/log/proftpd:/var/log/proftpd \
  -v $(pwd)/.salt:/etc/proftpd/.salt \
  -e MOD_TLS=ON \
  -v $(pwd)/tls.conf:/etc/proftpd/tls.conf \
  -v $(pwd)/certs:/etc/proftpd/certs \
  -e MOD_EXEC=ON \
  -v $(pwd)/exec:/etc/proftpd/exec \
  -e MOD_VROOT=ON \
  -v $(pwd)/vroot.conf:/etc/proftpd/vroot.conf
	-d proftpd

Note: a Makefile is also provided in the repository to help testing the docker run syntax. The Makefile contains a special function make env_run leveraging the exact same .env file expected by docker-compose. Just make sure the .env file is located right next to the Makefile to make it work.

Testing with curl

  • Listing files:
curl -v --ssl --insecure --disable-epsv ftp://my-ftp-server.com:21 -u user:pwd
  • Uploading files:
curl -v -T </path/to/file> --ssl --insecure --disable-epsv ftp://my-ftp-server.com:21 -u user:pwd