Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/crazy-max/docker-pure-ftpd

Pure-FTPd Docker image based on Alpine Linux with MySQL, PostgreSQL and LDAP support
https://github.com/crazy-max/docker-pure-ftpd

alpine-linux docker docker-compose pure-ftpd pureftpd

Last synced: 13 days ago
JSON representation

Pure-FTPd Docker image based on Alpine Linux with MySQL, PostgreSQL and LDAP support

Awesome Lists containing this project

README

        


Latest Version
Build Status
Docker Stars
Docker Pulls

Become a sponsor
Donate Paypal

## About

[Pure-FTPd](https://www.pureftpd.org/) Docker image based with MySQL,
PostgreSQL and LDAP support.

> [!TIP]
> Want to be notified of new releases? Check out 🔔 [Diun (Docker Image Update Notifier)](https://github.com/crazy-max/diun)
> project!

___

* [Features](#features)
* [Build locally](#build-locally)
* [Image](#image)
* [Environment variables](#environment-variables)
* [Volumes](#volumes)
* [Ports](#ports)
* [Usage](#usage)
* [Docker Compose](#docker-compose)
* [Command line](#command-line)
* [Upgrade](#upgrade)
* [Notes](#notes)
* [Flags](#flags)
* [Secure mode](#secure-mode)
* [PureDB authentication method](#puredb-authentication-method)
* [Persist FTP user home](#persist-ftp-user-home)
* [MySQL authentication method](#mysql-authentication-method)
* [PostgreSQL authentication method](#postgresql-authentication-method)
* [TLS connection](#tls-connection)
* [Logs](#logs)
* [Contributing](#contributing)
* [License](#license)

## Features

* Multi-platform image
* [s6-overlay](https://github.com/just-containers/s6-overlay/) as process supervisor
* [PureDB](#puredb-authentication-method), [MySQL](#mysql-authentication-method), [PostgreSQL](examples/postgresql) and LDAP support
* Latest [Pure-FTPd](https://github.com/jedisct1/pure-ftpd) release compiled from source
* Support of `argon2` and `scrypt` hashing method through [Libsodium](https://libsodium.org/)
* Logs processed to `stdout` through [socklog-overlay](https://github.com/just-containers/socklog-overlay/)
* Support of `pure-uploadscript`
* `PASSIVE_IP` for PASV support automatically resolved

## Build locally

```shell
git clone https://github.com/crazy-max/docker-pure-ftpd.git
cd docker-pure-ftpd

# Build image and output to docker (default)
docker buildx bake

# Build multi-platform image
docker buildx bake image-all
```

## Image

| Registry | Image |
|--------------------------------------------------------------------------------------------------|---------------------------------|
| [Docker Hub](https://hub.docker.com/r/crazymax/pure-ftpd/) | `crazymax/pure-ftpd` |
| [GitHub Container Registry](https://github.com/users/crazy-max/packages/container/package/pure-ftpd) | `ghcr.io/crazy-max/pure-ftpd` |

Following platforms for this image are available:

```
$ docker run --rm mplatform/mquery crazymax/pure-ftpd:latest
Image: crazymax/pure-ftpd:latest
* Manifest List: Yes
* Supported platforms:
- linux/amd64
- linux/arm/v6
- linux/arm/v7
- linux/arm64
- linux/386
- linux/ppc64le
```

## Environment variables

* `TZ`: Timezone assigned to the container (default `UTC`)
* `AUTH_METHOD`: Authentication method to use. Can be `puredb`, `mysql`, `pgsql` or `ldap` (default `puredb`)
* `SECURE_MODE`: Enable [secure mode](#secure-mode) (default `true`)
* `PASSIVE_IP`: IP/Host for PASV support (default auto resolved with `dig +short myip.opendns.com @resolver1.opendns.com`)
* `PASSIVE_PORT_RANGE`: Port range for passive connections (default `30000:30009`)
* `DB_TIMEOUT`: Time in seconds after which we stop trying to reach the database server. Only used for `mysql` and `pgsql` auth method (default `45`)
* `UPLOADSCRIPT`: What program/script to run after an upload. It has to be _an absolute filename_. (for example `/data/uploadscript.sh`)

> :warning: Do not set `--uploadscript` flag. It will be added if `UPLOADSCRIPT` is defined.

## Volumes

* `/data`: Contains config files and PureDB file

## Ports

* `2100`: FTP port
* `30000-30009`: PASV port range

## Usage

### Docker Compose

Docker compose is the recommended way to run this image. You can use the following
[compose template](examples/puredb/compose.yml), then run the container:

```bash
docker compose up -d
docker compose logs -f
```

### Command line

You can also use the following minimal command:

```bash
$ docker run -d --name pure-ftpd \
-p 2100:2100 \
-p 30000-30009:30000-30009 \
-e "TZ=Europe/Paris" \
-v $(pwd)/data:/data \
crazymax/pure-ftpd
```

## Upgrade

Recreate the container whenever I push an update:

```bash
docker compose pull
docker compose up -d
```

## Notes

### Flags

This image uses flags instead of the configuration file to set Pure-FTPd. Some
[flags are forced](https://github.com/crazy-max/docker-pure-ftpd/blob/55c6f6f0857536faf2d93f8d8227c6fec84200ec/entrypoint.sh#L32-L38)
but you can pass additional flags in `/data/pureftpd.flags` file:

```
-d
-d
--maxclientsperip 5
--minuid 100
--limitrecursion 10000:3
```

### Secure mode

`SECURE_MODE` enables
[specially crafted flags](https://github.com/crazy-max/docker-pure-ftpd/blob/55c6f6f0857536faf2d93f8d8227c6fec84200ec/entrypoint.sh#L44-L56)
to enforced security of Pure-FTPd.

### PureDB authentication method

Using [PureDB](examples/puredb) authentication method, the container will create a blank password file in
`/data/pureftpd.passwd` and a initialize a PureDB database in `/data/pureftpd.pdb`. If a password file is
already available, it will be read on startup and the PureDB database will be updated.

At first execution of the container no user will be available and you will have to create one:

```
$ docker compose exec pureftpd pure-pw useradd foo -u 1003 -g 1005 -d /home/foo -m
Password:
Enter it again:
$ docker compose exec pureftpd pure-pw list
foo /home/foo/./
$ cat ./data/pureftpd.passwd
foo:$2a$10$Oqn7I2P7YaGxQrtuydcDKuxmCJqPR7a79EeDy2gChyOGEnYA4UIPK:1003:1005::/home/foo/./::::::::::::
```

> User `foo` will be created with uid `1003`, gid `1005` with his home directory located at `/home/foo`.
> The password will be asked after. More info about local users database:
> https://github.com/jedisct1/pure-ftpd/blob/master/README.Virtual-Users

### Persist FTP user home

Looking at the previous example, don't forget to persist the home directory through a
[named or bind mounted volume](https://docs.docker.com/storage/volumes/) like:

```bash
version: "3.2"

services:
pureftpd:
image: crazymax/pure-ftpd
container_name: pureftpd
ports:
- "2100:2100"
- "30000-30009:30000-30009"
volumes:
- "./data:/data"
- "./foo:/home/foo"
environment:
- "TZ=Europe/Paris"
- "AUTH_METHOD=puredb"
restart: always
```

### MySQL authentication method

A [quick example](examples/mariadb) to use MySQL authentication method is also available using a MariaDB container.
Before using starting the container, a [MySQL configuration file](examples/mariadb/data/pureftpd-mysql.conf) must
be available in `/data/pureftpd-mysql.conf`.

In the [docker compose example](examples/mariadb) available, the database and the
[users table](examples/mariadb/users.sql) will be created at first launch.

To create your first user you can use this one line command:

```
$ docker compose exec db mysql -u pureftpd -p'asupersecretpassword' -e "INSERT INTO users (User,Password,Uid,Gid,Dir) VALUES ('foo',ENCRYPT('test'),'1003','1005','/home/foo');" pureftpd
$ docker compose exec db mysql -u pureftpd -p'asupersecretpassword' -e "SELECT * FROM users;" pureftpd
+------+---------------+------+------+-----------+
| User | Password | Uid | Gid | Dir |
+------+---------------+------+------+-----------+
| foo | Oo4cJdd1HNVA6 | 1003 | 1005 | /home/foo |
+------+---------------+------+------+-----------+
```

> User `foo` will be created with uid `1003`, gid `1005` with his home directory located at `/home/foo`. Here we assume
> `crypt` is the `MySQLCrypt` method and the password `test` is hashed using crypt.
> More info about MySQL authentication method: https://github.com/jedisct1/pure-ftpd/blob/master/README.MySQL

### PostgreSQL authentication method

Like MySQL, there is also a [quick example](examples/postgresql) to use PostgreSQL authentication method using a
PostgreSQL container. And also before starting the container, a
[PostgreSQL configuration file](examples/postgresql/data/pureftpd-pgsql.conf) must be available
in `/data/pureftpd-pgsql.conf`.

In the [docker compose example](examples/postgresql) available, the database and the
[users table](examples/postgresql/users.sql) will be also created at first launch.

How add new user with encrypted password?
```sql
CREATE EXTENSION pgcrypto;
INSERT INTO "users" ("User", "Password", "Dir") VALUES ('foo', crypt('mypassword', gen_salt('bf')), '/home/foo');
```

> More info about PostgreSQL authentication method: https://github.com/jedisct1/pure-ftpd/blob/master/README.PGSQL

### TLS connection

[TLS connections](https://github.com/jedisct1/pure-ftpd/blob/master/README.TLS) require certificates, as well as their
key. Both can be bundled into a single file. If you have both a `.pem` file and a `.key` file, just concatenate the
content of the `.key` file to the `.pem` file.

The certificate needs to be located in `/data/pureftpd.pem` and `--tls ` added to enable TLS connection.

To get started, you can create a self-signed certificate with the following command:

```
docker run --rm -it --entrypoint '' -v $(pwd)/data:/data crazymax/pure-ftpd \
openssl dhparam -out /data/pureftpd-dhparams.pem 2048
docker run --rm -it --entrypoint '' -v $(pwd)/data:/data crazymax/pure-ftpd \
openssl req -x509 -nodes -newkey rsa:2048 -sha256 -keyout /data/pureftpd.pem -out /data/pureftpd.pem
```

### Logs

Logs are displayed through `stdout` using `socklog-overlay`. You can increase verbosity with `-d -d` flags.

```
$ docker compose logs -f pureftpd
Attaching to pureftpd
pureftpd | [s6-init] making user provided files available at /var/run/s6/etc...exited 0.
pureftpd | [s6-init] ensuring user provided files have correct perms...exited 0.
pureftpd | [fix-attrs.d] applying ownership & permissions fixes...
pureftpd | [fix-attrs.d] done.
pureftpd | [cont-init.d] executing container initialization scripts...
pureftpd | [cont-init.d] 01-config.sh: executing...
pureftpd | Setting timezone to America/Edmonton...
pureftpd | Use PureDB authentication method
pureftpd | Flags
pureftpd | Secure:
pureftpd | Additional:
pureftpd | All: --bind 0.0.0.0,2100 --ipv4only --passiveportrange 30000:30009 --noanonymous --createhomedir --nochmod --syslogfacility ftp --forcepassiveip 90.101.64.158 --login puredb:/data/pureftpd.pdb
pureftpd | [cont-init.d] 01-config.sh: exited 0.
pureftpd | [cont-init.d] 02-service.sh: executing...
pureftpd | [cont-init.d] 02-service.sh: exited 0.
pureftpd | [cont-init.d] 03-uploadscript.sh: executing...
pureftpd | [cont-init.d] 03-uploadscript.sh: exited 0.
pureftpd | [cont-init.d] ~-socklog: executing...
pureftpd | [cont-init.d] ~-socklog: exited 0.
pureftpd | [cont-init.d] done.
pureftpd | [services.d] starting services
pureftpd | [services.d] done.
pureftpd | ftp.info: May 21 18:09:56 pure-ftpd: ([email protected]) [INFO] New connection from 192.168.0.1
pureftpd | ftp.info: May 21 18:09:56 pure-ftpd: ([email protected]) [INFO] foo is now logged in
pureftpd | ftp.notice: May 21 18:10:17 pure-ftpd: ([email protected]) [NOTICE] /home/foo//unlock.bin uploaded (1024 bytes, 448.83KB/sec)
...
```

## Contributing

Want to contribute? Awesome! The most basic way to show your support is to star
the project, or to raise issues. You can also support this project by [**becoming a sponsor on GitHub**](https://github.com/sponsors/crazy-max)
or by making a [PayPal donation](https://www.paypal.me/crazyws) to ensure this
journey continues indefinitely!

Thanks again for your support, it is much appreciated! :pray:

## License

MIT. See `LICENSE` for more details.