How to Set Up a SFTP-Only User on Linux: Secure File Transfer Without Shell Access


3 views

When setting up SFTP (SSH File Transfer Protocol) users, system administrators often need to restrict users to file transfer only, preventing shell access. The common approach of changing the shell to /sbin/nologin or /dev/null doesn't work because SFTP still requires a valid shell for authentication.

OpenSSH provides a built-in SFTP server that can be configured to chroot users while denying shell access. Here's how to properly set it up:

# 1. Create the user with no login shell
sudo adduser --shell /usr/sbin/nologin sftpuser

# 2. Set up the chroot directory
sudo mkdir -p /var/sftp/sftpuser/uploads
sudo chown root:root /var/sftp/sftpuser
sudo chmod 755 /var/sftp/sftpuser
sudo chown sftpuser:sftpuser /var/sftp/sftpuser/uploads

# 3. Configure SSH server (add to /etc/ssh/sshd_config)
Match User sftpuser
    ChrootDirectory /var/sftp/sftpuser
    ForceCommand internal-sftp
    AllowTcpForwarding no
    X11Forwarding no

After making these changes, restart the SSH service:

sudo systemctl restart sshd

Test the configuration by attempting to connect:

sftp sftpuser@yourserver.com

Then try to get a shell (which should fail):

ssh sftpuser@yourserver.com

For more complex setups, you might want to:

  1. Set up multiple SFTP-only users with different directories
  2. Configure disk quotas
  3. Implement logging for file transfers

Here's an example for multiple users:

Match Group sftponly
    ChrootDirectory /var/sftp/%u
    ForceCommand internal-sftp
    AllowTcpForwarding no
    X11Forwarding no

If you encounter problems:

  • Check permissions on the chroot directory (must be owned by root)
  • Verify SELinux contexts if you're using SELinux
  • Check SSH logs (/var/log/auth.log) for errors

Creating a user restricted to SFTP-only access is a common security requirement for system administrators. While the adduser tool creates standard accounts, we need additional configuration to prevent shell access while allowing secure file transfers.

Many administrators first try modifying shell assignments in /etc/passwd:

# Common but ineffective attempts:
sftpuser:x:1001:1001::/home/sftpuser:/sbin/nologin
sftpuser:x:1001:1001::/home/sftpuser:/dev/null
sftpuser:x:1001:1001::/home/sftpuser:/bin/false

These methods block shell access but typically break SFTP functionality because OpenSSH requires a valid shell for authentication.

The proper method involves configuring OpenSSH's internal-sftp subsystem:

# Step 1: Create the user (no shell change yet)
sudo adduser sftpuser
sudo passwd sftpuser

# Step 2: Edit /etc/ssh/sshd_config
Match User sftpuser
    ChrootDirectory /home/sftpuser
    ForceCommand internal-sftp
    AllowTcpForwarding no
    X11Forwarding no
    PermitTTY no

Proper permissions are crucial for security:

# Set up the chroot environment
sudo mkdir -p /home/sftpuser/uploads
sudo chown root:root /home/sftpuser
sudo chmod 755 /home/sftpuser
sudo chown sftpuser:sftpuser /home/sftpuser/uploads
sudo chmod 755 /home/sftpuser/uploads

After restarting SSH (sudo systemctl restart sshd), verify with:

sftp sftpuser@localhost
# Should connect successfully

ssh sftpuser@localhost
# Should fail with "This service allows sftp connections only"

For more complex setups, consider these additions:

# Multiple users in group
Match Group sftponly
    ChrootDirectory /home/%u
    ForceCommand internal-sftp
    # ... other restrictions

# Logging configuration
Subsystem sftp internal-sftp -l INFO -f AUTH

If connections fail, check:

  • SSH logs (/var/log/auth.log)
  • Directory ownership (must be root:root)
  • SELinux contexts if enabled
  • SSH config syntax (indentation matters)