
The fix is one FTP or SFTP account per website, chrooted, or jailed, to that site's own document root, so the account physically cannot see or write outside its own folder. Chrooting changes what the account's root directory (`/`) actually points to from that account's point of view — instead of the server's real filesystem root, an FTP client logging in as that account sees only its own site's folder as the top level, with no path, symlink, or `..` traversal that leads anywhere else on the box.
Each site needs its own document root already in place — for example `/home/clientname/sitename/public_html` — before you create the matching FTP or SFTP account, since the chroot path is set at account creation and points directly at that directory.
This doesn't require a full system account with a login shell for every client — that would be heavier than necessary and would clutter `/etc/passwd` with accounts that only ever need file transfer. There are two practical ways to get there on Ubuntu or Debian: Pure-FTPd's virtual users for plain FTP, or an SSH `Match User` block for SFTP. Both end at the same result — a scoped, jailed account with no reach beyond one directory.
Pure-FTPd, the FTP server CloudStick and many other panels use, supports virtual users stored outside `/etc/passwd`, each mapped to a specific home directory with chroot enabled by default in virtual-user mode. That's the standard way to give per-site FTP access without creating a full system or shell user for every client — the virtual user only exists in Pure-FTPd's own authentication database and has no ability to log in anywhere else on the server.
Each `pure-pw useradd` call takes its own directory argument, so repeating the command once per site — with a different username and a different document root each time — is how a single Pure-FTPd instance ends up serving ten fully isolated client accounts instead of one shared login. No shell access is granted, and none is needed for straightforward file uploads.
For SSH-based isolation instead of Pure-FTPd virtual users, the same `Match User` plus `ChrootDirectory` plus `ForceCommand internal-sftp` block used to jail a single SFTP user can be repeated per site in `/etc/ssh/sshd_config`, one `Match User` block per client account, each pointed at that site's own home directory.
One important requirement trips people up here: the chroot root directory itself must be owned by `root:root` and not writable by the chrooted user, with a writable subdirectory inside it for the actual uploads — sshd refuses to apply the chroot with a "bad ownership or modes" error if that ownership rule isn't satisfied. In practice that means `/home/acmecorp/website` stays root-owned while `public_html` underneath it, owned by the client's account, is where the files actually go.
Naming convention matters more than it sounds for a multi-client agency: name FTP accounts after the site, such as `ftp_clientname_sitename`, rather than a generic shared name like `ftpuser` or `webaccess`. A descriptive name means access can be revoked per client without touching anyone else's account when a contract ends, and it means an audit of `pure-pw list` or the sshd config six months from now still tells you exactly which client each account belongs to.
Rotating or revoking one client's FTP password should never require notifying or changing credentials for any other client — that's the entire point of per-site isolation, and it's the opposite of what a single shared FTP account gives you.
When a project wraps up or a developer rolls off a contract, deleting or disabling their one dedicated account is a single, contained operation — `pure-pw userdel` for that virtual user, or removing that one `Match User` block — that has zero effect on the other nine client accounts still running on the same server.
CloudStick creates a scoped FTP or SFTP account automatically for every website the moment it's created, chrooted to that site's own document root — there's no manual Pure-FTPd virtual-user command to run and no `sshd_config` file to edit by hand. SFTP is included on every plan, even Free, and plain FTP is added starting on the Basic plan and above, so the encrypted option is never gated behind a paid tier.
For an agency juggling a dozen client sites, this means handing a client SFTP access to exactly their own site takes one click in the dashboard instead of a `pure-pw useradd` command or a new `Match User` block written by hand, and revoking that access later never touches any other client's account. The isolation this article walks through by hand — one account, one chroot, one document root — is simply the default for every site the moment it's spun up, which is the practical difference between hardening a server after the fact and never having the shared-login problem in the first place.

