{"id":13548189,"url":"https://github.com/crazy-max/docker-pure-ftpd","last_synced_at":"2025-04-19T15:43:40.777Z","repository":{"id":40451055,"uuid":"218415841","full_name":"crazy-max/docker-pure-ftpd","owner":"crazy-max","description":"Pure-FTPd Docker image based on Alpine Linux with MySQL, PostgreSQL and LDAP support","archived":false,"fork":false,"pushed_at":"2024-08-08T19:27:00.000Z","size":227,"stargazers_count":56,"open_issues_count":3,"forks_count":15,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-10-18T07:32:11.508Z","etag":null,"topics":["alpine-linux","docker","docker-compose","pure-ftpd","pureftpd"],"latest_commit_sha":null,"homepage":"","language":"Dockerfile","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/crazy-max.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":".github/SUPPORT.md","governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"crazy-max","custom":"https://www.paypal.me/crazyws"}},"created_at":"2019-10-30T01:17:17.000Z","updated_at":"2024-10-06T07:32:54.000Z","dependencies_parsed_at":"2024-05-28T03:15:56.226Z","dependency_job_id":"d89e0479-1500-4d98-a083-37f6c444407d","html_url":"https://github.com/crazy-max/docker-pure-ftpd","commit_stats":{"total_commits":134,"total_committers":6,"mean_commits":"22.333333333333332","dds":"0.21641791044776115","last_synced_commit":"35056fc2170322ce7a53dde5e3c617508a3902a0"},"previous_names":[],"tags_count":40,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crazy-max%2Fdocker-pure-ftpd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crazy-max%2Fdocker-pure-ftpd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crazy-max%2Fdocker-pure-ftpd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crazy-max%2Fdocker-pure-ftpd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/crazy-max","download_url":"https://codeload.github.com/crazy-max/docker-pure-ftpd/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249729672,"owners_count":21317145,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["alpine-linux","docker","docker-compose","pure-ftpd","pureftpd"],"created_at":"2024-08-01T12:01:06.961Z","updated_at":"2025-04-19T15:43:40.761Z","avatar_url":"https://github.com/crazy-max.png","language":"Dockerfile","readme":"\u003cp align=\"center\"\u003e\u003ca href=\"https://github.com/crazy-max/docker-pure-ftpd\" target=\"_blank\"\u003e\u003cimg height=\"128\" src=\"https://raw.githubusercontent.com/crazy-max/docker-pure-ftpd/master/.github/docker-pure-ftpd.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://hub.docker.com/r/crazymax/pure-ftpd/tags?page=1\u0026ordering=last_updated\"\u003e\u003cimg src=\"https://img.shields.io/github/v/tag/crazy-max/docker-pure-ftpd?label=version\u0026style=flat-square\" alt=\"Latest Version\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/crazy-max/docker-pure-ftpd/actions?workflow=build\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/crazy-max/docker-pure-ftpd/build.yml?branch=master\u0026label=build\u0026logo=github\u0026style=flat-square\" alt=\"Build Status\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://hub.docker.com/r/crazymax/pure-ftpd/\"\u003e\u003cimg src=\"https://img.shields.io/docker/stars/crazymax/pure-ftpd.svg?style=flat-square\u0026logo=docker\" alt=\"Docker Stars\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://hub.docker.com/r/crazymax/pure-ftpd/\"\u003e\u003cimg src=\"https://img.shields.io/docker/pulls/crazymax/pure-ftpd.svg?style=flat-square\u0026logo=docker\" alt=\"Docker Pulls\"\u003e\u003c/a\u003e\n  \u003cbr /\u003e\u003ca href=\"https://github.com/sponsors/crazy-max\"\u003e\u003cimg src=\"https://img.shields.io/badge/sponsor-crazy--max-181717.svg?logo=github\u0026style=flat-square\" alt=\"Become a sponsor\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.paypal.me/crazyws\"\u003e\u003cimg src=\"https://img.shields.io/badge/donate-paypal-00457c.svg?logo=paypal\u0026style=flat-square\" alt=\"Donate Paypal\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n## About\n\n[Pure-FTPd](https://www.pureftpd.org/) Docker image based with MySQL,\nPostgreSQL and LDAP support.\n\n\u003e [!TIP] \n\u003e Want to be notified of new releases? Check out 🔔 [Diun (Docker Image Update Notifier)](https://github.com/crazy-max/diun)\n\u003e project!\n\n___\n\n* [Features](#features)\n* [Build locally](#build-locally)\n* [Image](#image)\n* [Environment variables](#environment-variables)\n* [Volumes](#volumes)\n* [Ports](#ports)\n* [Usage](#usage)\n  * [Docker Compose](#docker-compose)\n  * [Command line](#command-line)\n* [Upgrade](#upgrade)\n* [Notes](#notes)\n  * [Flags](#flags)\n  * [Secure mode](#secure-mode)\n  * [PureDB authentication method](#puredb-authentication-method)\n  * [Persist FTP user home](#persist-ftp-user-home)\n  * [MySQL authentication method](#mysql-authentication-method)\n  * [PostgreSQL authentication method](#postgresql-authentication-method)\n  * [TLS connection](#tls-connection)\n  * [Logs](#logs)\n* [Contributing](#contributing)\n* [License](#license)\n\n## Features\n\n* Multi-platform image\n* [s6-overlay](https://github.com/just-containers/s6-overlay/) as process supervisor\n* [PureDB](#puredb-authentication-method), [MySQL](#mysql-authentication-method), [PostgreSQL](examples/postgresql) and LDAP support\n* Latest [Pure-FTPd](https://github.com/jedisct1/pure-ftpd) release compiled from source\n* Support of `argon2` and `scrypt` hashing method through [Libsodium](https://libsodium.org/)\n* Logs processed to `stdout` through [socklog-overlay](https://github.com/just-containers/socklog-overlay/)\n* Support of `pure-uploadscript`\n* `PASSIVE_IP` for PASV support automatically resolved\n\n## Build locally\n\n```shell\ngit clone https://github.com/crazy-max/docker-pure-ftpd.git\ncd docker-pure-ftpd\n\n# Build image and output to docker (default)\ndocker buildx bake\n\n# Build multi-platform image\ndocker buildx bake image-all\n```\n\n## Image\n\n| Registry                                                                                         | Image                           |\n|--------------------------------------------------------------------------------------------------|---------------------------------|\n| [Docker Hub](https://hub.docker.com/r/crazymax/pure-ftpd/)                                            | `crazymax/pure-ftpd`                 |\n| [GitHub Container Registry](https://github.com/users/crazy-max/packages/container/package/pure-ftpd)  | `ghcr.io/crazy-max/pure-ftpd`        |\n\nFollowing platforms for this image are available:\n\n```\n$ docker buildx imagetools inspect crazymax/pure-ftpd --format \"{{json .Manifest}}\" | \\\n  jq -r '.manifests[] | select(.platform.os != null and .platform.os != \"unknown\") | .platform | \"\\(.os)/\\(.architecture)\\(if .variant then \"/\" + .variant else \"\" end)\"'\n\nlinux/386\nlinux/amd64\nlinux/arm/v6\nlinux/arm/v7\nlinux/arm64\nlinux/ppc64le\n```\n\n## Environment variables\n\n* `TZ`: Timezone assigned to the container (default `UTC`)\n* `AUTH_METHOD`: Authentication method to use. Can be `puredb`, `mysql`, `pgsql` or `ldap` (default `puredb`)\n* `SECURE_MODE`: Enable [secure mode](#secure-mode) (default `true`)\n* `PASSIVE_IP`: IP/Host for PASV support (default auto resolved with `dig +short myip.opendns.com @resolver1.opendns.com`)\n* `PASSIVE_PORT_RANGE`: Port range for passive connections (default `30000:30009`)\n* `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`)\n* `UPLOADSCRIPT`: What program/script to run after an upload. It has to be _an absolute filename_. (for example `/data/uploadscript.sh`)\n\n\u003e :warning: Do not set `--uploadscript` flag. It will be added if `UPLOADSCRIPT` is defined.\n\n## Volumes\n\n* `/data`: Contains config files and PureDB file\n\n## Ports\n\n* `2100`: FTP port\n* `30000-30009`: PASV port range\n\n## Usage\n\n### Docker Compose\n\nDocker compose is the recommended way to run this image. You can use the following\n[compose template](examples/puredb/compose.yml), then run the container:\n\n```bash\ndocker compose up -d\ndocker compose logs -f\n```\n\n### Command line\n\nYou can also use the following minimal command:\n\n```bash\n$ docker run -d --name pure-ftpd \\\n  -p 2100:2100 \\\n  -p 30000-30009:30000-30009 \\\n  -e \"TZ=Europe/Paris\" \\\n  -v $(pwd)/data:/data \\\n  crazymax/pure-ftpd\n```\n\n## Upgrade\n\nRecreate the container whenever I push an update:\n\n```bash\ndocker compose pull\ndocker compose up -d\n```\n\n## Notes\n\n### Flags\n\nThis image uses flags instead of the configuration file to set Pure-FTPd. Some\n[flags are forced](https://github.com/crazy-max/docker-pure-ftpd/blob/55c6f6f0857536faf2d93f8d8227c6fec84200ec/entrypoint.sh#L32-L38)\nbut you can pass additional flags in `/data/pureftpd.flags` file:\n\n```\n-d\n-d\n--maxclientsperip 5\n--minuid 100\n--limitrecursion 10000:3\n```\n\n### Secure mode\n\n`SECURE_MODE` enables\n[specially crafted flags](https://github.com/crazy-max/docker-pure-ftpd/blob/55c6f6f0857536faf2d93f8d8227c6fec84200ec/entrypoint.sh#L44-L56)\nto enforced security of Pure-FTPd.\n\n### PureDB authentication method\n\nUsing [PureDB](examples/puredb) authentication method, the container will create a blank password file in\n`/data/pureftpd.passwd` and a initialize a PureDB database in `/data/pureftpd.pdb`. If a password file is\nalready available, it will be read on startup and the PureDB database will be updated.\n\nAt first execution of the container no user will be available and you will have to create one:\n\n```\n$ docker compose exec pureftpd pure-pw useradd foo -u 1003 -g 1005 -d /home/foo -m\nPassword:\nEnter it again:\n$ docker compose exec pureftpd pure-pw list\nfoo                 /home/foo/./\n$ cat ./data/pureftpd.passwd\nfoo:$2a$10$Oqn7I2P7YaGxQrtuydcDKuxmCJqPR7a79EeDy2gChyOGEnYA4UIPK:1003:1005::/home/foo/./::::::::::::\n```\n\n\u003e User `foo` will be created with uid `1003`, gid `1005` with his home directory located at `/home/foo`.\n\u003e The password will be asked after. More info about local users database:\n\u003e https://github.com/jedisct1/pure-ftpd/blob/master/README.Virtual-Users\n\n### Persist FTP user home\n\nLooking at the previous example, don't forget to persist the home directory through a\n[named or bind mounted volume](https://docs.docker.com/storage/volumes/) like:\n\n```bash\nversion: \"3.2\"\n\nservices:\n  pureftpd:\n    image: crazymax/pure-ftpd\n    container_name: pureftpd\n    ports:\n      - \"2100:2100\"\n      - \"30000-30009:30000-30009\"\n    volumes:\n      - \"./data:/data\"\n      - \"./foo:/home/foo\"\n    environment:\n      - \"TZ=Europe/Paris\"\n      - \"AUTH_METHOD=puredb\"\n    restart: always\n```\n\n### MySQL authentication method\n\nA [quick example](examples/mariadb) to use MySQL authentication method is also available using a MariaDB container.\nBefore using starting the container, a [MySQL configuration file](examples/mariadb/data/pureftpd-mysql.conf) must\nbe available in `/data/pureftpd-mysql.conf`.\n\nIn the [docker compose example](examples/mariadb) available, the database and the\n[users table](examples/mariadb/users.sql) will be created at first launch.\n\nTo create your first user you can use this one line command:\n\n```\n$ 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\n$ docker compose exec db mysql -u pureftpd -p'asupersecretpassword' -e \"SELECT * FROM users;\" pureftpd\n+------+---------------+------+------+-----------+\n| User | Password      | Uid  | Gid  | Dir       |\n+------+---------------+------+------+-----------+\n| foo  | Oo4cJdd1HNVA6 | 1003 | 1005 | /home/foo |\n+------+---------------+------+------+-----------+\n```\n\n\u003e User `foo` will be created with uid `1003`, gid `1005` with his home directory located at `/home/foo`. Here we assume\n\u003e `crypt` is the `MySQLCrypt` method and the password `test` is hashed using crypt.\n\u003e More info about MySQL authentication method: https://github.com/jedisct1/pure-ftpd/blob/master/README.MySQL\n\n### PostgreSQL authentication method\n\nLike MySQL, there is also a [quick example](examples/postgresql) to use PostgreSQL authentication method using a\nPostgreSQL container. And also before starting the container, a\n[PostgreSQL configuration file](examples/postgresql/data/pureftpd-pgsql.conf) must be available\nin `/data/pureftpd-pgsql.conf`.\n\nIn the [docker compose example](examples/postgresql) available, the database and the\n[users table](examples/postgresql/users.sql) will be also created at first launch.\n\nHow add new user with encrypted password?\n```sql\nCREATE EXTENSION pgcrypto;\nINSERT INTO \"users\" (\"User\", \"Password\", \"Dir\") VALUES ('foo', crypt('mypassword', gen_salt('bf')), '/home/foo');\n```\n\n\u003e More info about PostgreSQL authentication method: https://github.com/jedisct1/pure-ftpd/blob/master/README.PGSQL\n\n### TLS connection\n\n[TLS connections](https://github.com/jedisct1/pure-ftpd/blob/master/README.TLS) require certificates, as well as their\nkey. Both can be bundled into a single file. If you have both a `.pem` file and a `.key` file, just concatenate the\ncontent of the `.key` file to the `.pem` file.\n\nThe certificate needs to be located in `/data/pureftpd.pem` and `--tls \u003copt\u003e` added to enable TLS connection.\n\nTo get started, you can create a self-signed certificate with the following command:\n\n```\ndocker run --rm -it --entrypoint '' -v $(pwd)/data:/data crazymax/pure-ftpd \\\n  openssl dhparam -out /data/pureftpd-dhparams.pem 2048\ndocker run --rm -it --entrypoint '' -v $(pwd)/data:/data crazymax/pure-ftpd \\\n  openssl req -x509 -nodes -newkey rsa:2048 -sha256 -keyout /data/pureftpd.pem -out /data/pureftpd.pem\n```\n\n### Logs\n\nLogs are displayed through `stdout` using `socklog-overlay`. You can increase verbosity with `-d -d` flags.\n\n```\n$ docker compose logs -f pureftpd\nAttaching to pureftpd\npureftpd    | [s6-init] making user provided files available at /var/run/s6/etc...exited 0.\npureftpd    | [s6-init] ensuring user provided files have correct perms...exited 0.\npureftpd    | [fix-attrs.d] applying ownership \u0026 permissions fixes...\npureftpd    | [fix-attrs.d] done.\npureftpd    | [cont-init.d] executing container initialization scripts...\npureftpd    | [cont-init.d] 01-config.sh: executing...\npureftpd    | Setting timezone to America/Edmonton...\npureftpd    | Use PureDB authentication method\npureftpd    | Flags\npureftpd    |   Secure:\npureftpd    |   Additional:\npureftpd    |   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\npureftpd    | [cont-init.d] 01-config.sh: exited 0.\npureftpd    | [cont-init.d] 02-service.sh: executing...\npureftpd    | [cont-init.d] 02-service.sh: exited 0.\npureftpd    | [cont-init.d] 03-uploadscript.sh: executing...\npureftpd    | [cont-init.d] 03-uploadscript.sh: exited 0.\npureftpd    | [cont-init.d] ~-socklog: executing...\npureftpd    | [cont-init.d] ~-socklog: exited 0.\npureftpd    | [cont-init.d] done.\npureftpd    | [services.d] starting services\npureftpd    | [services.d] done.\npureftpd    | ftp.info: May 21 18:09:56 pure-ftpd: (?@192.168.0.1) [INFO] New connection from 192.168.0.1\npureftpd    | ftp.info: May 21 18:09:56 pure-ftpd: (?@192.168.0.1) [INFO] foo is now logged in\npureftpd    | ftp.notice: May 21 18:10:17 pure-ftpd: (foo@192.168.0.1) [NOTICE] /home/foo//unlock.bin uploaded  (1024 bytes, 448.83KB/sec)\n...\n```\n\n## Contributing\n\nWant to contribute? Awesome! The most basic way to show your support is to star\nthe project, or to raise issues. You can also support this project by [**becoming a sponsor on GitHub**](https://github.com/sponsors/crazy-max)\nor by making a [PayPal donation](https://www.paypal.me/crazyws) to ensure this\njourney continues indefinitely!\n\nThanks again for your support, it is much appreciated! :pray:\n\n## License\n\nMIT. See `LICENSE` for more details.\n","funding_links":["https://github.com/sponsors/crazy-max","https://www.paypal.me/crazyws"],"categories":["Dockerfile"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrazy-max%2Fdocker-pure-ftpd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcrazy-max%2Fdocker-pure-ftpd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrazy-max%2Fdocker-pure-ftpd/lists"}