Non-Interactive Shell
How to Create Non-Interactive & Restricted Shell Users in Linux
A practical guide to locking down user access while keeping your system functional
The Problem
You need users to run specific tasks on your Linux server — Git pushes, file uploads, or service processes — but you don’t want them browsing your filesystem or running arbitrary commands.
The solution? Non-interactive shells and restricted environments.
Let me show you exactly how to set this up.
The Basics — Non-Interactive Users
These users can own processes and files, but cannot get a shell.
Quick Setup
1
2
3
4
5
# For service accounts (recommended)
sudo useradd -s /sbin/nologin -r username
# For existing users
sudo usermod -s /sbin/nologin username
How to Verify Non-Interactive Users Without Logging In
You don’t need to actually log in as the user to confirm they’re non-interactive. Here are 5 ways to verify from your admin account.
Check the Shell Assignment (Quickest)
1
2
3
4
5
# View the user's shell directly
grep username /etc/passwd
# Or using getent (works with LDAP/SSSD)
getent passwd username
1
username:x:1001:1001::/home/username:/sbin/nologin
If the last field is /sbin/nologin, /bin/false, or another restricted shell → non-interactive
Test Command Execution (Safest)
Run a command as the user without starting a shell:
bash
Try to run a simple command
sudo -u username whoami
Try to list directories
sudo -u username ls -la /
Try to start a shell
sudo -u username bash -c "echo test"
Complete List of Non-Interactive Shells in Linux
Built-in System Shells
| Shell | Path | Behavior | Use Case |
|---|---|---|---|
/sbin/nologin |
/sbin/nologin |
Shows “This account is currently not available” | Most common - Service accounts |
/bin/false |
/bin/false |
Exits with code 1, no output | Minimal accounts, automated scripts |
/bin/true |
/bin/true |
Exits with code 0, no output | Placeholder accounts |
/dev/null |
Not a shell | Redirects everything to void | Ultimate restriction |
Application-Specific Restricted Shells
| Shell | Path | Allowed Actions | Install Command |
|---|---|---|---|
git-shell |
/usr/bin/git-shell |
Git push/pull/fetch only | sudo apt install git |
scponly |
/usr/bin/scponly |
SCP/SFTP only | sudo apt install scponly |
rssh |
/usr/bin/rssh |
SFTP/SCP/rsync/cvs/svn | sudo apt install rssh |
jailkit |
/usr/sbin/jk_lsh |
Configurable allowlist | sudo apt install jailkit |
rbash (Restricted Bash) |
/bin/rbash |
Limited commands (configurable) | Built-in (part of bash) |
Special Purpose Shells
| Shell | Path | Purpose |
|---|---|---|
/usr/bin/passwd |
/usr/bin/passwd |
Password change only |
/usr/sbin/chpasswd |
/usr/sbin/chpasswd |
Batch password updates |
/bin/sync |
/bin/sync |
Force filesystem sync only |
/sbin/halt |
/sbin/halt |
Shutdown only (rare) |
/sbin/reboot |
/sbin/reboot |
Reboot only (rare) |
Custom / Third-Party Shells
| Tool | Description | Install Method |
|---|---|---|
| lshell | Limited shell with path restrictions | pip install lshell |
| rbash (Restricted Bash) | Bash with restrictions | Built-in |
| zsh restricted mode | Restricted Zsh | sudo apt install zsh |
| fish restricted | Restricted Fish shell | sudo apt install fish |
| chsh restricted | Custom compiled shells | Advanced |
Complete Comparison Table
| Shell | Interactive? | Can run commands? | Shows message? | Exit code | Security Level |
|---|---|---|---|---|---|
/bin/bash |
✅ Yes | ✅ Yes | N/A | 0 | None |
/sbin/nologin |
❌ No | ❌ No | ✅ Yes | 1 | High |
/bin/false |
❌ No | ❌ No | ❌ No | 1 | High |
/bin/true |
❌ No | ❌ No | ❌ No | 0 | High |
/usr/bin/git-shell |
❌ No | ⚠️ Git only | ✅ Yes | Varies | Medium |
/usr/bin/scponly |
❌ No | ⚠️ SCP/SFTP only | ✅ Yes | Varies | Medium |
/usr/sbin/jk_lsh |
❌ No | ⚠️ Allowlist only | ✅ Yes | Varies | High |
/bin/rbash |
⚠️ Restricted | ⚠️ Limited | ✅ Yes | Varies | Medium |
/usr/bin/rssh |
❌ No | ⚠️ Limited protocols | ✅ Yes | Varies | Medium |