Can't push file to my VSFTPD Server - 553 Could not create file error

I’ve set up a VSFTPD server on my Fedora 42 server for learning. I’ve shared my config file along with Firewalld and selinux status. I could able to login to the server via ftpuser which is allowed in the config file.

But the thing is when I execute put /tmp/index.html it throws an error (mentioned below), While executing put /tmp/index.html index.html works perfectly fine. Why?

I feel like it’s either my config file or SELinux causing this issue.

Config file

#Disable anonymous
anonymous_enable=NO

#Allows localusers
local_enable=YES

#To Allow users to upload
write_enable=YES
allow_writeable_chroot=YES

#To provide default permissions
local_umask=022

#Welcome Banner
ftpd_banner=Welcome to The private company

#Jail user within the home directory
chroot_local_user=YES

listen=YES

#PAM authentication
pam_service_name=vsftpd

#Only the mentioned users can able to access the FTP server.
userlist_enable=YES
userlist_file=/etc/vsftpd/allowed_users
userlist_deny=NO

SELinux O/P

ftpd_anon_write --> off
ftpd_connect_all_unreserved --> off
ftpd_connect_db --> off
ftpd_full_access --> off
ftpd_use_cifs --> off
ftpd_use_fusefs --> off
ftpd_use_nfs --> off
ftpd_use_passive_mode --> off
httpd_can_connect_ftp --> off
httpd_enable_ftp_server --> off
tftp_anon_write --> off
tftp_home_dir --> on

Error O/P

kiruba@QubeFed:/tmp$ ftp localhost
Trying ::1...
ftp: connect to address ::1Connection refused
Trying 127.0.0.1...
Connected to localhost (127.0.0.1).
220 Welcome to The private company
Name (localhost:kiruba): ftpuser
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
227 Entering Passive Mode (127,0,0,1,181,243).
150 Here comes the directory listing.
drwxr-xr-x 1 1001 1001 16 Sep 29 05:40 files
226 Directory send OK.
ftp>
ftp>
ftp> put /tmp/index.html
local: /tmp/index.html remote: /tmp/index.html
227 Entering Passive Mode (127,0,0,1,136,228).
553 Could not create file.
ftp> put /tmp/index.html file
local: /tmp/index.html remote: file
227 Entering Passive Mode (127,0,0,1,178,174).
150 Ok to send data.
226 Transfer complete.
19301 bytes sent in 8.6e-05 secs (224430.24 Kbytes/sec)
ftp> dir
227 Entering Passive Mode (127,0,0,1,237,127).
150 Here comes the directory listing.
-rw-r--r-- 1 1001 1001 19301 Sep 29 08:53 file
drwxr-xr-x 1 1001 1001 16 Sep 29 05:40 files
226 Directory send OK.
ftp> cd files
250 Directory successfully changed.
ftp> ls
227 Entering Passive Mode (127,0,0,1,224,113).
150 Here comes the directory listing.
-rw-r--r-- 1 1001 1001 12 Sep 29 05:40 testfile
226 Directory send OK.
ftp> put /tmp/index.html
local: /tmp/index.html remote: /tmp/index.html
227 Entering Passive Mode (127,0,0,1,30,62).
553 Could not create file.
ftp> put /tmp/index.html index.html
local: /tmp/index.html remote: index.html
227 Entering Passive Mode (127,0,0,1,75,209).
150 Ok to send data.
226 Transfer complete.
19301 bytes sent in 0.000114 secs (169307.01 Kbytes/sec)
ftp>
221 Goodbye.

Test using any of these below @Kiruba ; all avoid sending an absolute path as the remote name and see

  1. Try explicitly set the remote name like this:
put /tmp/index.html index.html
  1. Or change to the local dir first, then upload basename:
lcd /tmp
put index.html
  1. Or tell the client to put it in the current remote directory:
put /tmp/index.html .

Let us know how these tests perform.

Note:

If you truly want /tmp/index.html to work, create /tmp inside the chroot and make it writable (usually cosidered a bad idea for a jailed FTP tree, but you need to evaluate your own risk management profile, etc).

Thanks @Neo for the response, this is for learning purpose. I tried your steps and it works.

So, the thing is will vsftpd service works this way? Should we explicitly mention the file name in the remote destination? if not it doesn’t seems to create a file on its own.

ChatGPT 5.0 replies, thus:

The short answer: yes, vsftpd works exactly this way. It doesn’t auto-strip paths for you; it stores files using whatever remote pathname the client asks for.

Why this happens

  • put /tmp/index.html
    → your client sends STOR /tmp/index.html.
    Since your vsftpd user is jailed (chroot_local_user=YES), there is no /tmp/ directory inside the FTP root. Server returns 553 Could not create file.

  • put /tmp/index.html index.html
    → your client sends STOR index.html.
    That’s just a plain filename in the current remote directory, so it works.

Different FTP clients vary in how they guess the remote name when you don’t give one. Some will automatically strip to the basename, others will send the full local path. Yours does the latter.

What this means for you

  • It’s not a bug in vsftpd or SELinux. It’s client behavior + chrooted filesystem.

  • If you don’t want to type two arguments every time:

    • First do lcd /tmp then put index.html
    • Or use put /tmp/index.html . to drop it into the current directory
    • Or use a client that defaults to the basename

So yes: unless you explicitly tell it otherwise, vsftpd will literally try to create whatever remote path the client asks for. If that path doesn’t exist in the chroot, you get the 553 error.