📁 Lightweight Alpine-based FTP server with anonymous access for file uploads and downloads 🚀
1.6K
A lightweight Docker container running an FTP server with anonymous access for file uploads and downloads, built on Alpine Linux for minimal footprint. 🚀
GitHub Repository: logical-and/ftp-anon
docker run -it --rm -p 21:21 -p 30000-30100:30000-30100 andspace/ftp-anon
port=2121; pasv_from=$((port+1)); pasv_to=$((port+10)); \
docker run -it --rm \
-v $(pwd):/var/ftp/public \
-p "$port":"$port" \
-p "$pasv_from"-"$pasv_to":"$pasv_from"-"$pasv_to" \
-e PORT="$port" \
-e PASSIVE_MIN_PORT="$pasv_from" \
-e PASSIVE_MAX_PORT="$pasv_to" \
-e LOG_LEVEL=MINIMAL \
andspace/ftp-anon
docker run -it --rm \
-p 2121:2121 -p 35000-35100:35000-35100 \
-v $(pwd):/var/ftp/public \
-e EXTERNAL_IP=192.168.1.100 \
-e PORT=2121 \
-e PASSIVE_ENABLE=YES \
-e PASSIVE_MIN_PORT=35000 \
-e PASSIVE_MAX_PORT=35100 \
-e FTP_UID=1000 \
-e FTP_GID=1000 \
-e LOCAL_UMASK=022 \
-e MAX_CLIENTS=50 \
-e MAX_PER_IP=5 \
-e IDLE_TIMEOUT=600 \
-e DATA_TIMEOUT=120 \
-e TTL=10 \
-e LISTEN_ADDRESS= \
-e MAX_UPLOAD_RATE=0 \
-e MAX_DOWNLOAD_RATE=0 \
-e MAX_FILE_SIZE=0 \
-e ALLOW_DELETE=YES \
-e ALLOW_OVERWRITE=YES \
-e DIR_UMASK=022 \
-e LOG_LEVEL=VERBOSE \
-e BANNER_TEXT="Custom Welcome Message" \
-e ASCII_MODE=YES \
-e USE_SENDFILE=YES \
andspace/ftp-anon
| Variable | Default | Description |
|---|---|---|
EXTERNAL_IP | auto-detect | External IP address for passive mode |
PORT | 21 | FTP control port |
PASSIVE_ENABLE | YES | Enable/disable passive mode (YES/NO) |
PASSIVE_MIN_PORT | 30000 | Minimum passive mode port |
PASSIVE_MAX_PORT | 30100 | Maximum passive mode port |
FTP_UID | 21 | User ID for FTP file ownership |
FTP_GID | 21 | Group ID for FTP file ownership |
LOCAL_UMASK | 022 | File creation umask |
| Variable | Default | Description |
|---|---|---|
MAX_CLIENTS | 50 | Maximum simultaneous connections |
MAX_PER_IP | 5 | Maximum connections from same IP |
IDLE_TIMEOUT | 600 | Session idle timeout (seconds) |
DATA_TIMEOUT | 120 | Data connection timeout (seconds) |
TTL | 10 | Server lifetime in minutes (auto-shutdown for security) |
LISTEN_ADDRESS | all | Specific IP to bind to |
| Variable | Default | Description |
|---|---|---|
MAX_UPLOAD_RATE | 0 | Upload speed limit (bytes/sec, 0=unlimited) |
MAX_DOWNLOAD_RATE | 0 | Download speed limit (bytes/sec, 0=unlimited) |
MAX_FILE_SIZE | 0 | Maximum file size for uploads (bytes, 0=unlimited) |
| Variable | Default | Description |
|---|---|---|
ALLOW_DELETE | YES | Allow anonymous users to delete files (YES/NO) |
ALLOW_OVERWRITE | YES | Allow overwriting existing files (YES/NO) |
DIR_UMASK | 022 | Directory creation umask |
| Variable | Default | Description |
|---|---|---|
LOG_LEVEL | VERBOSE | Log verbosity (MINIMAL/VERBOSE) |
BANNER_TEXT | auto-generated | Custom welcome banner message |
| Variable | Default | Description |
|---|---|---|
ASCII_MODE | YES | Enable ASCII transfer mode (YES/NO) |
USE_SENDFILE | YES | Use sendfile for better performance (YES/NO) |
anonymous, Password: (any email or leave blank)/public directory to upload filesWhen you connect via FTP, you'll see a clean, environment-aware banner:
Welcome to Anonymous FTP Server! 🎉 | 📁 Upload to /public/ | 🌐 Server: 203.0.113.1 | 💾 Happy file sharing!
The banner automatically includes relevant environment information like server IP, custom ports, or TTL when they differ from defaults.
When the server starts, you'll see complete connection information in the logs:
[2025-08-14 17:36:17] [INFO] === 🚀 FTP Server Started Successfully! ===
[2025-08-14 17:36:17] [INFO]
[2025-08-14 17:36:17] [INFO] 📋 Connection Information:
[2025-08-14 17:36:17] [INFO] 🌐 Server IP: 203.0.113.1
[2025-08-14 17:36:17] [INFO] 🔌 Port: 2121
[2025-08-14 17:36:17] [INFO] 🔗 Quick Connect URL: ftp://[email protected]:2121/public/
[2025-08-14 17:36:17] [INFO] 👤 Username: anonymous
[2025-08-14 17:36:17] [INFO] 🔑 Password: (any email address or leave blank)
[2025-08-14 17:36:17] [INFO] 📂 Upload directory: /public/
# Using command-line FTP client
ftp <server-ip> 2121
# Username: anonymous
# Password: (press enter or type any email)
# List files
ls
# Change to upload directory
cd public
# Upload a file
put myfile.txt
# Download a file
get somefile.txt
/var/ftp/ - FTP root directory (read-only)/var/ftp/public/ - Upload directory for anonymous users (writable)The server automatically detects your external IP using the api.ipify.org service and includes it in the welcome banner. You can override this by setting the EXTERNAL_IP environment variable.
When mounting local directories, Docker may change file ownership and permissions which can be problematic. The container automatically detects and preserves both the ownership and permissions of your mounted directory:
# Automatic ownership & permission detection (recommended)
docker run -it --rm \
-v $(pwd):/var/ftp/public \
andspace/ftp-anon
The container automatically detects:
This ensures your local directory maintains its original ownership and access permissions, preventing permission issues.
You can also manually specify custom IDs if needed:
# Manual UID/GID specification (optional)
docker run -it --rm \
-v $(pwd):/var/ftp/public \
-e FTP_UID=1000 \
-e FTP_GID=1000 \
andspace/ftp-anon
This prevents Docker from changing your local directory ownership to the container's default FTP user (UID 21) and ensures proper access control.
The container provides multi-level logging with smart verbosity control:
# Default logging (VERBOSE level - shows all details)
docker run -it --rm andspace/ftp-anon
# Minimal logging (essential info only)
docker run -it --rm -e LOG_LEVEL=MINIMAL andspace/ftp-anon
# View logs
docker logs <container-name>
# Real-time log monitoring
docker logs -f <container-name>
VERBOSE Level (Default): Complete configuration details, debug info, and all operational information
MINIMAL Level: Clean startup with essential connection details and configuration summary only
public/ subdirectory allows uploadsContent type
Image
Digest
sha256:b6a2ae8dd…
Size
6.3 MB
Last updated
about 1 year ago
docker pull andspace/ftp-anon