You're usually looking up Ubuntu SFTP server how to for one of two reasons. Either a partner has just asked for a “secure drop folder”, or someone inside the business is still moving sensitive files by email, shared drives, or consumer file-sharing tools that weren't built for controlled exchange. Both situations create the same problem: files are moving, but accountability, isolation, and security controls aren't.
A production SFTP build on Ubuntu isn't just about getting sftp to connect. It's about deciding who can upload, who can read, who should never get shell access, and how to stop a simple file transfer service becoming a path into the rest of the server. That matters even more when the same files feed finance workflows, supplier onboarding, logistics updates, or imports into an ERP.
When I set these up for real use, the difference between a lab build and a business-ready one comes down to intent. Every permission, every sshd_config line, and every disabled forwarding option needs a reason behind it. If you understand the reason, you're far less likely to deploy something that works on day one but fails under audit, partner expansion, or a bad login storm.
Table of Contents
- Why a Secure SFTP Server Is a Business Essential
- Laying the Foundation with OpenSSH Server
- Building a Secure Chroot Jail for SFTP Users
- Configuring and Hardening the SSH Daemon
- Bolstering Security with Keys Firewalls and Fail2Ban
- Advanced Setups and Operational Integrations
- Final Checks and Common Questions
Why a Secure SFTP Server Is a Business Essential
A secure SFTP server becomes necessary when file exchange stops being occasional and starts becoming operational. A manufacturer receiving CAD files, a distributor sending stock updates to a partner, or a finance team collecting structured exports from third parties all need more than “somewhere to upload a file”. They need encrypted transfer, controlled access, and a clear boundary between one external user and the rest of the server.
That business context has only become more relevant in the UK. The government's launch of the goods vehicle movement service in January 2021 marked a wider move towards digital customs handling and secure machine-driven exchange, which is why hardened SFTP is still a practical operational skill for manufacturers, wholesalers, and distributors rather than a legacy sideline, as noted in this GVMS and Ubuntu SFTP overview.
Email is poor at this job. Shared folders are often worse. They blur ownership, mix identities, and make it easy to overexpose data. SFTP on Ubuntu gives you a simpler control model: SSH transport underneath, explicit users, file permissions, and logs that can be reviewed when something goes wrong.
Where SFTP fits in daily operations
A lot of teams don't need a large managed file transfer platform. They need a reliable endpoint that does a small number of things properly.
- Partner exchange: Suppliers, brokers, and customers can drop files into a bounded location without seeing anything else on the host.
- System handoff: Batch files can move between line-of-business tools when an API isn't available.
- ERP intake: A controlled upload path works well for imports into platforms like Odoo ERP for operations-focused businesses.
A good SFTP service should feel boring. Predictable paths, narrow permissions, no shell access, and no surprises.
Before you touch sshd_config, it's worth tightening your remote administration habits as well. If you're reviewing access patterns, jump hosts, and admin hygiene alongside the SFTP build, these essential server access tips for professionals are worth a look.
Laying the Foundation with OpenSSH Server
SFTP on Ubuntu starts with OpenSSH. If the SSH daemon isn't installed, enabled, and behaving normally, nothing else matters. This is the layer that handles transport, authentication, and the policy controls you'll use later for chrooting and command restriction.

Install the service cleanly
Start with package metadata refresh, then install the server package:
sudo apt update
sudo apt install openssh-server
If you're building this on a hosted Ubuntu instance that will later run business applications, keep the base predictable. Don't pile SFTP onto an already messy general-purpose box if you can avoid it. Teams that are already standardising their application estate often pair this kind of service separation with managed Odoo hosting on Ubuntu infrastructure, which makes file exchange boundaries easier to reason about.
Once the package is installed, make sure the service is enabled and started:
sudo systemctl enable ssh
sudo systemctl start ssh
Confirm SSH is actually usable
Don't assume “installed” means “ready”. Check service status directly:
sudo systemctl status ssh
What you're looking for is straightforward. The service should be active, and there shouldn't be obvious startup errors. If the daemon is down, SFTP won't work because SFTP rides on SSH port 22 and depends on that service being available.
A simple baseline check sequence looks like this:
- Service status:
systemctl status ssh - Unit enablement:
systemctl is-enabled ssh - Listening behaviour: confirm the host firewall or cloud policy isn't blocking intended access
- Config file presence:
/etc/ssh/sshd_configshould exist and be readable by root
Practical rule: Get SSH healthy before you specialise it. Troubleshooting a broken daemon and a bad SFTP policy at the same time wastes hours.
At this point, open the SSH daemon config and inspect it without changing anything yet:
sudo nano /etc/ssh/sshd_config
You're looking for two things. First, the file is intact and understandable. Second, the Subsystem entry for SFTP exists in a normal state. Later, you'll apply a targeted Match Group block for SFTP-only users rather than trying to reshape the whole SSH service globally.
That distinction matters in production. Admins still need proper SSH behaviour, while external file-transfer users need a narrower experience. Mixing those two audiences under one blunt global config is where avoidable lockouts and overbroad access tend to start.
Building a Secure Chroot Jail for SFTP Users
The most important security control in a practical Ubuntu SFTP build is the chroot jail. It keeps the user inside a designated part of the filesystem and stops them browsing the rest of the server. If you skip this, you don't have a clean transfer endpoint. You have a user account with fewer conveniences and more risk.

Create a restricted user model
Start by creating a dedicated group for SFTP-only accounts:
sudo groupadd sftpusers
Now create a user that belongs to that group and has no interactive shell:
sudo useradd -m -s /usr/sbin/nologin -G sftpusers partner_a
sudo passwd partner_a
The no-shell setting matters because it removes a whole class of mistakes. If someone authenticates successfully, they shouldn't land in Bash, run commands, inspect processes, or poke around environment files. They should get file transfer only.
A minimal check after user creation helps avoid later confusion:
id partner_a
getent passwd partner_a
You should see the expected group membership and a shell set to nologin.
Build the directory layout the way SSH expects it
This is the part many copy-paste guides under-explain. The top of the chroot has to be owned by root, and the user must only get write access to a subdirectory inside it. If you make the jail root writable by the user, OpenSSH rejects the session.
Create a clean directory layout:
sudo mkdir -p /sftp/partner_a/uploads
sudo chown root:root /sftp
sudo chmod 755 /sftp
sudo chown root:root /sftp/partner_a
sudo chmod 755 /sftp/partner_a
sudo chown partner_a:sftpusers /sftp/partner_a/uploads
sudo chmod 750 /sftp/partner_a/uploads
This pattern matches standard Ubuntu/Linux hardening guidance. The jail itself is controlled by root. The writable area is one level lower and owned by the SFTP user. The practical rule is simple: the boundary is root-owned, the work area is user-owned.
Here's the structure in plain terms:
| Path | Owner | Purpose |
|---|---|---|
/sftp |
root:root |
Parent container for SFTP jails |
/sftp/partner_a |
root:root |
Chroot root seen as / by the user |
/sftp/partner_a/uploads |
partner_a:sftpusers |
Writable directory for file transfers |
A visual summary helps when you're handing this to another admin:
Why this ownership model matters
The reason isn't cosmetic. The point of chroot is containment. If the user can modify the top of that environment, the boundary itself becomes untrustworthy. OpenSSH is strict about this for exactly that reason.
As shown in this Linux SFTP chroot guidance, the chroot directory must be owned by root, while the writable subdirectory inside it belongs to the SFTP user. SSH rejects the connection if the jail's root is writable by the user.
The failed login often looks like an authentication issue when it's really a filesystem ownership issue.
What works and what doesn't
A few patterns hold up in production:
- Works well: One root-owned jail per partner, plus a named writable folder such as
uploads. - Works well: Group-based policy in SSH, because it scales cleanly when you add more accounts.
- Doesn't hold up: Putting the user directly into a writable home directory and calling it “restricted”.
- Doesn't hold up: Reusing human admin accounts for partner transfers.
If you need read-only access for some users, create a separate directory inside the jail with no write permission for that account. If you need upload-only workflows, handle that with permissions and downstream processing rather than trying to make SFTP itself behave like a public dropbox.
Configuring and Hardening the SSH Daemon
The filesystem is ready. Now the SSH daemon needs instructions. It is at this point that the SFTP-only policy becomes enforceable. The right way to do it is with a group-specific Match block at the bottom of /etc/ssh/sshd_config.
Use a Match block instead of global guesswork
Global SSH settings affect everyone. That's rarely what you want. Administrators may still need shell access, port forwarding for legitimate maintenance workflows, or different authentication policy. SFTP users should get a much narrower path.
Open the daemon config:
sudo nano /etc/ssh/sshd_config
Make sure the SFTP subsystem uses the internal handler:
Subsystem sftp internal-sftp
That internal handler matters because it keeps the SFTP service inside sshd rather than handing off to an external binary. Fewer moving parts usually means fewer permission surprises and a cleaner forced-command model.
The SSHD block to apply
Append a block like this near the end of the file:
Match Group sftpusers
ChrootDirectory /sftp/%u
ForceCommand internal-sftp
AllowTcpForwarding no
X11Forwarding no
If your environment uses key-based authentication for these accounts and stores keys in the user's normal home path, you may also need an AuthorizedKeysFile setting that points outside the chroot. Keep that design deliberate. Don't add it casually without checking where your keys live.
What each directive is doing
Match Group sftpusers is the scoping mechanism. It tells SSH to apply the following rules only to members of that group. This avoids collateral damage to normal admin access.
ChrootDirectory /sftp/%u places each user inside their own jail directory. %u expands to the username, which gives you a predictable layout without custom blocks per account.
ForceCommand internal-sftp is one of the most important lines in the file. It means even if the client tries something else, the session is handed straight to the internal SFTP subsystem.
Operational insight:
ForceCommand internal-sftpisn't just convenience. It removes ambiguity. The user authenticated for file transfer, so the server should provide file transfer and nothing else.
AllowTcpForwarding no closes off SSH forwarding features that have no place in a file-transfer-only account. Left enabled, forwarding can create routes you never intended to expose.
X11Forwarding no removes another unnecessary capability. Most SFTP users don't need it, so keeping it enabled only expands the attack surface.
A quick summary:
- ChrootDirectory: containment
- ForceCommand internal-sftp: no shell, no alternate command execution
- AllowTcpForwarding no: blocks tunnel-style misuse
- X11Forwarding no: removes irrelevant graphical forwarding capability
Once you save the file, don't restart immediately without validation. Syntax mistakes in sshd_config can lock you out of a remote host. The safe pattern is validate first, restart second. That validation step belongs in your standard operating procedure, not just in your memory.
Bolstering Security with Keys Firewalls and Fail2Ban
A working SFTP server isn't the same as a production-safe one. The base build handles isolation and access control. Real hardening adds stronger authentication, tighter network exposure, and an automatic response when someone starts hammering the login surface.

Stop relying on passwords
Passwords are easy to enable and painful to defend. For internet-facing SFTP, SSH keys are the better default. The UK's National Cyber Security Centre advises that password-based remote access is a common risk and recommends stronger methods such as SSH keys, which makes them especially relevant for SMEs handling sensitive file exchange, as noted in this Ubuntu SFTP security guide.
Generate a key pair on the client side, then place the public key in the server-side authorized_keys file for that user. The exact path depends on your design, but the usual requirements still apply:
.sshdirectory permissions: keep them tight and user-ownedauthorized_keyspermissions: readable to the account, not world-writable- Rotation practice: remove old keys when staff, suppliers, or devices change
Key auth reduces exposure to password guessing and credential reuse. It also gives you a cleaner offboarding process. Remove the key, and access stops.
Restrict network exposure
UFW is simple and effective for this use case. If the host only needs SSH/SFTP inbound, allow that and block the rest.
sudo ufw allow 22/tcp
sudo ufw enable
sudo ufw status
If you already know which office locations, VPN ranges, or bastion systems should connect, narrow the rule set further. Broad access plus strong auth is better than broad access plus weak auth, but narrow access plus strong auth is better still.
A compact decision table helps:
| Control | What it reduces | Common mistake |
|---|---|---|
| SSH keys | Password guessing and reuse | Leaving old keys in place |
| UFW rules | Unnecessary reachable services | Allowing too many ports “temporarily” |
| Chroot and forced SFTP | Lateral exposure after login | Treating transfer users like normal shell users |
Add automated response to bad login patterns
Fail2Ban gives the server some memory. Instead of logging repeated failures and doing nothing, it can identify patterns and block abusive sources automatically.
Install it:
sudo apt install fail2ban
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
For SSH-backed SFTP, the default SSH jail is usually the right place to start. You don't need an exotic setup to get value from it. What matters is that failed authentication attempts aren't allowed to continue indefinitely without consequence.
If you're building your own hardening checklist, this guide to preventing brute force attacks is a useful companion read because it helps frame Fail2Ban as one control in a wider defensive stack rather than a magic fix.
Security layers should overlap. If one control fails, the next should still make the attacker work.
What doesn't work well is picking only one of these measures. Keys without firewall discipline still leave a broad attack surface. Firewall rules without key auth still leave passwords exposed. Fail2Ban without either of the first two becomes a bandage instead of a design choice.
Advanced Setups and Operational Integrations
Most Ubuntu SFTP server how to articles stop after the first successful login. That's fine for a test box. It doesn't answer what happens when six partners become twenty, or when one user should only upload while another needs a controlled read path for outbound reports.
The operational gap is real. A common weakness in SFTP guidance is scaling beyond the first user, even though businesses often need multiple partner accounts, differing permissions, and governance that lines up with UK data-handling expectations, as highlighted in this multi-user Ubuntu SFTP discussion.
Move beyond the single-user tutorial
The cleanest pattern is to standardise user creation and directory layout. Don't hand-build every account from memory. Use a shell script, configuration management, or both.
A scalable model usually includes:
- One account per external entity: never share credentials across partners
- One jail per account: simpler logging, cleaner offboarding, fewer permission mistakes
- Role-specific directories: for example,
uploads,outbound, or a read-only reporting folder - Provisioning automation: Ansible or a scripted wrapper around
useradd, directory creation, and SSH key deployment
Upload-only workflows need careful wording. SFTP itself doesn't magically create a perfect blind drop. What teams usually mean is “the partner can write incoming files but shouldn't browse unrelated data”. You can get close by giving write access only to a dedicated inbound folder and handling post-upload processing elsewhere on the server.
The first user proves the concept. The tenth user tests whether your model is actually maintainable.
Use SFTP as a controlled handoff point for business systems
SFTP moves beyond being solely an infrastructure task. In many businesses, it becomes the handoff layer between external parties and internal systems. Supplier price lists arrive overnight, a scheduled job validates them, and then an ERP imports approved records. Or a warehouse system exports stock snapshots that another platform consumes each morning.
That model is often easier to govern than ad hoc email attachments because the transfer path, naming conventions, and access rules are explicit. It also fits naturally with Odoo integration work across external systems, where SFTP can act as the controlled intake path when APIs aren't available or a partner insists on flat-file exchange.
A practical operating model often looks like this:
- External party uploads to their dedicated
uploadsdirectory. - A scheduled job validates file name, structure, and timestamp.
- Valid files move into a processing area not writable by the external user.
- The business application imports or reconciles the data.
- Logs record what arrived, what failed, and what was consumed.
That separation matters. It prevents an external account from writing directly into application-owned directories, which is exactly the kind of shortcut that creates compliance and data integrity headaches later.
Final Checks and Common Questions
Before you hand credentials to a partner or point an integration job at the server, validate the whole path. Real-world failures usually come from small operational misses, not big architectural flaws.

Pre-go-live verification
Validate the SSH configuration before any restart:
sudo sshd -t
That step is critical. In real deployments, common failures include forgetting to restart sshd after a configuration change, getting chroot ownership wrong, or leaving forwarding options enabled when they should be off. Validating with sshd -t before restart is a key best practice, as described in this Ubuntu SFTP troubleshooting walkthrough.
Then apply the configuration:
sudo systemctl restart ssh
Run a client-side login test and verify behaviour, not just connectivity.
- Successful login: confirm the user can authenticate by password or key, depending on your design
- Jail enforcement:
pwdand directory navigation should keep the user inside the intended root - Transfer test: upload a file into the writable directory, then confirm expected ownership and location
- Permission test: try writing outside the allowed directory and make sure it fails
- Log review: inspect SSH logs for warnings, denied actions, or path problems
A login that succeeds but lands in the wrong place is not a passing test.
Common questions
Can I change the default port?
Yes, but treat it as exposure management, not core security. It can reduce noise, but it doesn't replace keys, firewall rules, and proper user isolation.
What's the difference between SFTP and FTPS?
SFTP runs over SSH. FTPS is FTP with TLS added. They are different protocols. On Ubuntu, SFTP is usually simpler to manage because it uses OpenSSH and a single service model.
How do I monitor transfer activity?
Start with SSH logs and journal output. For business use, make sure you can answer basic questions: who connected, when they connected, and whether transfers succeeded or failed.
Why does the user authenticate but then get disconnected?
Check chroot ownership first. If the jail root is writable by the user, SSH commonly rejects the session after login.
Should I reuse one account for several partners?
No. Shared accounts destroy accountability and make revocation messy.
If your team is connecting SFTP workflows to ERP imports, partner onboarding, inventory feeds, or custom automation, ERP Artists can help design the wider process around Odoo, integrations, hosting, and operational controls so the file transfer layer fits the business instead of becoming another isolated admin task.