When working with OpenSSH's SFTP client on Linux systems, you'll notice it automatically sets file permissions to 640 (rw-r-----) during file transfers, unlike many GUI SFTP clients which don't explicitly set permissions. This behavior stems from OpenSSH's implementation that preserves original file modes by default.
$ sftp user@example.com
Connected to example.com.
sftp> put example.txt
Uploading example.txt to /home/user/example.txt
example.txt 100% 12KB 1.2MB/s 00:00
Looking at the OpenSSH source code (src/sftp-client.c), we can see the client attempts to preserve file modes regardless of whether the -P flag is specified:
/*
* Preserve file modes by default
*/
if (!preserve_flag && (st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != 0) {
attrib_flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
attrib.permissions = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
}
Option 1: Using umask
The most straightforward solution is to set the umask before running sftp:
$ umask 0022 # Results in 644 permissions
$ sftp user@example.com
Option 2: Post-transfer chmod
You can modify permissions after transfer using sftp's chmod command:
sftp> put file.txt
sftp> chmod 755 file.txt
Option 3: Alternative SFTP Clients
As mentioned in the original post, clients like PuTTY's PSFTP don't enforce permissions:
psftp> open user@example.com
psftp> put file.txt
For OpenSSH server administrators, you can modify the sshd_config
to influence default permissions:
# /etc/ssh/sshd_config
Subsystem sftp internal-sftp -u 0002 # Sets umask for SFTP connections
For complete control, create a wrapper script that handles permission setting:
#!/bin/bash
# sftp-wrapper.sh
TARGET_PERMS=$1
shift
sftp $@ <
Usage example:
$ find . -type f | ./sftp-wrapper.sh 644 user@example.com
When working with OpenSSH's sftp
command, many developers encounter unexpected behavior regarding file permissions. Unlike GUI clients like WinSCP or FileZilla that don't explicitly set modes, the OpenSSH client defaults to applying 640 permissions (rw-r-----) on uploaded files.
# Typical sftp upload with implicit 640 permissions
sftp user@host
put localfile.txt /remote/path/
The behavior stems from OpenSSH's source code where the client attempts to preserve file modes by default, even when the -P
flag (preserve permissions) isn't specified. This occurs in the upload.c
file where the client sets the mode bits during SSH_FXP_OPEN.
For those needing different permission behavior, consider these approaches:
1. Using umask Adjustments
Configure the server's umask to modify the final permissions:
# In /etc/ssh/sshd_config
Subsystem sftp /usr/lib/openssh/sftp-server -u 0002
2. Post-transfer Permission Modification
Chain commands to modify permissions after upload:
sftp user@host <
3. Alternative Clients
As mentioned in the original post, PuTTY's PSFTP client handles permissions differently. Example usage:
psftp user@host -b upload.txt
# upload.txt contents:
put localfile.txt /remote/path/
For those comfortable with compiling from source, you could modify the upload.c
behavior:
// Around line 986 in upload.c (OpenSSH 8.9)
if (!preserve_flag) {
// Original: attrib_to_set |= SSH2_FILEXFER_ATTR_PERMISSIONS;
attrib_to_set = 0; // Skip permission setting
}
Here's a complete bash script example that handles uploads with custom permissions:
#!/bin/bash
SFTP_HOST="example.com"
SFTP_USER="user"
TARGET_DIR="/remote/path"
LOCAL_FILE="data.csv"
REMOTE_PERMS="664"
sftp -b - ${SFTP_USER}@${SFTP_HOST} <