Service SSH accounts often need one allowed action instead of an interactive shell. A forced command lets a backup, deployment, Git, or transfer account authenticate while the server ignores the shell or remote command that the client requested.
OpenSSH applies forced commands through the server configuration or through key-level restrictions. A server-level ForceCommand inside a Match User block makes every login for one account run the same root-owned wrapper, and the original client request remains available to the wrapper as SSH_ORIGINAL_COMMAND.
An external forced command is invoked through the user's login shell with -c, so the matched account still needs a usable shell for this pattern. Keep a separate administrator session or console path available before reloading sshd_config, because a wrong Match block, wrapper path, or shell setting can block the restricted account from completing any session.
Steps to enforce an OpenSSH forced command for a user:
- Open a terminal on the SSH server with an account that can use sudo.
- Keep an unaffected administrator session open.
- Confirm the account that should receive the forced command.
$ id backupuser uid=1002(backupuser) gid=1002(backupuser) groups=1002(backupuser)
Replace backupuser with the dedicated automation or service account. Avoid testing this first on a shared administrator account.
- Create the forced-command wrapper as root.
$ sudoedit /usr/local/sbin/ssh-forced-command
- Save the wrapper script.
#!/usr/bin/env bash printf 'Forced command executed for %s.\n' "${USER:-unknown}" printf 'Requested command: %s\n' "${SSH_ORIGINAL_COMMAND:-none}"
Use this smoke-test body first. After the restriction works, replace the printf lines with the production backup, Git, transfer, or deployment command.
- Set root ownership on the wrapper.
$ sudo chown root:root /usr/local/sbin/ssh-forced-command
- Set executable permissions on the wrapper.
$ sudo chmod 0755 /usr/local/sbin/ssh-forced-command
- Back up the active SSH daemon configuration.
$ sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.pre-force-command
A bad sshd_config edit can block new SSH sessions. Keep a console path or another already-open administrator session available until the final login test succeeds.
- Edit the SSH daemon configuration.
$ sudoedit /etc/ssh/sshd_config
- Add the Match User block at the end of the file.
Match User backupuser ForceCommand /usr/local/sbin/ssh-forced-command PermitTTY no DisableForwarding yesForceCommand overrides the requested shell, remote command, or subsystem for the matched user. PermitTTY no blocks terminal allocation, and DisableForwarding yes blocks TCP, agent, X11, and stream-local forwarding for that account.
- Test the SSH daemon configuration syntax.
$ sudo sshd -t
No output means sshd parsed the active configuration without a blocking syntax error.
Related: How to test SSH server configuration
- Reload the SSH service.
$ sudo systemctl reload ssh
Use sudo systemctl reload sshd on distributions that package the service as sshd.
- Test the restricted account from a separate SSH client.
$ ssh backupuser@host.example.net 'uname -a' Forced command executed for backupuser. Requested command: uname -a
The absence of uname output confirms that OpenSSH ignored the client-requested command and ran the configured wrapper instead.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.