I am trying to set up a private repository via ssh. My sources.list.d/ contains the entry

deb ssh://user@host:/repo ./ 

user is a certificate only account on host. apt-get update works fine.

However, I would like to restrict the access to downloading the repository, i.e. disable shell access. If I set the user shell to rssh, allowing only scp and sftp, the update breaks.

From /var/log/syslog:

user user attempted to execute forbidden commands
command: /bin/sh

Why does apt need shell access on the repository machine, and is there a way to avoid this?

I noticed there is an github repository for apt-transport-sftp which I might have a look at, but I'd rather stick to more common packages for user convenience.

  • Did you read and understood the basic description of rssh? It’s a very restrictive shell, whereas apt-get needs the full system access to actually install or update anything. Sep 14, 2015 at 10:43
  • @IncnisMrsi apt-get does not install or update anything on the repository machine. As far as I can see, it only has to access the file structure and download the packages. It even knows which files to look for (Packages or Packages.gz)
    – relet
    Sep 14, 2015 at 11:41

2 Answers 2


What is APT doing remotely

I have set up a test account, and logged every command apt executed on the remote server by using a simple script as a replacement for the repo owner's shell. Apparently, apt is spawning a remote shell in order to find the full path to well-known files::

2015-09-14: Executing 'sh -c /bin/sh'; input and output follows:
find /tmp/repo/./InRelease -follow -printf '%s\n' 2> /dev/null || echo

find /tmp/repo/./Release.gpg -follow -printf '%s\n' 2> /dev/null || echo

find /tmp/repo/./Release -follow -printf '%s\n' 2> /dev/null || echo

find /tmp/repo/./Packages.bz2 -follow -printf '%s\n' 2> /dev/null || echo

find /tmp/repo/./it_CH.bz2 -follow -printf '%s\n' 2> /dev/null || echo

find /tmp/repo/./it.bz2 -follow -printf '%s\n' 2> /dev/null || echo

find /tmp/repo/./en.bz2 -follow -printf '%s\n' 2> /dev/null || echo

find /tmp/repo/./Packages.xz -follow -printf '%s\n' 2> /dev/null || echo


Therefore, I think you cannot restrict actions of the repo user via rssh, as: (1) the commands to be executed are being passed to the remote shell via STDIN (as opposed to SSH's remote exec feature), and (2) commands are shell pipelines.


If you still want to restrict actions performed by the repo user remotely, I see two ways forward:

  • Set the repo user's shell to rbash instead, and provide a customized $PATH setting with only the commands that need to be run. (Be sure to set $PATH and unset other shell variables from a startup file that cannot be written from the repo user.) This still leaves the possibility to anyone having the access credentials to read any file in the system.

  • Create a chroot jail with just the repo files and any command needed by APT, and set the repo user's shell to a script or program that performs chroot /jail "$@" instead.

Logging apt-get update actions

Here's the script I used to log actions executed remotely::


echo "$(date -I): executing 'sh $@'; input and output follows" >> /tmp/sh.log
tee -a /tmp/sh.log | /bin/sh "$@" | tee -a /tmp/sh.log
  • Thanks a lot for the analysis. Yes, I think chroot is the way to go. I guess finding the files instead of just assuming a path is somewhat more reliable with a seldom used apt protocol.
    – relet
    Sep 15, 2015 at 6:23

You have no way to avoid this.

With default ssh method, apt needs to login to remote server, call /bin/sh to get the shell access and does some work with some GNU utilities like find, dd.

The apt source code confirmed it:

 157       Args[i++] = "/bin/sh";
 158       Args[i] = 0;
 159       execvp(Args[0],(char **)Args);
 160       exit(100);

(It's surprising that apt still use find with -follow option, which marked deprecated)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .