You are here
How to create new sftp user with access to /var/www
In what appears to be the new way I do things (i.e. here and here), following a question from TurnKey Hub user Rob, I'm posting this "tutorial" as a blog post.
Via Hub support, Rob asked about the best way to set up a user who can SFTP into his TurnKey WordPress server and upload/download files. He noted that he had followed my vague advice on a support thread (I'm not sure which one as he didn't explicitly say - perhaps one of these?). Regardless, it wasn't working as he'd hoped. I gave him some further limited, somewhat vague guidance, with an intention to look into it a little further and clarify details.
The more I dug, the clearer it became that there were a lot of intricacies and a lot of opinion about what is "best". Surely Rob is not the only one trying to do this?! So I decided to have a bit of a play with it and define a process that (hopefully) might be useful!?
The new SFTP user
In this "tutorial" post I'll document how to create an sftp user with write access to /var/www so that files can be uploaded/downloaded and modified. This will describe how to create a "locked down" user who can only access sftp, is "chroot jailed" within /var/www and can't log in via SSH at all.
If you're interested in configuring a limited SSH user who can log in, then I may cover that another day. If that interests you, please let me know (e.g. in the comments below).
Note that whilst I make every effort to document a secure setup, allowing any access to your server always has risks. The more access, the more risk. So whenever possible use the "principle of least privilege" and only give the user the permissions needed to do the required job and always only access to people you trust.
I've written these instructions specifically for TurnKey GNU/Linux v17.x (based on Debian 11/Bullseye), but they should work on any recent TurnKey system. It should also work on Debian or derivatives, e.g. Ubuntu. They may even work with other Linux systems, but there may be specific paths and commands that differ.
These instructions assume that you are running as root. If not, try prefixing commands with sudo, or better still, open a root terminal (e.g. 'sudo su -'). They also assume that the default webserver user group is 'www-data'.
Important note: Don't do this if you are hosting from /var/www
I consider it important that you DO NOT follow these instructions if your docroot is /var/www. These instructions require that /var/www is owned by root. Hosting from subdirectories is fine - otherwise move your docroot to a subdir first.
These instructions will make /var/www the HOME (i.e. '~') for this sftp user. So long as root maintains ownership of /var/www your sftp user won't be able to write files to /var/www so the risk of data leakage is minimal. However, if /var/www is owned by your new user (or www-data), ssh log in is allowed and you serve directly from /var/www (i.e. you don't follow these instructions), you risk leaking sensitive user info via your webserver; likely compromising the new user.
If you are using a TurnKey appliance that is based on LAMP; such as WordPress, Joomla, Drupal, Laravel, Nextcloud, or any of the other ones (about 70% of the library) you should be fine as they are hosted in a sub directory by default (e.g. /var/www/wordpress). Note that the base appliances (e.g. LAMP, LAPP, Ngnix, LigHTTPd) DO serve from /var/www docroot.
If you are hosting directly from /var/www then move your docroot before taking any of these steps. If you need a hand with that, please feel free to ask, be sure to share details of your setup.
Create the new user and add to 'www-data' group
Under normal circumstance, you would use 'adduser' to create a new user account. However, we have some specific requirements, so we're going to use the lower level 'useradd'.
Create the Linux user 'sftpuser' (change the name if you wish) with the specific requirements (use a better password):
useradd sftpuser --home-dir /var/www \ --gid www-data \ --shell /usr/sbin/nologin \ --password 'YourAwesomePassword'
Configure correct permissions
Assuming that the docroot is '/var/www/wordpress' (substitute your relevant docroot wherever you see '/var/www/wordpress' - e.g. '/var/www/drupal', '/var/www/joomla', etc) then "fix" permissions like this:
for dir in /var /var/www; do chown root:root $dir chmod 0755 $dir done chown -R www-data:www-data /var/www/wordpress
FYI permissions for '/var' & '/var/www' should probably be ok by default. But it won't work if they're wrong and resetting them to what they should be does no harm.
To ensure that our new user will have access to everything in /var/www, we'll need to ensure that the permissions allow group read & write. FYI the "execute permission" on directories is often called the "search bit" - and is required to view the directory contents. The below will also set the 'setgid' bit for directories which should make new files inherit the group ownership. TBH, I'm not 100% sure how (or if) that affects SFTP usage? Anyway, this should do the job:
find /var/www/wordpress -type d -exec chmod 2775 {} \; find /var/www/wordpress -type f -exec chmod 0664 {} \;
Configure SSH/SFTP
We also need to ensure that ssh is configured to use it's internal sftp code. You can check that like this:
grep ^Subsystem /etc/ssh/sshd_config
If it's already configured, it should return output like this:
Subsystem sftp internal-sftp
If it looks like that, you're good to skip to the specific user ssh config just below. Otherwise, edit the file to make it look like above. Here's a command that will update it for you:
sed -i "\|^Subsystem\tsftp| s|/usr/lib/openssh/sftp-server|internal-sftp|" /etc/ssh/sshd_config
Now add the SSH config which will catch the 'sftpuser' and apply this specific config:
cat >> /etc/ssh/sshd_config.d/sftpuser.conf <<EOF # SSH config for SFTP only user Match User sftpuser ForceCommand internal-sftp -u 002 ChrootDirectory /var/www/ PasswordAuthentication yes X11Forwarding no AllowTcpForwarding no AllowAgentForwarding no PermitTunnel no EOF
And now restart SSH:
systemctl restart ssh
That's it!
You should be able to download & upload files via SFTP using your new user. But not log in via SSH. A quick and dirty test can be done from the CLI:
touch test.html sftp sftpuser@localhost
That should ask for your sftpuser password and drop you into the chroot ('/var/www' - which will report as '/' in the sftp session) with an sftp prompt:
sftpuser@localhost's password: Connected to localhost. sftp>
Now you can 'put' the test file into the wordpress directory:
sftp> put test.html wordpress/ Uploading test.html to /wordpress/test.html test.html
Or:
sftp> cd wordpress sftp> put test.html Uploading test.html to /wordpress/test.html test.html
Then exit out and double check the test file:
ls -l /var/www/wordpress/test.html
It should return something similar to this:
-rw-r--r-- 1 sftpuser www-data 0 Oct 27 06:57 /var/www/wordpress/test.html
As you might have noticed (if you didn't follow my suggestion exactly), the default starting point will be /var/www, but the 'sftp' user will see that as '/' and won't have write permissions there (only in sub-directories). So as per my example above, either 'put' directly to the remote subdir, or cd to the desired remote subdir first.
Now you could also double check ssh login:
$ ssh sftpuser@192.168.1.114 sftpuser@192.168.1.114's password: This service allows sftp connections only. Connection to 192.168.1.114 closed.
A word on permissions
One thing that isn't as neat and tidy as I might like is the fact that the files won't always have write access by the webserver by default. The '-u 002' switch appended on the 'ForceCommand' directive sets the umask for the sftp user to '002' which should give group write permissions. But unfortunately, I hadn't considered that a mask is subtractive so it doesn't work as I had hoped. I'm not 100% sure how it might act when using an SFTP client from Windows, but when used from a Linux client, the existing permissions of the file(s) (before uploading to the server) are the starting point. So if the original file doesn't have group read/write access then the uploaded won't by default either.
So please be aware that you may hit issues if the webserver doesn't have write permissions to specific locations it may need (e.g. config.php needs to be writable to change config from the admin web UI).
The "fix" is to ensure that all files and directories have 'write' permissions. One way to do that is to rerun the find commands from above (as root):
find /var/www/wordpress -type d -exec chmod 2775 {} \; find /var/www/wordpress -type f -exec chmod 0664 {} \;
Or if you know the exact files/directories then you can chmod them. Files should be 664 and directories 775 (or 2775). Files can be changed via an SFTP shell (or client) too if you want. If using sftp shell, then it's very similar to in normal shell:
chmod 644 path/to/file
Good luck
Hopefully you find this of value. If you find it helpful, or have other feedback and/or suggestions, please feel free to post below.
Comments
Excellent! Much appreciated. :)
Thank you, Jeremy! This seems to be a common need on my TKL sites, so I really appreciate the detailed tutorial.
Best regards,
Rob (Very Siberian)
Amazing! Thank you very much
It would be much more helpful for my website project.
Thanks so much
Not working initially...
I tried to get fancy and change the "drop in" directory at /var/www/tobaron/html/ because I am sure that's possible somehow but my atempt at that failed, I couldn't log in, so I backed out and just followed your instructions and it worked - so that's good enough - gets the job done.
BTW where you wrote
I think you meant sftp user@localhost; you're missing a space
If you make /var/www/tobaron/html/ the home dir of user
IIRC if you make /var/www/tobaron/html/ the home directory of the user, then you should be able to get that to work.
Although I would NOT recommend using that path as it is likely being served. And if it's being served, then so are all the users files, unless you explicitly disable that in the webserver config. Whilst you could work around that via webserver config, I recommend making the dir one level up (i.e. /var/www/tobaron/) the user's home dir instead. Then they will still have access to the /var/www/tobaron/html/ directory, but limited risk of serving sensitive user files.
Also you'll need to ensure that the permissions are correct (owned by user, accessible by group). If you want to try again, please share a bit more info about the errors you hit and I'll do my best to help out.
Also, thanks for the heads up re the typo you found. You were totally on the money that it was wrong, although 'sftpuser' is the example username so it is missing the 'sftp' command completely. I.e. instead of:
It should be (and now is - I've updated/fixed it):
Not working on my side
TBH, I'm not sure?
I'm not sure why it's not working for you? I will try to rerun it myself to double check that it still works, but I'm not sure when that will be.
changing to subfolder in sftp.conf
Hello, with a small configuration in the sftp.conf file it is possible to configure the "wordpress" folder as the default folder after the user logs in.
I hope this helps.
Thanks for sharing! :)
Thanks for sharing! :)
I'm sure that others will find it useful.
More than one User
Hi.
First, nice Tutorial. Works fine.
Problem:
I would like to have more than one User.
f.e : user1, user2, user3
They all habe thier own folder under /var/www
So if i try to Setup like this, with more than one user, user1 will be able to cd into user2 directory because all are group of www-data.
How can i trap them in thier own folder /var/www/user{1|2|3} ?
TBH I'm not 100% sure exactly what you want?
TBH, I'm not 100% sure exactly what you want?
My example is for our WordPress appliance. The webserver only has access to /var/www/wordpress and the sftp user has read only access to /var/www and read/write to /var/www/wordpress. As something of an aside, I should actually edit my post to include Marco's suggestion. IMO that is a nice improvement on the use case in my post, although I'd like to double check that it works as expected first.
Back to your request; you say that you want the users "trapped" in their own subdir of /var/www. That will mean that the users won't have access to the other user dirs - or the WordPress dir. It will also mean that the webserver won't have access to the user dirs either. Assuming that is actually what you want, then their personal (aka home) dirs would be better in the standard location. E.g. /home/user1.
If you can clarify exactly what your want, or better still share what you are actually trying to achieve then I'll write it up for you. Hopefully I'll get to that soon after you post back, but I'm pretty busy ATM so no guarantees of timeframe. Hopefully speak most soon.
Pages
Add new comment