Compare commits
39 Commits
Author | SHA1 | Date |
---|---|---|
Paolo Asperti | 799895baa0 | |
Paolo Asperti | dcf768fd21 | |
Paolo Asperti | 9137f439f1 | |
Paolo Asperti | fade210106 | |
Paolo Asperti | e1e1e1ee29 | |
Paolo Asperti | 8dcdd4a30a | |
Paolo Asperti | 8289114ee6 | |
Paolo Asperti | 9fca459f93 | |
Paolo Asperti | d5c00a0308 | |
Paolo Asperti | 08134aefa5 | |
Paolo Asperti | e92da50d28 | |
Paolo Asperti | 5eaede5ca8 | |
Paolo Asperti | 83d15f9436 | |
Paolo Asperti | 26f542354d | |
Paolo Asperti | 962624e294 | |
Paolo Asperti | 488acf16c1 | |
Paolo Asperti | 5a78015465 | |
Paolo Asperti | 07629dfc63 | |
Paolo Asperti | 9acb740486 | |
Paolo Asperti | 476ba9bb82 | |
Paolo Asperti | ac93e435be | |
Paolo Asperti | f4579d2608 | |
Paolo Asperti | 4ea2ba1fb8 | |
Paolo Asperti | 342593fb8b | |
Paolo Asperti | 0bfeed1515 | |
Paolo Asperti | ee03f1ed43 | |
Paolo Asperti | 8c2fcfc4a1 | |
Paolo Asperti | f34ea92952 | |
Paolo Asperti | 1769ab4503 | |
Paolo Asperti | 89eab906e4 | |
Paolo Asperti | f837bda293 | |
Paolo Asperti | 9b26bdf411 | |
Paolo Asperti | 750799ccdc | |
Paolo Asperti | 967cb2aaf5 | |
Paolo Asperti | 51f2e1f2d4 | |
Paolo Asperti | 5704aef30a | |
Paolo Asperti | f4cfd24fdb | |
Paolo Asperti | 880c9340fa | |
Paolo Asperti | ff5ac84a71 |
158
.drone.yml
158
.drone.yml
|
@ -1,34 +1,166 @@
|
|||
kind: pipeline
|
||||
name: default
|
||||
type: docker
|
||||
name: linux-amd64
|
||||
|
||||
platform:
|
||||
arch: amd64
|
||||
os: linux
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: plugins/docker:linux-amd64
|
||||
pull: always
|
||||
settings:
|
||||
daemon_off: false
|
||||
dockerfile: Dockerfile
|
||||
dry_run: true
|
||||
repo: docker.asperti.com/paspo/ftps
|
||||
tags:
|
||||
- latest
|
||||
when:
|
||||
event:
|
||||
exclude:
|
||||
- tag
|
||||
|
||||
- push
|
||||
|
||||
- name: build_and_publish
|
||||
image: plugins/docker:linux-amd64
|
||||
pull: always
|
||||
settings:
|
||||
daemon_off: false
|
||||
dockerfile: Dockerfile
|
||||
force_tag: true
|
||||
password:
|
||||
from_secret: docker_password
|
||||
registry: docker.asperti.com
|
||||
repo: docker.asperti.com/paspo/ftps
|
||||
tags:
|
||||
- latest
|
||||
username:
|
||||
from_secret: docker_username
|
||||
tags:
|
||||
- ${DRONE_TAG}-linux-amd64
|
||||
- ${DRONE_SEMVER_MAJOR}.${DRONE_SEMVER_MINOR}-linux-amd64
|
||||
- ${DRONE_SEMVER_MAJOR}-linux-amd64
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
- tag
|
||||
|
||||
- name: build_and_publish2
|
||||
image: plugins/docker:linux-amd64
|
||||
settings:
|
||||
dockerfile: Dockerfile
|
||||
force_tag: true
|
||||
password:
|
||||
from_secret: gitea_docker_password
|
||||
registry: git.asperti.com
|
||||
repo: git.asperti.com/paspo/docker-ftps
|
||||
username:
|
||||
from_secret: gitea_docker_username
|
||||
tags:
|
||||
- ${DRONE_TAG}-linux-amd64
|
||||
- ${DRONE_SEMVER_MAJOR}.${DRONE_SEMVER_MINOR}-linux-amd64
|
||||
- ${DRONE_SEMVER_MAJOR}-linux-amd64
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: linux-arm64
|
||||
|
||||
platform:
|
||||
arch: arm64
|
||||
os: linux
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: plugins/docker:linux-arm64
|
||||
settings:
|
||||
dockerfile: Dockerfile
|
||||
dry_run: true
|
||||
repo: docker.asperti.com/paspo/ftps
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
|
||||
- name: build_and_publish
|
||||
image: plugins/docker:linux-arm64
|
||||
settings:
|
||||
dockerfile: Dockerfile
|
||||
force_tag: true
|
||||
password:
|
||||
from_secret: docker_password
|
||||
registry: docker.asperti.com
|
||||
repo: docker.asperti.com/paspo/ftps
|
||||
username:
|
||||
from_secret: docker_username
|
||||
tags:
|
||||
- ${DRONE_TAG}-linux-arm64
|
||||
- ${DRONE_SEMVER_MAJOR}.${DRONE_SEMVER_MINOR}-linux-arm64
|
||||
- ${DRONE_SEMVER_MAJOR}-linux-arm64
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
|
||||
- name: build_and_publish2
|
||||
image: plugins/docker:linux-arm64
|
||||
settings:
|
||||
dockerfile: Dockerfile
|
||||
force_tag: true
|
||||
password:
|
||||
from_secret: gitea_docker_password
|
||||
registry: git.asperti.com
|
||||
repo: git.asperti.com/paspo/docker-ftps
|
||||
username:
|
||||
from_secret: gitea_docker_username
|
||||
tags:
|
||||
- ${DRONE_TAG}-linux-arm64
|
||||
- ${DRONE_SEMVER_MAJOR}.${DRONE_SEMVER_MINOR}-linux-arm64
|
||||
- ${DRONE_SEMVER_MAJOR}-linux-arm64
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: manifest
|
||||
|
||||
steps:
|
||||
- name: manifest
|
||||
image: plugins/manifest
|
||||
settings:
|
||||
force_tag: true
|
||||
ignore_missing: true
|
||||
spec: manifest.tmpl
|
||||
username:
|
||||
from_secret: docker_username
|
||||
password:
|
||||
from_secret: docker_password
|
||||
tags:
|
||||
- latest
|
||||
- ${DRONE_TAG}
|
||||
- ${DRONE_SEMVER_MAJOR}.${DRONE_SEMVER_MINOR}
|
||||
- ${DRONE_SEMVER_MAJOR}
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
|
||||
- name: manifest2
|
||||
image: plugins/manifest
|
||||
settings:
|
||||
force_tag: true
|
||||
ignore_missing: true
|
||||
spec: manifest2.tmpl
|
||||
username:
|
||||
from_secret: gitea_docker_username
|
||||
password:
|
||||
from_secret: gitea_docker_password
|
||||
tags:
|
||||
- latest
|
||||
- ${DRONE_TAG}
|
||||
- ${DRONE_SEMVER_MAJOR}.${DRONE_SEMVER_MINOR}
|
||||
- ${DRONE_SEMVER_MAJOR}
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
|
||||
trigger:
|
||||
event:
|
||||
- tag
|
||||
|
||||
depends_on:
|
||||
- linux-amd64
|
||||
- linux-arm64
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
name: Vulnerability Scan
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 14 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
scan:
|
||||
name: Daily Vulnerability Scan
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: catthehacker/ubuntu:act-latest
|
||||
|
||||
steps:
|
||||
- name: Pull docker image
|
||||
run: docker pull docker.asperti.com/paspo/ftps:latest
|
||||
# run: docker pull git.asperti.com/paspo/docker-ftps:latest
|
||||
|
||||
- name: Run Trivy vulnerability scanner
|
||||
id: scan
|
||||
uses: aquasecurity/trivy-action@master
|
||||
with:
|
||||
image-ref: "docker.asperti.com/paspo/ftps:latest"
|
||||
# image-ref: "git.asperti.com/paspo/docker-ftps:latest"
|
||||
format: "json"
|
||||
output: "trivy-results.json"
|
||||
|
||||
# if some vulnerability is found, we fail
|
||||
- name: check output
|
||||
run: if [ $(jq '.Results[0].Vulnerabilities|length' trivy-results.json) -ne "0" ] ; then exit 1 ; fi
|
19
Dockerfile
19
Dockerfile
|
@ -1,13 +1,14 @@
|
|||
FROM alpine:edge
|
||||
FROM alpine:latest
|
||||
|
||||
RUN \
|
||||
echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \
|
||||
apk -U add proftpd proftpd-mod_tls proftpd-mod_auth_file proftpd-utils openssl && \
|
||||
mkdir -p /var/run/proftpd
|
||||
apk -U add proftpd proftpd-mod_tls proftpd-mod_ifsession \
|
||||
proftpd-mod_deflate proftpd-mod_geoip proftpd-mod_sql_sqlite \
|
||||
proftpd-utils openssl perl acme.sh lftp sqlite && \
|
||||
mkdir -p /var/run/proftpd /etc/proftpd/custom.conf.d/
|
||||
|
||||
COPY custom.conf /etc/proftpd/conf.d/custom.conf
|
||||
COPY run.sh /run.sh
|
||||
COPY rootfs /
|
||||
|
||||
RUN chmod +x /run.sh
|
||||
|
||||
ENTRYPOINT ["/run.sh"]
|
||||
HEALTHCHECK --interval=2m --timeout=3s \
|
||||
CMD /app/healthcheck.sh || exit 1
|
||||
|
||||
ENTRYPOINT ["/app/entrypoint.sh"]
|
||||
|
|
132
README.md
132
README.md
|
@ -4,6 +4,14 @@
|
|||
|
||||
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
|
||||
|
@ -22,7 +30,7 @@ docker run -d --name my-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 mofify like this:
|
||||
You must provide valid certificates for TLS; if you use Lets'Encrypt, you can modify like this:
|
||||
|
||||
```bash
|
||||
docker run -d --name my-ftps \
|
||||
|
@ -33,7 +41,7 @@ docker run -d --name my-ftps \
|
|||
docker.asperti.com/paspo/ftps
|
||||
```
|
||||
|
||||
## docker-compose
|
||||
## docker-compose (external certificate)
|
||||
|
||||
```yaml
|
||||
version: "3"
|
||||
|
@ -45,18 +53,82 @@ services:
|
|||
ports:
|
||||
- "21:21"
|
||||
- "20:20"
|
||||
- "50000-50500:50000-50500"
|
||||
- "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"
|
||||
- "/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.
|
||||
|
@ -72,3 +144,55 @@ docker exec -ti my-ftps ftpasswd --passwd --name=paolo --uid=1000 --home=/home/p
|
|||
```
|
||||
|
||||
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
|
||||
```
|
||||
|
|
23
custom.conf
23
custom.conf
|
@ -1,23 +0,0 @@
|
|||
AuthOrder mod_auth_file.c
|
||||
AuthUserFile /auth/passwd
|
||||
RequireValidShell off
|
||||
ScoreBoardFile /run/proftpd/scoreboard
|
||||
AllowOverwrite on
|
||||
WtmpLog off
|
||||
UseReverseDNS off
|
||||
DefaultRoot ~
|
||||
Maxclients 30
|
||||
MaxClientsPerHost 5
|
||||
|
||||
<IfModule mod_tls.c>
|
||||
TLSEngine on
|
||||
TLSVerifyClient off
|
||||
TLSRenegotiate none
|
||||
TLSProtocol TLSv1.2
|
||||
TLSRSACertificateFile /etc/proftpd/cert.pem
|
||||
TLSRSACertificateKeyFile /etc/proftpd/privkey.pem
|
||||
TLSCertificateChainFile /etc/proftpd/chain.pem
|
||||
TLSCipherSuite "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-RC4-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:RC4-SHA:AES256-GCM-SHA384:AES256-SHA256:CAMELLIA256-SHA:ECDHE-RSA-AES128-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:CAMELLIA128-SHA !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4"
|
||||
TLSOptions NoSessionReuseRequired AllowClientRenegotiations
|
||||
TLSRequired on
|
||||
</IfModule>
|
|
@ -0,0 +1,19 @@
|
|||
image: docker.asperti.com/paspo/ftps:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}latest{{/if}}
|
||||
{{#if build.tags}}
|
||||
tags:
|
||||
{{#each build.tags}}
|
||||
- {{this}}
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
manifests:
|
||||
-
|
||||
image: docker.asperti.com/paspo/ftps:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64
|
||||
platform:
|
||||
architecture: amd64
|
||||
os: linux
|
||||
-
|
||||
image: docker.asperti.com/paspo/ftps:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64
|
||||
platform:
|
||||
variant: v8
|
||||
architecture: arm64
|
||||
os: linux
|
|
@ -0,0 +1,19 @@
|
|||
image: git.asperti.com/paspo/docker-ftps:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}latest{{/if}}
|
||||
{{#if build.tags}}
|
||||
tags:
|
||||
{{#each build.tags}}
|
||||
- {{this}}
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
manifests:
|
||||
-
|
||||
image: git.asperti.com/paspo/docker-ftps:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64
|
||||
platform:
|
||||
architecture: amd64
|
||||
os: linux
|
||||
-
|
||||
image: git.asperti.com/paspo/docker-ftps:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64
|
||||
platform:
|
||||
variant: v8
|
||||
architecture: arm64
|
||||
os: linux
|
|
@ -0,0 +1,30 @@
|
|||
#!/bin/sh
|
||||
|
||||
MASQUERADE=${MASQUERADE:-127.0.0.1}
|
||||
ACME_SERVER=${ACME_SERVER:-letsencrypt}
|
||||
ACME_DNS=${ACME_DNS:-myapi}
|
||||
|
||||
if [ ! -d /acme/cert ] ; then
|
||||
mkdir -p /acme/cert
|
||||
fi
|
||||
|
||||
if [ -n "${ACME_EMAIL}" ] ; then
|
||||
ACME_EMAIL="--accountemail ${ACME_EMAIL}"
|
||||
fi
|
||||
|
||||
if [ ! -f "/acme/cert/cert.pem" ] ; then
|
||||
echo "Initializing certificate with acme.sh"
|
||||
# shellcheck disable=SC2086
|
||||
acme.sh --issue -d "${MASQUERADE}" \
|
||||
--home /acme \
|
||||
--dns "${ACME_DNS}" \
|
||||
--server "${ACME_SERVER}" \
|
||||
--cert-file /acme/cert/cert.pem \
|
||||
--key-file /acme/cert/privkey.pem \
|
||||
--fullchain-file /acme/cert/chain.pem \
|
||||
--reloadcmd /app/acme-refresh-cert.sh ${ACME_EMAIL}
|
||||
echo "Certificate ready"
|
||||
else
|
||||
/app/acme-refresh-cert.sh
|
||||
echo "Certificate ready"
|
||||
fi
|
|
@ -0,0 +1,8 @@
|
|||
#!/bin/sh
|
||||
|
||||
if [ "$ENABLE_ACME" = "1" ] ; then
|
||||
/usr/bin/acme.sh --cron --home /acme
|
||||
fi
|
||||
|
||||
############ RELOAD
|
||||
pidof proftpd >/dev/null && killall -HUP proftpd
|
|
@ -0,0 +1,38 @@
|
|||
#!/bin/sh
|
||||
|
||||
############ FILES
|
||||
|
||||
TLS_CERT=/acme/cert/cert.pem
|
||||
TLS_KEY=/acme/cert/privkey.pem
|
||||
TLS_CHAIN=/acme/cert/chain.pem
|
||||
|
||||
[ ! -f "$TLS_CERT" ] && exit 1
|
||||
[ ! -f "$TLS_KEY" ] && exit 1
|
||||
[ ! -f "$TLS_CHAIN" ] && exit 1
|
||||
|
||||
############ CHECK CERT KEY ALGO
|
||||
ALGO=$(openssl x509 -in "$TLS_CERT" -text | sed -n 's/\ *Public Key Algorithm: //p' | tr '\n')
|
||||
|
||||
############ UPDATE cert config if needed
|
||||
if [ "$ALGO" = "id-ecPublicKey" ] ; then
|
||||
cat > /etc/proftpd/conf.d/certificate.conf <<EOF
|
||||
<IfModule mod_tls.c>
|
||||
TLSECCertificateFile "$TLS_CERT"
|
||||
TLSECCertificateKeyFile "$TLS_KEY"
|
||||
TLSCertificateChainFile "$TLS_CHAIN"
|
||||
</IfModule>
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [ "$ALGO" = "rsaEncryption" ] ; then
|
||||
cat > /etc/proftpd/conf.d/certificate.conf <<EOF
|
||||
<IfModule mod_tls.c>
|
||||
TLSRSACertificateFile "$TLS_CERT"
|
||||
TLSRSACertificateKeyFile "$TLS_KEY"
|
||||
TLSCertificateChainFile "$TLS_CHAIN"
|
||||
</IfModule>
|
||||
EOF
|
||||
fi
|
||||
|
||||
############ RELOAD PROFTPD IF RUNNING
|
||||
pidof proftpd >/dev/null && killall -HUP proftpd
|
|
@ -0,0 +1,37 @@
|
|||
#!/bin/sh
|
||||
|
||||
############ TLS
|
||||
TLS_CERT=${TLS_CERT:-/certs/cert.pem}
|
||||
TLS_KEY=${TLS_KEY:-/certs/privkey.pem}
|
||||
TLS_CHAIN=${TLS_CHAIN:-/certs/chain.pem}
|
||||
|
||||
cat "$TLS_CERT" > /etc/proftpd/cert.pem
|
||||
cat "$TLS_KEY" > /etc/proftpd/privkey.pem
|
||||
cat "$TLS_CHAIN "> /etc/proftpd/chain.pem
|
||||
|
||||
############ CHECK CERT KEY ALGO
|
||||
ALGO=$(openssl x509 -in /etc/proftpd/cert.pem -text | sed -n 's/\ *Public Key Algorithm: //p' | tr '\n')
|
||||
|
||||
############ UPDATE cert config if needed
|
||||
if [ "$ALGO" = "id-ecPublicKey" ] ; then
|
||||
cat > /etc/proftpd/conf.d/certificate.conf <<EOF
|
||||
<IfModule mod_tls.c>
|
||||
TLSECCertificateFile /etc/proftpd/cert.pem
|
||||
TLSECCertificateKeyFile /etc/proftpd/privkey.pem
|
||||
TLSCertificateChainFile /etc/proftpd/chain.pem
|
||||
</IfModule>
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [ "$ALGO" = "rsaEncryption" ] ; then
|
||||
cat > /etc/proftpd/conf.d/certificate.conf <<EOF
|
||||
<IfModule mod_tls.c>
|
||||
TLSRSACertificateFile /etc/proftpd/cert.pem
|
||||
TLSRSACertificateKeyFile /etc/proftpd/privkey.pem
|
||||
TLSCertificateChainFile /etc/proftpd/chain.pem
|
||||
</IfModule>
|
||||
EOF
|
||||
fi
|
||||
|
||||
md5sum "$TLS_CERT" > /app/sums
|
||||
echo "Certificate ready"
|
|
@ -0,0 +1,46 @@
|
|||
#!/bin/sh
|
||||
|
||||
############ IF ACME IS ENABLED, THIS IS THE WRONG SCRIPT
|
||||
if [ ! "$ENABLE_ACME" = "1" ] ; then
|
||||
exit
|
||||
fi
|
||||
|
||||
############ TLS
|
||||
TLS_CERT=${TLS_CERT:-/certs/cert.pem}
|
||||
TLS_KEY=${TLS_KEY:-/certs/privkey.pem}
|
||||
TLS_CHAIN=${TLS_CHAIN:-/certs/chain.pem}
|
||||
|
||||
cat "$TLS_CERT" > /etc/proftpd/cert.pem
|
||||
cat "$TLS_KEY" > /etc/proftpd/privkey.pem
|
||||
cat "$TLS_CHAIN" > /etc/proftpd/chain.pem
|
||||
|
||||
############ IF CERT IS THE SAME, THEN EXIT
|
||||
md5sum -c /app/sums >/dev/null 2>/dev/null && exit
|
||||
|
||||
############ CHECK CERT KEY ALGO
|
||||
ALGO=$(openssl x509 -in /etc/proftpd/cert.pem -text | sed -n 's/\ *Public Key Algorithm: //p' | tr '\n')
|
||||
|
||||
if [ "$ALGO" = "id-ecPublicKey" ] ; then
|
||||
cat > /etc/proftpd/conf.d/certificate.conf <<EOF
|
||||
<IfModule mod_tls.c>
|
||||
TLSECCertificateFile /etc/proftpd/cert.pem
|
||||
TLSECCertificateKeyFile /etc/proftpd/privkey.pem
|
||||
TLSCertificateChainFile /etc/proftpd/chain.pem
|
||||
</IfModule>
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [ "$ALGO" = "rsaEncryption" ] ; then
|
||||
cat > /etc/proftpd/conf.d/certificate.conf <<EOF
|
||||
<IfModule mod_tls.c>
|
||||
TLSRSACertificateFile /etc/proftpd/cert.pem
|
||||
TLSRSACertificateKeyFile /etc/proftpd/privkey.pem
|
||||
TLSCertificateChainFile /etc/proftpd/chain.pem
|
||||
</IfModule>
|
||||
EOF
|
||||
fi
|
||||
|
||||
md5sum "$TLS_CERT" > /app/sums
|
||||
|
||||
############ RELOAD
|
||||
killall -HUP proftpd
|
|
@ -0,0 +1,78 @@
|
|||
#!/bin/sh
|
||||
|
||||
############ CREATE DIRS
|
||||
mkdir -p /auth /logs
|
||||
chown proftpd /auth /logs
|
||||
chmod u+rw /auth /logs
|
||||
chmod g-w /auth /logs
|
||||
|
||||
############ MASQUERADE
|
||||
MASQUERADE=${MASQUERADE:-127.0.0.1}
|
||||
echo "MasqueradeAddress ${MASQUERADE}" > /etc/proftpd/conf.d/masquerade.conf
|
||||
|
||||
############ AUTH
|
||||
[ ! -f /auth/passwd ] && touch /auth/passwd
|
||||
chmod 0600 /auth/passwd
|
||||
chmod 0700 /auth
|
||||
|
||||
############ PASSIVE PORTS
|
||||
PASSIVEPORTS_START=${PASSIVEPORTS_START:-50000}
|
||||
PASSIVEPORTS_END=${PASSIVEPORTS_END:-50050}
|
||||
echo "PassivePorts ${PASSIVEPORTS_START} ${PASSIVEPORTS_END}" > /etc/proftpd/conf.d/passive_ports.conf
|
||||
|
||||
############ MAX CLIENTS
|
||||
MAXCLIENTS=${MAXCLIENTS:-30}
|
||||
MAXCLIENTSPERHOST=${MAXCLIENTSPERHOST:-5}
|
||||
echo "Maxclients ${MAXCLIENTS}" > /etc/proftpd/conf.d/maxclients.conf
|
||||
echo "MaxClientsPerHost ${MAXCLIENTSPERHOST}" >> /etc/proftpd/conf.d/maxclients.conf
|
||||
|
||||
############ CERT INIT
|
||||
ENABLE_ACME=${ENABLE_ACME:-no}
|
||||
|
||||
if [ "$ENABLE_ACME" = "1" ] ; then
|
||||
/app/acme-cert-init.sh
|
||||
else
|
||||
/app/cert-init.sh
|
||||
fi
|
||||
|
||||
############ INIT DB if needed
|
||||
SQLITE_AUTH=${SQLITE_AUTH:-no}
|
||||
if [ "$SQLITE_AUTH" = "1" ] ; then
|
||||
if [ ! -f /auth/ftpd.db ] ; then
|
||||
sqlite3 /auth/ftpd.db < /app/init.sql
|
||||
fi
|
||||
fi
|
||||
|
||||
############ GENERATE RANDOM PASSWORD FOR HEALTHCHECK
|
||||
head /dev/urandom | tr -dc A-Za-z0-9 | head -c 20 > /app/healthcheck.pwd
|
||||
chmod 600 /app/healthcheck.pwd
|
||||
|
||||
############ UPDATE HEALTHCHECK CREDS
|
||||
HEALTHCHECK_UID=1999
|
||||
mkdir -p /home/healthcheck
|
||||
chown ${HEALTHCHECK_UID}:${HEALTHCHECK_UID} /home/healthcheck
|
||||
if [ "$SQLITE_AUTH" = "1" ] ; then
|
||||
PASSWD_SHA=$(cat /app/healthcheck.pwd | mkpasswd -m sha512)
|
||||
sqlite3 /auth/ftpd.db <<EOF
|
||||
INSERT OR IGNORE INTO users (userid,passwd,uid,gid,homedir,shell) VALUES ('healthcheck','',${HEALTHCHECK_UID},${HEALTHCHECK_UID},'/home/healthcheck','/bin/false');
|
||||
INSERT OR IGNORE INTO groups (groupname,gid,members) VALUES ('healthcheck',${HEALTHCHECK_UID},'healthcheck');
|
||||
UPDATE users SET passwd='$PASSWD_SHA' WHERE userid='healthcheck';
|
||||
EOF
|
||||
else
|
||||
cat /app/healthcheck.pwd | ftpasswd --stdin --passwd --name=healthcheck \
|
||||
--uid=${HEALTHCHECK_UID} \
|
||||
--home=/home/healthcheck --sha512 --shell=/bin/false --file=/auth/passwd
|
||||
fi
|
||||
|
||||
############ CONFIGURE AUTH
|
||||
if [ "$SQLITE_AUTH" = "1" ] ; then
|
||||
echo "AuthOrder mod_sql.c" > /etc/proftpd/conf.d/auth.conf
|
||||
else
|
||||
echo "AuthOrder mod_auth_file.c" > /etc/proftpd/conf.d/auth.conf
|
||||
fi
|
||||
|
||||
############ START CRON
|
||||
crond -b
|
||||
|
||||
############ START
|
||||
proftpd -n
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/sh
|
||||
|
||||
USER=healthcheck
|
||||
LFTP_PASSWORD=$(cat /app/healthcheck.pwd)
|
||||
|
||||
lftp -e "set ssl-allow true; set ftp:ssl-force true; set ftp:passive-mode true; set ssl:verify-certificate false; set net:timeout 5; set net:max-retries 1; open -u ${USER},${LFTP_PASSWORD} ftp://127.0.0.1; ls; bye" > /dev/null
|
||||
echo $?
|
|
@ -0,0 +1,14 @@
|
|||
CREATE TABLE `users` (
|
||||
userid VARCHAR(30) NOT NULL UNIQUE,
|
||||
passwd VARCHAR(80) NOT NULL,
|
||||
uid INTEGER UNIQUE,
|
||||
gid INTEGER,
|
||||
homedir VARCHAR(255),
|
||||
shell VARCHAR(255),
|
||||
last_accessed DATETIME
|
||||
);
|
||||
CREATE TABLE `groups` (
|
||||
groupname VARCHAR(30) NOT NULL UNIQUE,
|
||||
gid INTEGER NOT NULL,
|
||||
members VARCHAR(255)
|
||||
);
|
|
@ -0,0 +1,38 @@
|
|||
#!/bin/sh
|
||||
|
||||
############ FILES
|
||||
|
||||
TLS_CERT=/acme/cert/cert.pem
|
||||
TLS_KEY=/acme/cert/privkey.pem
|
||||
TLS_CHAIN=/acme/cert/chain.pem
|
||||
|
||||
[ ! -f "$TLS_CERT" ] && exit 1
|
||||
[ ! -f "$TLS_KEY" ] && exit 1
|
||||
[ ! -f "$TLS_CHAIN" ] && exit 1
|
||||
|
||||
############ CHECK CERT KEY ALGO
|
||||
ALGO=$(openssl x509 -in "$TLS_CERT" -text | sed -n 's/\ *Public Key Algorithm: //p' | tr '\n')
|
||||
|
||||
############ UPDATE cert config if needed
|
||||
if [ "$ALGO" = "id-ecPublicKey" ] ; then
|
||||
cat > /etc/proftpd/conf.d/certificate.conf <<EOF
|
||||
<IfModule mod_tls.c>
|
||||
TLSECCertificateFile "$TLS_CERT"
|
||||
TLSECCertificateKeyFile "$TLS_KEY"
|
||||
TLSCertificateChainFile "$TLS_CHAIN"
|
||||
</IfModule>
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [ "$ALGO" = "rsaEncryption" ] ; then
|
||||
cat > /etc/proftpd/conf.d/certificate.conf <<EOF
|
||||
<IfModule mod_tls.c>
|
||||
TLSRSACertificateFile "$TLS_CERT"
|
||||
TLSRSACertificateKeyFile "$TLS_KEY"
|
||||
TLSCertificateChainFile "$TLS_CHAIN"
|
||||
</IfModule>
|
||||
EOF
|
||||
fi
|
||||
|
||||
############ RELOAD PROFTPD IF RUNNING
|
||||
pidof proftpd >/dev/null && killall -HUP proftpd
|
|
@ -0,0 +1 @@
|
|||
../../../app/acme-cron.sh
|
|
@ -0,0 +1 @@
|
|||
../../../app/cron.sh
|
|
@ -0,0 +1,49 @@
|
|||
AuthUserFile /auth/passwd
|
||||
RequireValidShell off
|
||||
ScoreBoardFile /run/proftpd/scoreboard
|
||||
AllowOverwrite on
|
||||
AllowStoreRestart On
|
||||
AllowRetrieveRestart On
|
||||
WtmpLog off
|
||||
UseReverseDNS off
|
||||
DefaultRoot ~
|
||||
|
||||
<IfModule mod_tls.c>
|
||||
TLSEngine on
|
||||
TLSVerifyClient off
|
||||
TLSRenegotiate none
|
||||
TLSProtocol TLSv1.2 TLSv1.3
|
||||
TLSOptions NoSessionReuseRequired AllowClientRenegotiations
|
||||
TLSRequired on
|
||||
</IfModule>
|
||||
|
||||
<IfModule mod_delay.c>
|
||||
DelayOnEvent FailedLogin 5s
|
||||
DelayTable /run/proftpd/proftpd.delay
|
||||
</IfModule>
|
||||
|
||||
<IfModule mod_deflate.c>
|
||||
DeflateEngine on
|
||||
</IfModule>
|
||||
|
||||
<IfModule mod_sql.c>
|
||||
<IfModule mod_sql_sqlite.c>
|
||||
SQLBackend sqlite3
|
||||
SQLConnectInfo /auth/ftpd.db
|
||||
SQLEngine On
|
||||
SQLAuthenticate users
|
||||
SQLAuthTypes OpenSSL Crypt
|
||||
SQLUserInfo users userid passwd uid gid homedir shell
|
||||
SQLGroupInfo groups groupname gid members
|
||||
|
||||
SQLNamedQuery last_accessed UPDATE "last_accessed = DATETIME('now') WHERE userid='%u'" users
|
||||
SQLLog PASS last_accessed
|
||||
SQLMinId 33
|
||||
SQLDefaultUID 33
|
||||
SQLDefaultGID 33
|
||||
|
||||
RequireValidShell off
|
||||
</IfModule>
|
||||
</IfModule>
|
||||
|
||||
Include /etc/proftpd/custom.conf.d/
|
|
@ -0,0 +1,56 @@
|
|||
# This is the directory where DSO modules reside
|
||||
ModulePath /usr/lib/proftpd
|
||||
|
||||
# Allow only user root to load and unload modules, but allow everyone
|
||||
# to see which modules have been loaded
|
||||
ModuleControlsACLs insmod,rmmod allow user root
|
||||
ModuleControlsACLs lsmod allow user *
|
||||
|
||||
Include /etc/proftpd/modules.d/
|
||||
|
||||
ServerName "ProFTPD Default Installation"
|
||||
ServerType standalone
|
||||
|
||||
# Port 21 is the standard FTP port.
|
||||
Port 21
|
||||
|
||||
# Don't use IPv6 support by default.
|
||||
UseIPv6 off
|
||||
|
||||
# Umask 022 is a good standard umask to prevent new dirs and files
|
||||
# from being group and world writable.
|
||||
Umask 022
|
||||
|
||||
# To prevent DoS attacks, set the maximum number of child processes
|
||||
# to 30. If you need to allow more than 30 concurrent connections
|
||||
# at once, simply increase this value. Note that this ONLY works
|
||||
# in standalone mode, in inetd mode you should use an inetd server
|
||||
# that allows you to limit maximum number of processes per service
|
||||
# (such as xinetd).
|
||||
MaxInstances 30
|
||||
|
||||
# Set the user and group under which the server will run.
|
||||
User proftpd
|
||||
Group proftpd
|
||||
|
||||
# To cause every FTP user to be "jailed" (chrooted) into their home
|
||||
# directory, uncomment this line.
|
||||
#DefaultRoot ~
|
||||
|
||||
# Normally, we want files to be overwriteable.
|
||||
AllowOverwrite on
|
||||
|
||||
DefaultServer on
|
||||
ShowSymlinks on
|
||||
|
||||
TimeoutNoTransfer 600
|
||||
TimeoutStalled 600
|
||||
TimeoutIdle 1200
|
||||
|
||||
DisplayLogin welcome.msg
|
||||
DisplayChdir .message true
|
||||
ListOptions "-l"
|
||||
|
||||
DenyFilter \*.*/
|
||||
|
||||
Include /etc/proftpd/conf.d/
|
|
@ -0,0 +1,4 @@
|
|||
# valid login shells
|
||||
/bin/sh
|
||||
/bin/ash
|
||||
/bin/false
|
34
run.sh
34
run.sh
|
@ -1,34 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
############ MASQUERADE
|
||||
|
||||
MASQUERADE=${MASQUERADE:-127.0.0.1}
|
||||
echo "MasqueradeAddress ${MASQUERADE}" > /etc/proftpd/conf.d/masquerade.conf
|
||||
|
||||
############ AUTH
|
||||
|
||||
[ ! -f /auth/passwd ] && touch /auth/passwd
|
||||
|
||||
chmod 0600 /auth/passwd
|
||||
chmod 0700 /auth
|
||||
|
||||
############ TLS
|
||||
|
||||
TLS_CERT=${TLS_CERT:-/certs/cert.pem}
|
||||
TLS_KEY=${TLS_KEY:-/certs/privkey.pem}
|
||||
TLS_CHAIN=${TLS_CHAIN:-/certs/chain.pem}
|
||||
|
||||
cat $TLS_CERT > /etc/proftpd/cert.pem
|
||||
cat $TLS_KEY > /etc/proftpd/privkey.pem
|
||||
cat $TLS_CHAIN > /etc/proftpd/chain.pem
|
||||
|
||||
############ PASSIVE PORTS
|
||||
|
||||
PASSIVEPORTS_START=${PASSIVEPORTS_START:-50000}
|
||||
PASSIVEPORTS_END=${PASSIVEPORTS_END:-50050}
|
||||
|
||||
echo "PassivePorts ${PASSIVEPORTS_START} ${PASSIVEPORTS_END}" > /etc/proftpd/conf.d/passive_ports.conf
|
||||
|
||||
############ START
|
||||
|
||||
proftpd -n
|
Loading…
Reference in New Issue