Skip to content

Commit

Permalink
Initial FTP Server
Browse files Browse the repository at this point in the history
  • Loading branch information
haravich committed Aug 15, 2023
0 parents commit 1ed41e5
Show file tree
Hide file tree
Showing 9 changed files with 443 additions and 0 deletions.
29 changes: 29 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Use the Alpine base image
FROM alpine:latest

LABEL Maintainer="Hariprasath Ravichandran"

# Install vsftpd and other necessary packages
RUN apk update && apk add --no-cache openssl vsftpd bash && rm -rf /var/cache/apk/*

# Create an FTP user and set their password
RUN adduser -D ftpuser
RUN echo "ftpuser:admin" | chpasswd

RUN mkdir -p /home/vsftpd/
RUN mkdir -p /var/log/vsftpd
RUN chown -R ftp:ftp /home/vsftpd/

# Copy vsftpd configuration files
COPY *.conf /etc/vsftpd/

# Copy the password change script
COPY run-vsftpd.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/run-vsftpd.sh
RUN mkdir -p /var/log/vsftpd && chown ftp:ftp /var/log/vsftpd

# Expose FTP port
EXPOSE 20 21 21100-21110

# Start vsftpd service
ENTRYPOINT ["/usr/local/bin/run-vsftpd.sh"]
13 changes: 13 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
MIT License

Copyright (c) [2023] [Hariprasath Ravichandran]

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Copyright (C) 2020 Logan HAUSPIE

The original LICENSE can be found in [lhauspie/docker-vsftpd-alpine](https://github.com/lhauspie/docker-vsftpd-alpine/blob/develop/LICENCE)
101 changes: 101 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# FTP Server in Docker based on Alpine Linux

This repository contains a Docker configuration to set up an FTP server using the Alpine Linux base image. The FTP server supports the following modes
* FTP (Port 21)
* FTPS (Port 21) AKA Explicit
* FTPS Implicit (Port 990)
* FTPS TLS (Port 21) AKA Explicit with strong cipher

## Prerequisites

Before you begin, ensure you have the following installed:

- Docker: Follow the official [Docker installation guide](https://docs.docker.com/get-docker/) to install Docker on your system.

## Getting Started

1. **Clone the Repository**:

Clone this repository to your local machine:

```bash
git clone https://github.com/haravich/custom-ftp-server.git
cd custom-ftp-server
```

2. **Customize Configuration**:

Configure FTP Server:
- Modify the `vsftpd-<FTP_MODE>.conf` file to customize the FTP server configuration. You can adjust settings such as user accounts, directory permissions, passive ports range, and security options.

Default:
- By default the `vsftpd.conf` is enabled with required configuration for specific modes.

3. **Generate SSL Certificate:**

Generate an SSL certificate and private key for FTPS if you plan to use secure connections. We do apply a default certficate is the environment variable `SSL_SUBJECT` not provided.

```bash
SSL_SUBJECT="/C=IN/O=haravich/CN=freeops.dev"
```

4. **Build and Run**:

Build the Docker image and run the container:

```bash
docker build -t custom-ftp-server .
docker run -d -p 2222:22 -p 20-22:20-22 -p 21100-21110:21100-21110 -p 990:990 custom-ftp-server
(or)
docker run -d -p 2222:22 -e FTP_MODE=ftps -e -p 20-22:20-22 -p 21100-21110:21100-21110 -p 990:990 custom-ftp-server
(or)
docker run -d -p 2222:22 -e FTP_MODE=ftps -e SSL_SUBJECT="/C=IN/O=haravich/CN=freeops.dev" -p 20-22:20-22 -p 21100-21110:21100-21110 -p 990:990 custom-ftp-server
```

### Environment Variables

| Variable | Default Value | Available Options |
|----------|----------|----------|
| FTP_USER | `ftpuser` | (string) `name` |
| FTP_PASSWORD | `admin` | (string) `password` |
| PASV_ENABLE | `YES` | (bool) `YES`/`NO` |
| PASV_ADDRESS | - | (Valid IP Address) `x.x.x.x` |
| PASV_ADDRESS_INTERFACE | `eth0` | (Vlaid ETH interface) `xth1` |
| PASV_ADDR_RESOLVE | `YES` | (bool) `YES`/`NO` |
| PASV_MIN_PORT | `21100` | (Port) `Any valid port` |
| PASV_MAX_PORT | `21110` | (Port) `Any valid port` |
| FTP_MODE | `ftp` | (string) `ftp`/`ftps`/`ftps_implicit`/`ftps_tls` |
| LOG_STDOUT | `YES` | (bool) `YES`/`NO` |
| SSL_SUBJECT | - | (string) `/C=IN/O=haravich/CN=freeops.dev` |

## Access FTP Server:

Connect to the FTP server using an FTP client. Use the ftpuser username and the password. For secure FTPS connections, connect to port 21 and choose "FTP with TLS/SSL" or "FTPES" as the protocol.

```bash
ftp -p 22 <ftp_user>@localhost
```
Replace <ftp_user> with appropriate values.

## Customization
* Adjust the FTP server settings in the vsftpd file.
* Customize the run-vsftpd.sh script to modify for further configs.

## License
This project is licensed under the [MIT License](LICENSE.md). See the [LICENSE.md](LICENSE.md) file for details.
```
Copy and paste this Markdown content into a file named README.md in the root of your repository. Feel free to adjust the formatting and content as needed for your project.
```
## Credits
### lhauspie/docker-vsftpd-alpine
The core config files is created and maintained by [Logan HAUSPIE](https://github.com/lhauspie). The source code can be found in [Github](https://github.com/lhauspie/docker-vsftpd-alpine).
The original LICENSE can be found in [lhauspie/docker-vsftpd-alpine](https://github.com/lhauspie/docker-vsftpd-alpine/blob/develop/LICENCE)
117 changes: 117 additions & 0 deletions run-vsftpd.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#!/bin/bash

# Fetch password, and public key from environment variables
FTP_USER="${FTP_USER:-ftpuser}"
FTP_PASSWORD="${FTP_PASSWORD:-admin}"
PASV_ENABLE="${PASV_ENABLE:-YES}"
PASV_ADDRESS="${PASV_ADDRESS:-}"
PASV_ADDRESS_INTERFACE="${PASV_ADDRESS_INTERFACE:-eth0}"
PASV_ADDR_RESOLVE="${PASV_ADDR_RESOLVE:-YES}"
PASV_MIN_PORT="${PASV_MIN_PORT:-21100}"
PASV_MAX_PORT="${PASV_MAX_PORT:-21110}"
FTP_MODE="${FTP_MODE:-ftp}"
LOG_STDOUT="${LOG_STDOUT:-YES}"
SSL_SUBJECT="${SSL_SUBJECT:-}"

# GENERATE SELF-SIGNED CERT
if [ -z "$SSL_SUBJECT" ]; then
openssl req -x509 -nodes -days 365 \
-newkey rsa:2048 -keyout /etc/vsftpd/vsftpd.pem -out /etc/vsftpd/vsftpd.pem \
-subj "/C=IN/O=FTP/CN=ftp.docker.local"
else
openssl req -x509 -nodes -days 365 \
-newkey rsa:2048 -keyout /etc/vsftpd/vsftpd.pem -out /etc/vsftpd/vsftpd.pem \
-subj "$SSL_SUBJECT"
fi

# Change FTP user's password
if [ -n "$FTP_PASSWORD" ]; then
echo "$FTP_USER:$FTP_PASSWORD" | chpasswd
fi

# You can set PASV_ADDRESS_INTERFACE to the name of the interface you'd like to
# bind to and this will look up the IP and set the proper PASV_ADDRESS value.
if [ -z "$PASV_ADDRESS" ]; then
echo "PASV_ADDRESS env variable is not set"
if [ -n "$PASV_ADDRESS_INTERFACE" ]; then
echo "attempt to guess the PASV_ADDRESS from PASV_ADDRESS_INTERFACE"
PASV_ADDRESS=$(ip -o -4 addr list $PASV_ADDRESS_INTERFACE | head -n1 | awk '{print $4}' | cut -d/ -f1)
if [ -z "$PASV_ADDRESS" ]; then
echo "Could not find IP for interface '$PASV_ADDRESS_INTERFACE', exiting"
exit 1
fi
echo "==> Found address '$PASV_ADDRESS' for interface '$PASV_ADDRESS_INTERFACE', setting PASV_ADDRESS env variable..."
fi
else
echo "PASV_ADDRESS is set so we use it directly"
fi

# Add the FTP_USER, change his password and declare him as the owner of his home folder and all subfolders
addgroup -g 433 -S $FTP_USER
adduser -u 431 -D -G $FTP_USER -h /home/vsftpd/$FTP_USER -s /bin/false $FTP_USER
chown -R $FTP_USER:$FTP_USER /home/vsftpd/

# Building the configuration file
VSFTPD_CONF=/etc/vsftpd/vsftpd.conf
more /etc/vsftpd/vsftpd-base.conf > $VSFTPD_CONF

if [[ "$FTP_MODE" =~ ^(ftp|ftps|ftps_implicit|ftps_tls)$ ]]; then
echo "FTP mode is $FTP_MODE"
echo "" >> $VSFTPD_CONF
more /etc/vsftpd/vsftpd-${FTP_MODE}.conf >> $VSFTPD_CONF
else
echo "$FTP_MODE is not a supported FTP mode"
echo "FTP_MODE env var must be ftp, ftps, ftps_implicit or ftps_tls"
echo "exiting"
exit 1
fi

# Update the vsftpd-ftp.conf according to env variables
echo "Update the vsftpd.conf according to env variables"
echo "" >> $VSFTPD_CONF
echo "# the following lines are added through auto config on container startup" >> $VSFTPD_CONF
echo "anonymous_enable=NO" >> $VSFTPD_CONF
echo "pasv_enable=$PASV_ENABLE" >> $VSFTPD_CONF
echo "pasv_address=$PASV_ADDRESS" >> $VSFTPD_CONF
echo "pasv_addr_resolve=$PASV_ADDR_RESOLVE" >> $VSFTPD_CONF
echo "pasv_max_port=$PASV_MAX_PORT" >> $VSFTPD_CONF
echo "pasv_min_port=$PASV_MIN_PORT" >> $VSFTPD_CONF
echo "" >> $VSFTPD_CONF

# Get log file path
export LOG_FILE=`grep ^vsftpd_log_file $VSFTPD_CONF | cut -d= -f2`

cat << EOF
********************************************************
* *
* Docker image: haravich/custom-ftpd-server *
* https://github.com/haravich/custom-ftpd-server *
* *
********************************************************
SERVER SETTINGS
---------------
. FTP_USER: "${FTP_USER}"
. FTP_PASSWORD: "${FTP_PASSWORD}"
. PASV_ENABLE: "${PASV_ENABLE}"
. PASV_ADDRESS: "${PASV_ADDRESS}"
. PASV_ADDRESS_INTERFACE: "${PASV_ADDRESS_INTERFACE}"
. PASV_ADDR_RESOLVE: "${PASV_ADDR_RESOLVE}"
. PASV_MIN_PORT: "${PASV_MIN_PORT}"
. PASV_MAX_PORT: "${PASV_MAX_PORT}"
. FTP_MODE: "${FTP_MODE}"
. LOG_STDOUT: "${LOG_STDOUT}"
. LOG_FILE: "${LOG_FILE}"
EOF

if [[ "${LOG_STDOUT}" == "YES" ]]; then
touch ${LOG_FILE}
tail -f ${LOG_FILE} >> /dev/stdout &
elif [[ "${LOG_STDOUT}" != "NO" ]]; then
echo "LOG_STDOUT available options are 'YES' or 'NO'"
exit 1
fi

# Run the vsftpd server
echo "Running vsftpd"
/usr/sbin/vsftpd $VSFTPD_CONF
Loading

0 comments on commit 1ed41e5

Please sign in to comment.