Skip to content

Commit 4ee5736

Browse files
init
0 parents  commit 4ee5736

File tree

12 files changed

+254
-0
lines changed

12 files changed

+254
-0
lines changed

.github/workflows/docker.yml

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
name: Build
2+
on:
3+
push:
4+
branches: ["master"]
5+
paths:
6+
- "docker-compose.yml"
7+
- "docker/**"
8+
- ".github/workflows/**"
9+
pull_request:
10+
branches: ["master"]
11+
paths:
12+
- "docker-compose.yml"
13+
- "docker/**"
14+
- ".github/workflows/**"
15+
16+
env:
17+
REGISTRY: ghcr.io
18+
LATEST_TAG: ghcr.io/rootshell-coder/proftpd:latest
19+
TRIVY_SECURITY: SECURITY.txt
20+
21+
jobs:
22+
build:
23+
name: Publish to github registry
24+
runs-on: [ubuntu-24.04]
25+
steps:
26+
- name: Checkout
27+
uses: actions/checkout@v4
28+
- name: Set up QEMU
29+
uses: docker/setup-qemu-action@v3
30+
- name: Set up Docker Buildx
31+
uses: docker/setup-buildx-action@v3
32+
- name: Login to GHCR
33+
uses: docker/login-action@v3
34+
with:
35+
registry: ${{ env.REGISTRY }}
36+
username: ${{ github.actor }}
37+
password: ${{ secrets.GITHUB_TOKEN }}
38+
- name: Build and push
39+
uses: docker/build-push-action@v5
40+
with:
41+
context: docker
42+
push: true
43+
platforms: linux/amd64,linux/arm64
44+
tags: |
45+
${{ env.LATEST_TAG }}
46+
47+
check:
48+
needs: [build]
49+
name: Check Trivy
50+
runs-on: [ubuntu-24.04]
51+
steps:
52+
- uses: actions/checkout@v4
53+
- name: Check Trivy
54+
run: |
55+
docker pull ${{ env.LATEST_TAG }}
56+
docker run --rm ghcr.io/rootshell-coder/trivy-cached:latest image ${{ env.LATEST_TAG }} --skip-db-update > ${{ env.TRIVY_SECURITY }}
57+
58+
- name: Commit changes
59+
uses: EndBug/add-and-commit@v9
60+
with:
61+
author_name: RootShell-coder
62+
author_email: [email protected]
63+
message: "trivy"
64+
add: "*.txt"

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*build

Readme.md

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Proftpd
2+
3+
- The `mod_exec` module in ProFTPD allows the execution of external programs or scripts in response to various FTP commands such as STOR, RETR, QUIT, and others. This module is useful for integrating the FTP server with other systems or for performing arbitrary actions in response to user actions, such as uploading or downloading files.
4+
5+
- The `mod_lang` module in ProFTPD allows you to configure support for different languages for messages displayed to the user when interacting with the FTP server. This module is used for localization and translation of standard error messages, warnings, and other text that is output to the client during FTP sessions.
6+
7+
---
8+
9+
## Environments
10+
11+
PROFTPD_USER: "`<user>`:`<password>`:`<uid>`:`<gid>`"
12+
13+
PROFTPD_MASQUERADE_ADDRESS: "`proftpd`" usually only the service name is enough
14+
15+
PROFTPD_PASSIVE_PORTS: "`30000-30100`" FTP passive ports
16+
17+
TZ: "`Europe/London`" Timezone
18+
19+
LANG: "`en_GB.UTF8`" Locale
20+
21+
LC_ALL: "`en_GB.UTF-8`"
22+
23+
## Processing
24+
25+
The `mod_exec` module actively uses the `processing` file. When the STOR event is triggered, it writes a `.mod_exec.test` file in the user's home directory with the following content: `127.0.0.1 user1 /home/user1/new file.txt STOR`. Configured in the `exec.conf` file.
26+
27+
### exec.conf
28+
29+
```conf
30+
<IfModule mod_exec.c>
31+
ExecEngine on
32+
ExecLog /var/log/proftpd/exec.log
33+
ExecOnCommand STOR /usr/local/bin/processing %a %u %f %m %b
34+
</IfModule>
35+
36+
```
37+
38+
---
39+
40+
Users are locked into their home directories with `Limit`, but this is not a `chroot` directory.

docker-compose.yml

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
volumes:
3+
proftpd-home:
4+
name: "proftpd-home"
5+
6+
services:
7+
proftpd:
8+
image: "ghcr.io/rootshell-coder/proftpd:latest"
9+
network_mode: "host"
10+
volumes:
11+
- "./docker/processing:/usr/local/bin/processing"
12+
- "proftpd-home:/home:rw"
13+
environment:
14+
PROFTPD_USER: "user1:password1:1001:1001, user2:password2:1002:1002"
15+
PROFTPD_MASQUERADE_ADDRESS: "proftpd"
16+
PROFTPD_PASSIVE_PORTS: "30000-30100"
17+
TZ: "Europe/Moscow"
18+
LANG: "ru_RU.UTF8"
19+
LC_ALL: "ru_RU.UTF-8"
20+
restart: "always"
21+
deploy:
22+
resources:
23+
limits:
24+
cpus: "1.0"
25+
memory: "1024M"
26+
reservations:
27+
cpus: "0.64"
28+
memory: "512M"

docker/Dockerfile

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
FROM alpine:latest
2+
3+
RUN set -eux; \
4+
apk add --no-cache \
5+
shadow \
6+
musl \
7+
musl-locales-lang \
8+
musl-utils \
9+
musl-locales \
10+
tzdata \
11+
proftpd \
12+
proftpd-mod_lang \
13+
proftpd-mod_site_misc \
14+
proftpd-mod_rewrite \
15+
proftpd-mod_exec \
16+
proftpd-mod_sftp \
17+
proftpd-mod_unique_id \
18+
proftpd-mod_readme \
19+
proftpd-utils; \
20+
mkdir -p /var/run/proftpd/; \
21+
sed -i 's/ProFTPD Default Installation/ProFTPD/' /etc/proftpd/proftpd.conf; \
22+
sed -i 's/^MultilineRFC2228/#MultilineRFC2228/' /etc/proftpd/proftpd.conf; \
23+
sed -i '/^#MultilineRFC2228/a WtmpLog off' /etc/proftpd/proftpd.conf; \
24+
sed -i '/^Port/a PassivePorts 30000 30100' /etc/proftpd/proftpd.conf; \
25+
sed -i '/^DenyFilter/a MasqueradeAddress 127.0.0.1' /etc/proftpd/proftpd.conf; \
26+
sed -i '/^MasqueradeAddress/a SysLogLevel error' /etc/proftpd/proftpd.conf; \
27+
sed -i '/^SysLogLevel/a SystemLog /var/log/proftpd/proftpd.log' /etc/proftpd/proftpd.conf; \
28+
sed -i '/^SystemLog/a TransferLog /var/log/proftpd/xfer.log' /etc/proftpd/proftpd.conf;
29+
30+
ADD entrypoint /usr/bin/entrypoint
31+
ADD processing /usr/local/bin/processing
32+
ADD conf.d /etc/proftpd/conf.d
33+
RUN chmod +x /usr/bin/entrypoint
34+
35+
EXPOSE 21
36+
ENTRYPOINT ["entrypoint"]

docker/conf.d/delay.conf

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<IfModule mod_delay.c>
2+
DelayEngine on
3+
</IfModule>

docker/conf.d/exec.conf

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<IfModule mod_exec.c>
2+
ExecEngine on
3+
ExecLog /var/log/proftpd/exec.log
4+
ExecOnCommand STOR /usr/local/bin/processing %a %u %f %m %b
5+
</IfModule>

docker/conf.d/lang.conf

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<IfModule mod_lang.c>
2+
LangEngine on
3+
UseEncoding on
4+
LangDefault ru_RU
5+
LangPath /usr/share/locale
6+
UseEncoding utf8 cp1251
7+
8+
<Directory /usr/share/locale/*>
9+
<Limit READ>
10+
AllowAll
11+
</Limit>
12+
</Directory>
13+
14+
</IfModule>

docker/conf.d/limit.conf

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<Directory />
2+
<Limit ALL>
3+
DenyAll
4+
</Limit>
5+
</Directory>
6+
7+
<Directory /home/%u>
8+
<Limit ALL>
9+
AllowUser %u
10+
</Limit>
11+
</Directory>

docker/conf.d/sftp.conf

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<IfModule mod_sftp.c>
2+
SFTPEngine off
3+
# Port 2222
4+
# SFTPLog /var/log/proftpd/sftp.log
5+
# SFTPHostKey /etc/ssh/ssh_host_rsa_key
6+
# SFTPHostKey /etc/ssh/ssh_host_dsa_key
7+
# SFTPAuthMethods publickey
8+
# SFTPAuthorizedUserKeys file:/etc/proftpd/authorized_keys/%u
9+
# SFTPCompression delayed
10+
</IfModule>

docker/entrypoint

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#!/bin/sh
2+
3+
if [ -z "${PROFTPD_USER}" ]; then
4+
echo "The USER variable is not set or empty."
5+
exit 1
6+
fi
7+
8+
USER=$(echo "$PROFTPD_USER" | sed 's/[[:space:]]//g')
9+
users=$(echo "$USER" | tr ',' '\n')
10+
for user in $users; do
11+
set -- $(echo "$user" | tr ':' ' ')
12+
login=$1; password=$2; uid=$3; gid=$4
13+
adduser --disabled-password --gecos "" --uid "$uid" "$login"
14+
echo "$login:$password" | chpasswd
15+
if [ ! -z "$gid" ]; then
16+
addgroup --system "$gid" || true
17+
adduser "$login" "$gid"
18+
fi
19+
usermod -aG proftpd "$login"
20+
done
21+
22+
if [[ -n "${PROFTPD_PASSIVE_PORTS}" ]]; then
23+
set -- $(echo "$PROFTPD_PASSIVE_PORTS" | tr '-' ' ')
24+
sed -i "s/^PassivePorts.*$/PassivePorts $1 $2/" /etc/proftpd/proftpd.conf
25+
fi
26+
27+
if [[ -n "${PROFTPD_MASQUERADE_ADDRESS}" ]]; then
28+
sed -i "s/^MasqueradeAddress.*$/MasqueradeAddress ${PROFTPD_MASQUERADE_ADDRESS}/" /etc/proftpd/proftpd.conf
29+
fi
30+
31+
if [[ -n "${LANG}" ]]; then
32+
lang=$(echo "$LANG" | cut -d. -f1)
33+
sed -i "s/LangDefault.*$/LangDefault $lang/" /etc/proftpd/conf.d/lang.conf
34+
fi
35+
36+
chown proftpd:proftpd /usr/local/bin/processing > dev/null 2>&1
37+
chmod chmod a+x /usr/local/bin/processing > dev/null 2>&1
38+
39+
/usr/sbin/proftpd -n -p /var/run/proftpd.pid -c /etc/proftpd/proftpd.conf

docker/processing

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/bin/sh
2+
set -eux
3+
echo "${1} ${2} ${3} ${4}" >> /home/${2}/.mod_exec.test

0 commit comments

Comments
 (0)