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.
$ 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.
$ sudoedit /usr/local/sbin/ssh-forced-command
#!/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.
$ sudo chown root:root /usr/local/sbin/ssh-forced-command
$ sudo chmod 0755 /usr/local/sbin/ssh-forced-command
$ 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.
$ sudoedit /etc/ssh/sshd_config
Match User backupuser
ForceCommand /usr/local/sbin/ssh-forced-command
PermitTTY no
DisableForwarding yes
ForceCommand 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.
$ sudo sshd -t
No output means sshd parsed the active configuration without a blocking syntax error.
Related: How to test SSH server configuration
$ sudo systemctl reload ssh
Use sudo systemctl reload sshd on distributions that package the service as sshd.
$ 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.