A partner wants to drop a file on your server every night. Finance, logistics, a payroll bureau, a supplier with a spreadsheet and a deadline. SFTP is the sensible answer, and then you notice the awkward part: unlike your internal servers, this one has to be reachable by people who are not in your building, on networks you do not run.
That changes the job. You cannot simply close the port. You have to decide who gets through it, what they can do once inside, and how you find out if that goes wrong.
What does “secure” mean for a partner SFTP server?
Three questions, in this order.
Who can connect? Only named partners, from as few places as practical. What can they do? Move files in one folder. Nothing else: no shell, no tunnelling, no looking at the neighbour’s files. Can you tell what happened? Every login and transfer logged, and someone who reads the logs.
SFTP itself, the file transfer protocol that runs over SSH, is fine. The risk is almost never the protocol. It is the shared account, the home directory that is really the whole disk, and the port that has been open to the world since 2019.
Lock each partner into a single directory
OpenSSH has what you need built in. Per the sshd_config manual, ChrootDirectory confines a session to a directory, and ForceCommand internal-sftp runs an SFTP server inside sshd instead of a shell, “ignoring any command supplied by the client.”
A typical block for a group of partner accounts looks like this:
Match Group partners
ChrootDirectory /srv/sftp/partner-a
ForceCommand internal-sftp
AllowTcpForwarding no
PermitTTY no
PasswordAuthentication no
The manual describes AllowTcpForwarding as controlling whether TCP forwarding is permitted (the default is yes) and PermitTTY as controlling whether a pty is allocated (also yes by default). For a file drop, you want both off. A partner who can only upload files cannot use your server as a stepping stone to your network.
There is one trap. For the chroot to work, the manual requires that “all components of the pathname are root-owned directories which are not writable by group or others.” So the jail itself is owned by root, and the partner writes into a subdirectory inside it. People lose an afternoon to this. Now you will lose less.
Give every partner their own account and their own directory. One shared “partners” login means you cannot revoke one company without breaking all of them, and you cannot tell whose credentials were used.
Use keys, not passwords
A password on an internet-facing login is something bots can guess around the clock. OpenSSH lets you turn it off: PasswordAuthentication “specifies whether password authentication is allowed”, and the default is yes, so you have to switch it off yourself. For stricter control, AuthenticationMethods sets which methods “must be successfully completed” for access.
Ask each partner for a public key. Their IT team will know what that means; if they do not, that is useful information about the partner. Record whose key it is and when it expires, because a key nobody remembers is a password nobody can rotate.
Shrink the audience
Partners tend to connect from a small number of places: a head office, a data centre, a cloud account. CISA’s exposure guidance says to “close or restrict access to ports that do not have a documented operational need”, and for assets that do not need to be internet accessible, to “implement measures to remove or restrict access.”
In OpenSSH, AllowUsers can restrict “login… only for user names that match one of the patterns”, and it accepts a USER@HOST form to restrict the source as well. A firewall allow-list does the same job one layer earlier. If you use AWS Transfer Family, note that AWS advises against placing a network load balancer in front of the server, because it hides user source IPs.
A source restriction has a limit. Partners change providers, work from home and use VPNs that change addresses, so the list needs an owner. A stale allow-list is merely a slower version of “open to everyone.”
Compare the common ways to host it
| Approach | Who patches the SFTP software | Inbound port on your network | Best when |
|---|---|---|---|
| OpenSSH on your own server | You | Yes, usually 22 | You want data on your own hosts |
| Managed SFTP (e.g. AWS Transfer Family) | The provider | Provider’s endpoint, not yours | Files belong in cloud storage anyway |
| Server behind a broker with no inbound listener | You | No | Partners can use a defined access path |
AWS describes Transfer Family as a service for transferring files “over SFTP, AS2, FTPS, FTP”, with common uses that include “uploads from third parties such as vendors and partners.” It moves the patching burden, not the access decisions. Someone still has to say which partner reaches which folder.
A short routine for onboarding and offboarding
- 1Name the needWho, what folder, until when
- 2Create the accountOwn user, own jail, key only
- 3Restrict the sourceKnown addresses or a broker
- 4Log and reviewLogins and transfers, read by a person
- 5Remove on expiryContract ends, account goes
The last step is the one that gets skipped. Accounts outlive contracts, and a dormant partner account is a login nobody is watching. Put an end date in the ticket on day one, and make someone responsible for noticing it.
Where SSHepherd fits
If the awkward part is that the SFTP server must be reachable from outside, SSHepherd® removes that requirement. It closes the externally exposed listening port on the server: the server and the people who need it connect outbound to a broker, which joins them only for authorised identities. A scan of your network finds no port 22 to try, and partner sessions can be monitored and ended. It works for SSH and file transfer, takes about ten minutes to deploy on a server, and needs no network re-architecture. It does assume the partner can use the access path you give them, so check that before you promise it. See SSHepherd and the file transfers use case.
The bottom line
A partner SFTP server has to be reachable, so make reaching it worth very little: one account, one jailed folder, a key instead of a password, a short list of allowed sources, logs someone reads, and an end date. Where you can, take the open port away entirely.