Driver FixRecommendedSound, Wi-Fi or graphics acting up? Check drivers firstFind missing or outdated drivers fast.Check DriversHalloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PC×
Skip to content
VGSources
Blog

How to Create a Limited FTP Account on a Linux VPS (vsftpd, FTPS, and SFTP)

Build a least-privilege FTP account on a Linux VPS with vsftpd, a root-owned chroot, a writable upload subdirectory, required FTPS encryption, and a bounded passive-port range. Includes local and virtual-user setups plus SFTP guidance.
Length11 min Posted Quest giverVGSources Team
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use vsftpd with a dedicated, non-login Linux account, a root-owned chroot directory, and a separate writable child directory. That combination gives an FTP user access to one transfer tree without SSH access or permission to write the jail itself. Encrypt the connection with FTPS, restrict passive ports in both firewalls, and test the jail from outside the VPS.

If your client supports SSH, SFTP is usually the simpler secure choice because it uses the existing SSH service and does not need FTP’s separate passive data channel. Use FTPS when FTP compatibility is required.

As an Amazon Associate I earn from qualifying purchases.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What a limited FTP account actually restricts

An FTP account has several independent boundaries:

  • Authentication: which credentials are accepted.
  • Filesystem scope: the directory visible after login.
  • Unix permissions: which files and subdirectories can be read, created, changed, or deleted.
  • Protocol commands: whether uploads, renames, deletion, or directory creation are enabled.
  • Network exposure: which control and passive data ports are reachable.

Chrooting hides the rest of the filesystem, but it is not a substitute for Unix ownership and mode bits. A user who can write every directory inside the jail can still alter every file that those permissions allow. Design the directory tree first, then configure vsftpd to match it.

Choose local users or vsftpd virtual users

There are two supported designs. Select one before editing the configuration.

Decision point Local Linux user vsftpd virtual user
Identity source /etc/passwd and the system account database A vsftpd/PAM user database
Operating-system account One account per FTP identity; its shell can be set to nologin FTP identities are mapped to one unprivileged local guest account
Best fit One or a few administrators, contractors, or site owners Many FTP-only customers, vendors, or application identities
Main risk Review whether SSH or another service also accepts the account Protect the credential database, PAM file, and mapped guest account
Administration Use normal Linux account and permission tools Maintain a separate password database and, commonly, one directory per virtual name

The local-user procedure below is the shortest reliable setup. The virtual-user procedure appears later for installations that must not create a normal system account for each FTP identity.

Prerequisites and the example layout

The commands in this guide target Ubuntu or Debian with sudo. Package names and service commands differ on Red Hat–family distributions, so use that distribution’s package manager and service unit where necessary. You need:

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • A VPS with a static public address or a stable DNS name.
  • Root or sudo access.
  • An FTP client that supports explicit TLS if credentials must be protected.
  • Permission to change the VPS firewall and the cloud provider’s security group.
  • A decision about whether the account is download-only or must upload.

The examples use this tree:

/srv/ftp/client-a/                 # chroot root; administrative ownership only
/srv/ftp/client-a/incoming/         # writable upload directory, if required

After login, /srv/ftp/client-a appears as /. The user cannot use cd .. to reach the VPS’s real root.

Install and start vsftpd

  1. Install the server package:

    sudo apt update
    sudo apt install vsftpd
  2. Back up the original configuration before changing it:

    sudo cp /etc/vsftpd.conf /etc/vsftpd.conf.orig
  3. Enable the service at boot and start it:

    sudo systemctl enable --now vsftpd
    sudo systemctl status vsftpd

If the service fails to start, read the unit log before changing more settings:

sudo journalctl -u vsftpd --no-pager -n 100

Create the limited local account

1. Build a root-owned jail

sudo install -d -o root -g root -m 755 /srv/ftp/client-a
sudo install -d -o clienta -g clienta -m 750 /srv/ftp/client-a/incoming

The second command requires the account to exist, so create the account first if you are following these commands literally. A complete order is:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
sudo useradd --home-dir /srv/ftp/client-a --shell /usr/sbin/nologin --no-create-home clienta
sudo passwd clienta
sudo install -d -o root -g root -m 755 /srv/ftp/client-a
sudo install -d -o clienta -g clienta -m 750 /srv/ftp/client-a/incoming

If /usr/sbin/nologin is at a different path on your distribution, find it with command -v nologin. The account still exists in the operating system, but it cannot open an interactive shell. Check that no SSH configuration, group membership, or other service grants it access you did not intend.

2. Set ownership for the files the user should download

Place downloadable files under the jail and make them readable by clienta through ownership or group permissions. For example:

sudo install -o root -g clienta -m 640 release.zip /srv/ftp/client-a/release.zip

Keep the jail directory itself owned by root (or another administrative account) and not writable by clienta. The writable incoming child is where uploads, renames, and deletions should occur.

Configure authenticated, jailed local access

Edit /etc/vsftpd.conf. Remove duplicate entries or ensure the last value is the one you intend; vsftpd configuration files are easier to audit when each option appears once.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
listen=YES
listen_ipv6=NO
anonymous_enable=NO
local_enable=YES
write_enable=YES
local_umask=027
chroot_local_user=YES
allow_writeable_chroot=NO

# Optional command restrictions
# cmds_allowed=PASV,EPSV,LIST,MLSD,NLST,RETR,STOR,TYPE,USER,PASS,PWD,CWD,CDUP,QUIT

# TLS settings (paths shown are examples)
ssl_enable=YES
force_local_logins_ssl=YES
force_local_data_ssl=YES
rsa_cert_file=/etc/ssl/private/ftp-server.crt
rsa_private_key_file=/etc/ssl/private/ftp-server.key
ssl_sslv3=NO
ssl_tlsv1=NO

# Passive data ports
pasv_min_port=40000
pasv_max_port=40100
# Set this when the VPS is behind NAT or has a separate public address:
# pasv_address=ftp.example.com

write_enable=YES is necessary for uploads, renames, deletion, and directory creation. If the account only downloads, set it to NO or use a per-user configuration that does so. The cmds_allowed line is optional: command names must match the operations your clients need, and an overly narrow list can break directory listings or modern FTP clients.

With chroot_local_user=YES, every selected local user is jailed to its home directory. The meaning of chroot_list_file reverses in this mode: users listed there become exceptions rather than jailed users. Do not add an exception unless you have a specific reason and have reviewed its consequences.

Create a certificate and require FTPS

FTP sends credentials in clear text unless TLS is negotiated. For a temporary internal test, you can create a self-signed certificate; production clients should use a certificate they trust and verify the server name.

sudo openssl req -x509 -nodes -newkey rsa:2048 -days 365 
  -keyout /etc/ssl/private/ftp-server.key 
  -out /etc/ssl/private/ftp-server.crt

Protect the private key:

sudo chown root:root /etc/ssl/private/ftp-server.key
sudo chmod 600 /etc/ssl/private/ftp-server.key

The settings above require TLS for local-user logins and data transfers. Client labels vary: choose FTP over TLS, explicit (also called explicit FTPS) on the normal control port. A self-signed certificate will produce a trust warning until the client is configured to trust it; do not silently accept an unexpected certificate on an Internet-facing server.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Option names and TLS capabilities vary between vsftpd builds. If vsftpd rejects an option, consult the manual installed with your package and use the strongest protocol settings that your clients support.

Open only the required network ports

FTP uses one control connection and separate data connections. Passive mode makes the server listen on a bounded range that the client connects to. Permit TCP port 21 and the exact passive range in both layers of filtering.

sudo ufw allow 21/tcp
sudo ufw allow 40000:40100/tcp
sudo ufw status

Repeat equivalent rules in the VPS provider’s security group or network firewall. If the server has a private address and a different public address, set pasv_address to the public DNS name or address that clients can reach. Never expose a broad, unbounded passive range when a small range is sufficient.

Reload and verify the local-user setup

  1. Check the configuration syntax and restart the service:

    Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
    sudo systemctl restart vsftpd
    sudo systemctl status vsftpd
  2. Connect from a machine outside the VPS using an FTP client configured for explicit TLS.

  3. Confirm that the initial directory is the intended client root and that a directory listing works.

  4. Run cd .. repeatedly. The client must remain inside the jail.

  5. Download a permitted file.

  6. If uploads are enabled, upload into incoming, rename a test file there, and delete it. Do not test by making the chroot root writable.

    What’s actually slowing this PC down?

    Pick the symptom - the matching free tool is one click away.

    Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  7. Attempt an upload or deletion in a read-only directory and confirm that it fails.

  8. Inspect the client’s connection details and confirm that TLS protects both authentication and the data channel.

These checks prove the account’s effective behavior rather than merely proving that the daemon is running.

Use virtual users when FTP identities should not be system accounts

Virtual users are useful when you have many external identities or when you want FTP credentials that cannot be reused for SSH. vsftpd authenticates the names through PAM and maps them to one unprivileged local account.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

1. Create the mapped guest account and directories

sudo useradd --system --home-dir /srv/ftp --shell /usr/sbin/nologin ftpguest
sudo install -d -o root -g root -m 755 /srv/ftp
sudo install -d -o ftpguest -g ftpguest -m 750 /srv/ftp/client-a/incoming

Create one directory per virtual identity. The guest account owns only the locations that virtual users need.

2. Build the credential database

Create a file containing alternating usernames and passwords, with restrictive permissions:

sudo sh -c 'umask 077; cat > /etc/vsftpd/virtual_users.txt'

Enter:

client-a
use-a-long-unique-password

Press Ctrl-D, then convert the file to a Berkeley DB database with the db_load utility (the package providing that utility varies by distribution):

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
sudo db_load -T -t hash -f /etc/vsftpd/virtual_users.txt /etc/vsftpd/virtual_users.db
sudo chmod 600 /etc/vsftpd/virtual_users.db
sudo shred -u /etc/vsftpd/virtual_users.txt

Keep backups of the database protected like passwords. Anyone who obtains it may be able to authenticate, depending on the database format and protections.

3. Point PAM at the database

Create a dedicated PAM service file such as /etc/pam.d/vsftpd-virtual:

auth    required pam_userdb.so db=/etc/vsftpd/virtual_users
account required pam_userdb.so db=/etc/vsftpd/virtual_users

Use a separate PAM file if you also need local Linux users; do not overwrite an existing distribution file without first understanding which authentication methods it contains.

4. Enable the virtual-user mode

Add the following settings to the vsftpd configuration:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
anonymous_enable=NO
local_enable=YES
write_enable=YES
guest_enable=YES
guest_username=ftpguest
virtual_use_local_privs=YES
pam_service_name=vsftpd-virtual
user_sub_token=$USER
local_root=/srv/ftp/$USER
chroot_local_user=YES
user_config_dir=/etc/vsftpd/user_conf
pasv_min_port=40000
pasv_max_port=40100

Create the per-user directory and, when needed, an override file:

sudo install -d -o root -g root -m 755 /etc/vsftpd/user_conf
sudo sh -c 'cat > /etc/vsftpd/user_conf/client-a <<EOF
local_root=/srv/ftp/client-a
write_enable=YES
EOF'

The upstream virtual-user pattern maps authenticated names to the unprivileged guest account. Confirm that every mapped directory has the ownership and modes you expect; the virtual name is not itself a Unix UID.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Limit commands and writes further

Use the narrowest capability that meets the workflow:

  • For download-only access, set write_enable=NO globally or in the user’s configuration.
  • For upload-only exchange, grant write permission to incoming and avoid granting write permission to the jail root.
  • Use user_config_dir for per-user differences rather than making every account equally powerful.
  • Use cmds_allowed or cmds_denied only after testing listings, passive negotiation, uploads, and the client’s required commands.
  • Keep the mapped guest account unprivileged and out of administrative groups.

FTP, FTPS, or SFTP?

Protocol How it works Firewall and account implications When to choose it
FTP Traditional FTP without encryption Credentials and data can be observed; requires control and passive data ports Only isolated, non-sensitive networks where clear text is explicitly acceptable
FTPS FTP protected by TLS Still requires passive ports and certificate management; encrypts credentials and transfers When an existing FTP client or workflow requires FTP semantics
SFTP File transfer over SSH Uses the SSH service and avoids FTP’s separate passive data channel; users need a shell account, usually with an SSH restriction or chroot design The simplest secure option when clients support SSH

Ubuntu documentation distinguishes the account models: SFTP users need a shell account, while FTP users can be assigned a nologin shell and constrained by vsftpd. If you must provide FTP compatibility, use FTPS and a tightly bounded passive range rather than unencrypted FTP.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Troubleshooting by symptom

Login is rejected

  • Verify that the selected mode is enabled: local_enable=YES for local accounts, or guest_enable=YES with the correct PAM service for virtual users.
  • Check that the account is not blocked by userlist_enable, userlist_deny, or a distribution-specific access rule.
  • For local users, confirm the password, home directory, and nologin shell path. A shell listed in /etc/shells rules can affect authentication on some builds.
  • Read journalctl -u vsftpd and the client’s exact server response.

vsftpd refuses to start or refuses the jail

Inspect ownership and mode bits:

namei -l /srv/ftp/client-a
stat -c '%U %G %a %n' /srv/ftp/client-a /srv/ftp/client-a/incoming

The chroot root must not be writable by the jailed identity. vsftpd warns that allowing a user to chroot into a directory writable by that user is potentially dangerous: a user could create an etc directory and influence library configuration loading. Keep the root administrative and use a writable child directory.

Directory listings or transfers hang

  • Allow TCP 21 and the configured passive range in the VPS firewall.
  • Allow the same ports in the cloud security group.
  • Confirm that pasv_address advertises a reachable public address or DNS name.
  • Check that the client is using passive mode, especially from a private network or behind NAT.

Uploads return permission denied

  • Inspect Unix owner, group, mode bits, and any ACL on the destination.
  • Confirm that the destination is the writable child directory, not the chroot root.
  • Verify write_enable=YES and that the requested command is not excluded by cmds_denied or a restrictive allowlist.
  • On distributions using SELinux or AppArmor, inspect the policy denial and apply the distribution-approved label or profile change rather than disabling the security framework.

TLS negotiation fails

  • Verify that the certificate and private-key paths exist and that the daemon can read them.
  • Check the certificate name, expiration, and client trust store.
  • Confirm that the client supports the TLS versions and explicit-FTPS mode required by the server.
  • If encrypted sessions are mandatory, make sure the client is not attempting plain FTP.

Final least-privilege checklist

  • Anonymous access is disabled.
  • The FTP identity has no interactive shell.
  • The chroot root is owned by an administrator and is not writable by the FTP identity.
  • Only the required child directory is writable.
  • Write operations are disabled unless the workflow needs them.
  • FTPS is required for credentials and data, or SFTP is used instead.
  • Passive ports are a small, documented range allowed in both firewall layers.
  • Virtual-user databases, PAM files, and private keys are readable only by necessary administrative processes.
  • An external client test confirms the jail, permitted operations, denied operations, and TLS negotiation.

The Bottom Line

For a small number of accounts, create a local user with a nologin shell, chroot it with vsftpd, and grant write access only to a child directory. For larger FTP-only populations, use vsftpd virtual users mapped to one unprivileged guest account. Prefer SFTP whenever your clients support SSH; otherwise deploy FTPS with a bounded passive-port range.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More quests from Patch Notes

  1. How to Set Up a RedM (RDR2) Server in 2026: License Key, txAdmin and server.cfg, Step by StepBlog11min
  2. Best RedM (RDR2) Server Hosting in 2026: Comparing Four Hosts on Slots, Memory and PriceBlog10min
  3. How to Host a Mindustry Server in 2026: server-release.jar, Port 6567 and the Commands That MatterBlog7min
Recommended PC Tool
Recommended PC Tool
Windows Errors? Fix Them Before They SpreadFree repair scan
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.