Sign inSign up

bfren/ftps

By bfren

โ€ขUpdated about 15 hours ago

Simple FTP image based on Alpine Linux, with passive FTP over TLS support.

Image
Networking
Developer tools
7

100K+

bfren/ftps repository overview

โ FTPS

GitHub release (latest by date) Docker Pulls Docker Image Size GitHub Workflow Status

Docker Hubโ  - Quay.ioโ  - bfren ecosystemโ 

โ Introduction

An FTP server that only accepts encrypted connections (FTPS - FTP over TLS), for devices and apps that can't use SFTP. It runs vsftpdโ  with one user, kept inside /files, and creates a self-signed certificate if you don't provide one.

It is built on Alpine + S6โ , with vsftpd from Alpine's packages.

โ Quickstart

services:
  ftps:
    image: quay.io/bfren/ftps:5.2
    restart: unless-stopped
    ports:
      - "0.0.0.0:21:21"
      - "0.0.0.0:18700-18710:18700-18710"
    environment:
      - BF_FTPS_EXTERNAL_URI=ftp.example.com
      - BF_FTPS_VSFTPD_USER=fred
      - BF_FTPS_VSFTPD_PASS=${FTPS_PASS}
    volumes:
      - ./v/files:/files
      - ./v/ssl:/ssl

Run docker compose up -d, then connect with an FTP client, e.g. in FileZilla or WinSCP:

SettingValue
ProtocolFTP (not SFTP - that is a different protocol)
EncryptionExplicit FTP over TLS (not plain or implicit)
Hostftp.example.com - the address in BF_FTPS_EXTERNAL_*
Port21
User nameBF_FTPS_VSFTPD_USER
PasswordBF_FTPS_VSFTPD_PASS

Accept the certificate when the client asks - it is self-signed unless you provide your own.

โ Features

  • ๐Ÿ” Encryption required for logins and file transfers
  • ๐Ÿ“ One user, kept inside /files
  • ๐Ÿ“œ Self-signed certificate created on first start, or use your own
  • ๐ŸŒ Passive mode with a fixed port range, for firewalls and NAT
  • ๐Ÿฉบ Health check that logs in and uploads a file
  • ๐Ÿงช Built-in tests

โ Tags

Images are published to Docker Hub (bfren/ftps) and Quay.io (quay.io/bfren/ftps) for linux/amd64, linux/arm/v7 and linux/arm64, with vsftpd 3.0.5 on Alpine 3.24.

TagExampleUse when
latestYou always want the newest image
MAJOR5You want updates, but not breaking changes
MINOR5.2You want fixes only - recommended
VERSION5.2.0You want to pin this image exactly
vsftpdX, vsftpdX.Yvsftpd3.0You want a vsftpd version
vsftpdX.Y.Zvsftpd3.0.5You want an exact vsftpd release
vsftpdX.Y.Z-VERSIONvsftpd3.0.5-5.2.0You want to pin both

โ Configuration

โ Ports
PortPurpose
21FTP control connection - encrypted with explicit TLS
18700-18710Passive data connections (change with BF_FTPS_VSFTPD_*_PORT)

Publish the whole passive range, with the same numbers on the host and in the container.

โ Volumes
VolumePurpose
/filesThe user's files - owned by the user, who can't see anything outside it.
/sslvsftpd.pem - the certificate and key (created if it doesn't exist).
โ Environment Variables
VariableValuesDescriptionDefault
BF_FTPS_VSFTPD_USERstringRequired. The user name to log in with.
BF_FTPS_VSFTPD_PASSstringRequired. The user's password.
BF_FTPS_EXTERNAL_URIhost nameThe address clients use - told to clients for passive connections. Takes priority over BF_FTPS_EXTERNAL_IP.
BF_FTPS_EXTERNAL_IPIP addressThe address clients use, if you don't have a host name. One of the two is required.
BF_FTPS_VSFTPD_UIDnumberThe user's UID - set it to the owner of /files on the host.1000
BF_FTPS_VSFTPD_MIN_PORTportFirst port for passive data connections.18700
BF_FTPS_VSFTPD_MAX_PORTportLast port for passive data connections.18710
BF_FTPS_VSFTPD_WELCOMEtextMessage shown when users log in.Welcome to the FTPS server.
BF_FTPS_VSFTPD_ENABLE_DEBUG_LOG0, 1Log every FTP command and transfer to docker logs.0
BF_FTPS_VSFTPD_ENABLE_PASV_PROMISCUOUS0, 1Turn off vsftpd's check that data connections come from the same address as the login. Only for secure tunnels - leave it off.0
BF_FTPS_SSL_BITSnumberKey size for the self-signed certificate.4096
BF_FTPS_LFTP_VERIFY_CERTno, yesWhether the health check verifies the certificate - only yes with a trusted certificate.no

See Alpine + S6โ  for BF_DEBUG, BF_TZ and the other base image variables.

โ How It Works

On every start:

  1. The user, password and external address are checked - the container stops if any are missing.
  2. The user is created (if it doesn't exist yet) with /files as its home, and given /files.
  3. If /ssl/vsftpd.pem doesn't exist, a self-signed certificate valid for ten years is created there.
  4. vsftpd.conf is generated, and vsftpd runs under S6. The container stops if it crashes.

Logins and file transfers must be encrypted, the user is kept inside /files (chroot), and anonymous logins are refused. Uploaded files are readable only by the user (umask 077).

In passive mode the client opens a second connection for each transfer, to a port in the passive range, at the address the server gives it - BF_FTPS_EXTERNAL_URI (looked up when vsftpd starts) or BF_FTPS_EXTERNAL_IP. That address must reach the server from the client's side.

The health check (every 30 seconds) logs in as the user with lftp, uploads a small file and deletes it.

โ Using your own certificate

Put a PEM file containing both the certificate and its private key at /ssl/vsftpd.pem, then restart. Set BF_FTPS_LFTP_VERIFY_CERT=yes if the certificate is trusted for 127.0.0.1.

โ Testing

./test.nu   # builds the image and runs /test
./run.sh    # builds the image and opens a shell, with the ports published on 127.0.0.1

/test runs this image's tests alongside the base images' tests: the environment checks, creating the certificate, the generated vsftpd.conf and lftp.conf, and the installed vsftpd version.

โ Troubleshooting

โ The container stops straight after starting

Check docker logs <container> - BF_FTPS_VSFTPD_USER, BF_FTPS_VSFTPD_PASS, and BF_FTPS_EXTERNAL_URI or BF_FTPS_EXTERNAL_IP must all be set.

โ Logging in works, but listing files times out

The passive connection can't get through. Check the whole port range is published and allowed by your firewall, and that BF_FTPS_EXTERNAL_* is the address clients use to reach the server.

โ I changed the password but the old one still works

The user is only created once, so changes are ignored until the container is recreated (docker compose up -d --force-recreate).

โ The client says the certificate isn't trusted

It is self-signed. Accept it, or use your own certificateโ .

โ FAQs

โ Can I have more than one user?

No - one user per container. Run another container (with different ports) for another user.

โ What's the difference between FTPS and SFTP?

FTPS is FTP with TLS encryption. SFTP is a different protocol, part of SSH. This image only supports FTPS.

โ Licence

Copyright (c) 2021-2026 bfrenโ  (unless otherwise stated)

Tag summary

Content type

Image

Digest

sha256:03ed00965โ€ฆ

Size

30.5 MB

Last updated

about 15 hours ago

docker pull bfren/ftps