Paolo Asperti
8289114ee6
All checks were successful
continuous-integration/drone/push Build is passing
199 lines
6.4 KiB
Markdown
199 lines
6.4 KiB
Markdown
# docker-ftps
|
|
|
|
[![Build Status](https://drone.asperti.com/api/badges/paspo/docker-ftps/status.svg)](https://drone.asperti.com/paspo/docker-ftps)
|
|
|
|
Simple container for FTP+TLS+authentication
|
|
|
|
Supported architectures:
|
|
|
|
| Architecture | Available | Tag |
|
|
| :----: | :----: | ---- |
|
|
| x86-64 | ✅ | \<version tag\>-linux-amd64 |
|
|
| arm64 | ✅ | \<version tag\>-linux-arm64 |
|
|
| armhf | ❌ | - |
|
|
|
|
## build
|
|
|
|
```bash
|
|
docker build . -t docker.asperti.com/paspo/ftps
|
|
```
|
|
|
|
## run
|
|
|
|
```bash
|
|
docker run -d --name my-ftps \
|
|
-p 21:21 -p 20:20 -p 50000-50500:50000-50500 \
|
|
-e "MASQUERADE=ftp.mydomain.com" \
|
|
-v "$PWD/auth:/auth" -v "$PWD/ftpdata:/home" \
|
|
-v "$PWD/certs:/certs" \
|
|
docker.asperti.com/paspo/ftps
|
|
```
|
|
|
|
The *MASQUERADE* parameter is the only required one. You can use an IP address (which is discouraged) or a DNS name.
|
|
You must provide valid certificates for TLS; if you use Lets'Encrypt, you can modify like this:
|
|
|
|
```bash
|
|
docker run -d --name my-ftps \
|
|
-p 21:21 -p 20:20 -p 50000-50500:50000-50500 \
|
|
-e "MASQUERADE=ftp.mydomain.com" \
|
|
-v "$PWD/auth:/auth" -v "$PWD/ftpdata:/home" \
|
|
-v "/etc/letsencrypt/live/ftp.mydomain.com:/certs" \
|
|
docker.asperti.com/paspo/ftps
|
|
```
|
|
|
|
## docker-compose (external certificate)
|
|
|
|
```yaml
|
|
version: "3"
|
|
services:
|
|
|
|
ftps-server:
|
|
image: docker.asperti.com/paspo/ftps
|
|
restart: always
|
|
ports:
|
|
- "21:21"
|
|
- "20:20"
|
|
- "21210-21220:21210-21220"
|
|
volumes:
|
|
- "/srv/ftps/auth:/auth"
|
|
- "/srv/ftps/conf:/etc/proftpd/custom.conf.d:ro"
|
|
- "/srv/ftps/data:/home"
|
|
- "/etc/letsencrypt:/certs:ro"
|
|
environment:
|
|
- MASQUERADE=ftp.mydomain.com
|
|
- PASSIVEPORTS_START=21210
|
|
- PASSIVEPORTS_END=21220
|
|
- MAXCLIENTS=500
|
|
- MAXCLIENTSPERHOST=100
|
|
- TLS_CERT=/certs/live/ftp.mydomain.com/cert.pem
|
|
- TLS_KEY=/certs/live/ftp.mydomain.com/privkey.pem
|
|
- TLS_CHAIN=/certs/live/ftp.mydomain.com/chain.pem
|
|
```
|
|
|
|
## docker-compose (using internal acme.sh)
|
|
|
|
```yaml
|
|
version: "3"
|
|
services:
|
|
|
|
ftps-server:
|
|
image: docker.asperti.com/paspo/ftps
|
|
restart: always
|
|
ports:
|
|
- "21:21"
|
|
- "20:20"
|
|
- "21210-21220:21210-21220"
|
|
volumes:
|
|
- "/srv/ftps/auth:/auth"
|
|
- "/srv/ftps/conf:/etc/proftpd/custom.conf.d:ro"
|
|
- "/srv/ftps/data:/home"
|
|
- "/srv/ftps/acme:/acme"
|
|
environment:
|
|
- MASQUERADE=ftp.mydomain.com
|
|
- PASSIVEPORTS_START=21210
|
|
- PASSIVEPORTS_END=21220
|
|
- MAXCLIENTS=500
|
|
- MAXCLIENTSPERHOST=100
|
|
- ENABLE_ACME=1 # "1" will enable, anything else means external cert
|
|
- ACME_SERVER=letsencrypt # optional
|
|
- ACME_EMAIL=myemail@gmail.com # used by letsencrypt
|
|
- ACME_DNS=dns_ovh # see below
|
|
- OVH_END_POINT=ovh-eu
|
|
- OVH_AK=abc123abc123abc1 # application key
|
|
- OVH_AS=abc123abc123abc1abc123abc123abc1 # application secret
|
|
- OVH_CK=abc123abc123abc1abc123abc123abc1 # consumer key
|
|
```
|
|
|
|
## The rationale behind the acme.sh alternative
|
|
|
|
You normally use an external letsencrypt client to obtain the certificate and then pass it to the docker container. In some cases, you can't use an external acme client and/or you can't do HTTP-01 auth.
|
|
The included `acme.sh` client will help you to setup DNS-01 auth and in keeping the cert updated.
|
|
Please check [here](https://github.com/acmesh-official/acme.sh/wiki/dnsapi) for supported dns providers.
|
|
Each provider will use different environment variables, you have to add these variables to the container's environment.
|
|
|
|
### OVH
|
|
|
|
A quick way to create required credentials for OVH:
|
|
|
|
- login to your [OVH accuont](https://www.ovh.com/manager/)
|
|
- paste in your browser an URL like the following one:
|
|
|
|
```txt
|
|
https://api.ovh.com/createToken/?GET=/domain/zone/mydomain.com/*&POST=/domain/zone/mydomain.com/*&PUT=/domain/zone/mydomain.com/*&GET=/domain/zone/mydomain.com&DELETE=/domain/zone/mydomain.com/record/*
|
|
```
|
|
|
|
This will create some credentials that'll allow management only for that domain (`mydomain.com`).
|
|
|
|
## passive ports
|
|
|
|
If you want to change the passive ports range (which by default is 50000-50050), you can do so via environment variables (PASSIVEPORTS_START and PASSIVEPORTS_END).
|
|
In any case, you also have to enable a matching range of exposed ports.
|
|
|
|
## notes
|
|
|
|
Please note that you have to restart the container (or send sighup to proftpd) whenever the certificate is renewed.
|
|
We mount the complete letsencrypt directory because the in live/ftp.mydomain.com we have symlinks to the actual live certificates and in the container these will refer to non-existant files.
|
|
Also FTP active mode doesn't work until you configure networking as "host".
|
|
|
|
## users management
|
|
|
|
To change/set a password, do like this (replace "paolo" with the correct username):
|
|
|
|
```bash
|
|
docker exec -ti my-ftps ftpasswd --passwd --name=paolo --uid=1000 --home=/home/paolo --sha512 --shell=/bin/false --file=/auth/passwd
|
|
```
|
|
|
|
You also have to create and chown the user's home folder.
|
|
|
|
## sql db for user authentication
|
|
|
|
It is possible to use a sqlite db for user authentication, just add `SQLITE_AUTH=1` to the environment:
|
|
|
|
```yaml
|
|
version: "3"
|
|
services:
|
|
ftps-server:
|
|
image: docker.asperti.com/paspo/ftps
|
|
restart: always
|
|
ports:
|
|
- "21:21"
|
|
- "20:20"
|
|
- "21210-21220:21210-21220"
|
|
volumes:
|
|
- "/srv/ftps/auth:/auth"
|
|
- "/srv/ftps/conf:/etc/proftpd/custom.conf.d:ro"
|
|
- "/srv/ftps/data:/home"
|
|
- "/etc/letsencrypt:/certs:ro"
|
|
environment:
|
|
- SQLITE_AUTH=1
|
|
- MASQUERADE=ftp.mydomain.com
|
|
- PASSIVEPORTS_START=21210
|
|
- PASSIVEPORTS_END=21220
|
|
- MAXCLIENTS=500
|
|
- MAXCLIENTSPERHOST=100
|
|
- TLS_CERT=/certs/live/ftp.mydomain.com/cert.pem
|
|
- TLS_KEY=/certs/live/ftp.mydomain.com/privkey.pem
|
|
- TLS_CHAIN=/certs/live/ftp.mydomain.com/chain.pem
|
|
```
|
|
|
|
Now, instead of using `/auth/passwd`, proftpd is using `/auth/ftpd.db`.
|
|
To create a new user, you must now update this db.
|
|
|
|
To create a new user:
|
|
|
|
```bash
|
|
docker exec -ti my-ftps sqlite3 sqlite3 /auth/ftpd.db <<EOF
|
|
INSERT OR IGNORE INTO users (userid,passwd,uid,gid,homedir,shell) VALUES ('new_user','',1000,1000,'/home/new_user','/bin/false');
|
|
INSERT OR IGNORE INTO groups (groupname,gid,members) VALUES ('new_user',1000,'new_user');
|
|
EOF
|
|
```
|
|
|
|
To update a password:
|
|
|
|
```bash
|
|
PASSWD_SHA=$(echo -n ChangeThisPass | mkpasswd -m sha512)
|
|
docker exec -ti my-ftps sqlite3 sqlite3 /auth/ftpd.db <<EOF
|
|
UPDATE users SET passwd='$PASSWD_SHA' WHERE userid='new_user';
|
|
EOF
|
|
```
|