Guides 11792 Published by

The guide explains how a chroot jail can confine SSH sessions to a limited directory tree, protecting the rest of the system even if a user gains shell access. It walks through creating a minimal file hierarchy under /srv/chroot/ssh, copying only the essential binaries and libraries, setting root ownership and restrictive permissions so sshd will accept the session. By editing sshd_config with a Match User block that specifies ChrootDirectory, disables TCP and X11 forwarding, and forces internal‑sftp, it keeps users locked in an SFTP‑only sandbox while still allowing file transfers. The post also covers practical steps for adding a test user, restarting the daemon, troubleshooting common errors like missing /dev/null or improper permissions, and notes when a chroot is overkill if SSH is not exposed to the Internet.



Secure Your Remote Logins With a Chroot Jail in OpenSSH

OpenSSH is great, but if you let anyone log in from anywhere it can still expose your whole system. A chroot jail limits what an SSH session can see and do—think of it as a tiny sandbox that keeps users locked into one directory tree. In this guide we’ll walk through how to set up that sandbox so your remote accounts stay safe without over‑engineering the whole server.

1. Why You Should Use a Chroot Jail

A chroot jail forces the SSH process to see only a specific subtree of your filesystem. If someone manages to break out of their shell, they’re still stuck inside a world where /etc/passwd is just a file that belongs to the jail, not your real user accounts. This keeps the rest of your machine safe and limits potential damage from accidental mistakes or malicious users.

2. Quick Checklist Before You Start
  • Root access: you’ll need sudo or direct root login.
  • OpenSSH version ≥ 7.0 (most distributions ship it by default).
  • A clean, minimal directory you can copy essential binaries into—no extra packages that might create new attack vectors.
  • A backup of your current /etc/ssh/sshd_config; mistakes here can lock everyone out.
3. Create the Directory Structure
sudo mkdir -p /srv/chroot/ssh/{bin,lib,lib64,usr/bin}

Why each folder? bin and usr/bin will hold the binaries you want the user to run (e.g., /usr/bin/login). lib and lib64 are for the shared libraries those binaries depend on. If you forget any library the shell won’t start.

4. Copy in What You Need
sudo cp /bin/bash /srv/chroot/ssh/bin/
sudo cp -a /lib/* /srv/chroot/ssh/lib/
sudo cp -a /usr/lib/* /srv/chroot/ssh/lib64/

It’s tempting to copy everything, but that bloats the jail and introduces unnecessary files. Only bring what you need for a basic shell.

5. Set Permissions Right
sudo chown root:root /srv/chroot/ssh -R
sudo chmod 755 /srv/chroot/ssh/bin/bash

If you set the wrong permissions, sshd will refuse to start the session. The jail directory itself must be owned by root and not writable by users; otherwise the whole point collapses.

6. Configure sshd_config for Chroot

Edit /etc/ssh/sshd_config and add:

Match User chrooted_user
    ChrootDirectory /srv/chroot/ssh
    AllowTcpForwarding no
    X11Forwarding no
    ForceCommand internal-sftp

Match User scopes the jail to a single account. AllowTcpForwarding and X11Forwarding are disabled by default in a sandbox—enabling them would let users bypass the limited filesystem. ForceCommand internal-sftp ensures they can still transfer files securely.

7. Add a Dummy User for Testing
sudo useradd -d /home/chrooted_user -s /usr/bin/bash chrooted_user
sudo passwd chrooted_user

Create a minimal home inside the jail:

sudo mkdir -p /srv/chroot/ssh/home/chrooted_user
sudo chown chrooted_user:chrooted_user /srv/chroot/ssh/home/chrooted_user

This step is crucial; if you skip it, SSH will complain that the home directory doesn’t exist.

8. Restart SSHD and Test It
sudo systemctl restart sshd
ssh chrooted_user@yourserver

You should land in a shell that has only /bin, /lib, etc., visible. Try cd .. or cat /etc/passwd; you’ll hit “Permission denied” or “No such file.” If the session dies immediately, check the journal:

journalctl -xe | grep sshd
9. Common Pitfalls & What I’ve Seen

I once helped a friend on Debian 12 who updated OpenSSH and then found his SSH sessions dropping after every login. Turns out he’d omitted /dev/null from the chroot, so the shell tried to write logs there and failed. Adding this simple device file fixes it:

sudo mknod -m 666 /srv/chroot/ssh/dev/null c 1 3

Another trap: forgetting ForceCommand internal-sftp. Without it, users can try running arbitrary binaries that might escape the chroot if you accidentally copy a malicious library. The internal-sftp command keeps them strictly in SFTP mode unless you explicitly allow a shell.

10. When You Don’t Need It

If your server is only hosting services where remote access isn’t possible (e.g., an intranet-only web app), the extra setup may be overkill. Use chroot when you have exposed SSH to the Internet and want an extra safety net.

Give it a whirl, keep that sandbox tight, and enjoy a more secure remote login experience.