Uploading a whole project tree to a remote server is common in release staging, backup rotation, and partner handoff workflows where partial delivery can leave the destination unusable. Sending one archive instead of many loose files keeps the transfer atomic, makes retries predictable, and gives downstream extract or deploy jobs one artifact to validate.
With cURL, a directory upload is really a file upload. cURL does not recursively walk a local directory and push every entry on its own, so the reliable pattern is to package the directory tree into one archive, upload that archive with --upload-file, and extract it later on the remote side if the original tree layout is needed again. The URL scheme selects the transport, so the same archive can be sent to either an FTP or SFTP destination.
The examples below use masked release-style hostnames, paths, account names, and archive names so the command flow stays realistic without exposing a live environment.
Protocol support and path handling vary by build and server. Some cURL packages include ftp support but omit sftp, plain FTP exposes credentials and file contents unless a secure alternative is used, and missing SFTP directories usually need to be created before the upload. Keep passwords out of shell history, prefer .netrc or SSH keys for recurring jobs, and verify the remote path before any follow-up extract step runs.
Steps to upload directories to FTP or SFTP with cURL:
- Check that the local cURL build supports the protocol needed for the transfer.
$ curl --version | awk '/^Protocols:/{print $0}' Protocols: dict file ftp ftps gopher gophers http https imap imaps ldap ldaps mqtt pop3 pop3s rtmp rtsp scp sftp smb smbs smtp smtps telnet tftp
The Protocols line must contain ftp for FTP uploads and sftp for SFTP uploads. Some platform builds include FTP support but omit SSH-based protocols.
- Package the directory tree into one archive before transferring it.
$ tar -C /srv/releases -czf partner-portal-2026-03-archive.tar.gz partner-portal $ ls -lh partner-portal-2026-03-archive.tar.gz -rw-r--r-- 1 user user 18M Mar 29 10:44 partner-portal-2026-03-archive.tar.gz
cURL uploads files, not directory trees, so the archive becomes the single object that is moved and verified.
- Upload the archive to the FTP destination and let cURL create missing remote directories in the target path.
$ curl --upload-file partner-portal-2026-03-archive.tar.gz \ --ftp-create-dirs \ --netrc \ ftp://ftp-upload.example.net/incoming/releases/2026/03/partner-portal-2026-03-archive.tar.gz % Total % Received % Xferd Average Speed Time Time Time Current 100 18.2M 0 0 100 18.2M 0 12.1M 0:00:01 0:00:01 --:--:-- 12.2M
Plain FTP does not encrypt credentials or file contents. Use SFTP or FTPS on untrusted networks and avoid putting user:password directly on the command line.
- Confirm that the archive landed in the expected FTP directory before any remote extract or publish step runs.
$ curl --silent --list-only --netrc ftp://ftp-upload.example.net/incoming/releases/2026/03/ | grep '^partner-portal-2026-03-archive.tar.gz$' partner-portal-2026-03-archive.tar.gz
A directory listing check catches path mistakes early and confirms that the destination server received the right artifact name.
- Create the remote SFTP directory tree first when the destination path does not already exist.
$ curl --silent --output /dev/null \ --user releasebot: \ --key ~/.ssh/id_ed25519 \ --pubkey ~/.ssh/id_ed25519.pub \ --quote '*mkdir /home/releasebot/incoming' \ --quote '*mkdir /home/releasebot/incoming/releases' \ --quote '*mkdir /home/releasebot/incoming/releases/2026/03' \ sftp://sftp-upload.example.net/
Each --quote command runs before the transfer. The leading \* keeps reruns from aborting if one of the directories already exists.
- Upload the archive to the prepared SFTP path with SSH key authentication.
$ curl --upload-file partner-portal-2026-03-archive.tar.gz \ --user releasebot: \ --key ~/.ssh/id_ed25519 \ --pubkey ~/.ssh/id_ed25519.pub \ sftp://sftp-upload.example.net/home/releasebot/incoming/releases/2026/03/partner-portal-2026-03-archive.tar.gz % Total % Received % Xferd Average Speed Time Time Time Current 100 18.2M 0 0 100 18.2M 0 10.8M 0:00:01 0:00:01 --:--:-- 10.9M
When the file path should be resolved from the login account's home directory, the SFTP URL can also begin with /~/ instead of a full absolute path.
- List the remote SFTP directory and match the uploaded archive name before handing the file to an extract or deploy job.
$ curl --silent --list-only \ --user releasebot: \ --key ~/.ssh/id_ed25519 \ --pubkey ~/.ssh/id_ed25519.pub \ sftp://sftp-upload.example.net/home/releasebot/incoming/releases/2026/03/ | grep '^partner-portal-2026-03-archive.tar.gz$' partner-portal-2026-03-archive.tar.gz
Matching the archive name at the destination confirms that the remote path, authentication, and upload target were all correct.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.
