This article describes how to setup a SFTP server installation, plus some advices from a security point of view.
The users will find themselves inside a chrooted environment, and the file system permissions are active:
Every user may have a seperated, isolated environment.


Step 1: Prepare your system

Create a group for users that are allowed to use sftp, and add some users to it. Since those users communicate with the ssh server without needing a login shell, we will disable shell access for them by setting /bin/false as login shell.

root@testkraxn /home/tester # groupadd sftponly
root@testkraxn /home/tester # cat /etc/group | tail -n 1

root@testkraxn /home/tester # useradd garfield -d / -g 1001 -M -N -o -u 1001
root@testkraxn /home/tester # passwd garfield
Enter new UNIX password: 
Retype new UNIX password: 
passwd: password updated successfully

root@testkraxn ~tester # chsh garfield
Changing the login shell for garfield
Enter the new value, or press ENTER for the default
        Login Shell [/bin/sh]: /bin/false
root@testkraxn /home/tester # cat /etc/passwd | tail -n 1

Step 2: Configure the SSH Server

root@testkraxn /home/tester # cp /etc/ssh/sshd_config /etc/ssh/sshd_config.`date +%F_%T`.backup
root@testkraxn /home/tester # vim /etc/ssh/sshd_config

replace line:

Subsystem sftp /usr/lib/openssh/sftp-server


Subsystem sftp internal-sftp

Then, append these lines at the end of the file:

Match group sftponly
    ChrootDirectory /var/www
    X11Forwarding no
    AllowTcpForwarding no
    ForceCommand internal-sftp

my whole config, to be complete here:

root@killerkraxn ~ # grep -vE '^\s*(#.*|)$' /etc/ssh/sshd_config
Port 22
Protocol 2
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_dsa_key
UsePrivilegeSeparation yes
KeyRegenerationInterval 3600
ServerKeyBits 768
SyslogFacility AUTH
LogLevel INFO
LoginGraceTime 120
PermitRootLogin yes
StrictModes yes
RSAAuthentication yes
PubkeyAuthentication yes
IgnoreRhosts yes
RhostsRSAAuthentication no
HostbasedAuthentication no
PermitEmptyPasswords no
ChallengeResponseAuthentication no
X11Forwarding yes
X11DisplayOffset 10
PrintMotd no
PrintLastLog yes
TCPKeepAlive yes
AcceptEnv LANG LC_*
Subsystem sftp internal-sftp
UsePAM yes
Match group sftponly
    ChrootDirectory /data/sftpusers
    X11Forwarding no
    AllowTcpForwarding no
    ForceCommand internal-sftp

Step 2: Create some test directories

I use a script like this to create a new user: (run as root)

echo crating user: $NEW_USER

useradd $NEW_USER -d / -G sftponly -M -s /bin/false
groups $NEW_USER

cd /data/sftpusers

echo "setting up home directories..."

mkdir $NEW_USER
chown root:$NEW_USER $NEW_USER
chmod 750 $NEW_USER

mkdir $NEW_USER/readonly
chmod 755 $NEW_USER/readonly
echo "you cannot change this file" > $NEW_USER/readonly/test.txt
chmod 644 $NEW_USER/readonly/test.txt

mkdir $NEW_USER/readwrite
echo "delete me if you wish" > $NEW_USER/readwrite/test.txt
chown $NEW_USER:$NEW_USER -R $NEW_USER/readwrite

mkdir $NEW_USER/no-access
chmod 700 $NEW_USER/no-access
echo "you won't ever read this, douchebag!" > $NEW_USER/no-access/test.txt

echo "you should set a password for the user: passwd $NEW_USER"

If you want to provide access to other folders to the users, you can mount the directory into the users base dir.
In this example, i will grant access to /media/misc/foo to the user garfield:

root@testkraxn ~ # mkdir -p /data/sftpusers/garfield/media
root@testkraxn ~ # mount --bind /media/misc/foo  /data/sftpusers/garfield/media
Finally, the directory structure for the user looks like this:
root@killerkraxn /data/sftpusers # tree
└── garfield
    ├── no-access
    │   └── test.txt
    ├── readonly
    │   └── test.txt
    ├── readwrite
    │   └── test.txt
    └── misc
        └── foo --> mountpoint of /media/misc/foo
            └── foo-contents

Restart the ssh server and test the setup:

root@testkraxn ~ # service ssh restart
andre@buenosaires ~ % sftp garfield@
garfield@'s password: 
Connected to

sftp> cd /
sftp> pwd
Remote working directory: /

sftp> ls
foo readonly readwrite no-access

sftp> cd no-access
sftp> pwd
Remote working directory: /no-access

sftp> ls
remote readdir("/no-access"): Permission denied

sftp> cd /readwrite
sftp> mkdir bar
sftp> ls
bar test.txt

sftp> cd /readonly
sftp> mkdir bar
Couldn't create directory: Permission denied

sftp> ls

sftp> cd /misc
sftp> pwd
Remote working directory: /misc
sftp> ls
sftp> exit

And the users do not have access to a shell when trying to connect via ssh:

andre@buenosaires ~ % ssh garfield @
garfield@'s password: 
This service allows sftp connections only.
Connection to closed.