196

I want to stop having to use sudo everytime I work in /var/www. How can I do that? I simply want to put all of my sites into this directory and work with them without too much pain.

Lekensteyn
  • 174,277
TaylorOtwell
  • 2,095
  • 3
    Are you using apache? – Rinzwind Jun 01 '11 at 05:29
  • 1
    After reading here, this can also help in the permission part: http://askubuntu.com/questions/20105/reasons-why-var-www-should-not-have-chmod-777 – Luis Alvarado Jun 01 '11 at 13:31
  • 2
    Another way to get safety is to continue to use sudo -u www-data but restrict yourself in the sudoers file to only be able to sudo www-data (and not sudo root). See http://serverfault.com/questions/295429/is-it-possible-to-enable-sudo-u-only-for-specific-users – Simon Woodside May 31 '16 at 04:18

8 Answers8

278

Most answers here are not written with security in mind. It's good to get a feeling that running sudo each time is not very wise. If you make a typo (for example a single space in a wrong place, such as recursively deleting / var/www/dir, which means / and var/www/dir, instead of /var/www/dirplease do not attempt), you might trash your system.

Note: Starting with Apache 2.4.7 / Ubuntu 14.04, /var/www has been moved to /var/www/html Adjust the commands in this answer accordingly.

See:

Bad ideas:

  • chmod 777 (sagarchalise) - this allows anyone with access to your system write into the directories and files and thereby allowing the intruder to execute any code under the www-data user
  • chgrp -R www-data $HOME (cob) - this allows www-data to read or write any files in the home directory. This is not keeping the Least Privilege rule in mind
  • chown -R $USER:$USER /var/www (kv1dr) - unless the world has read permissions on /var/www, the webserver running under www-data will not be able to read (serve) the files. If the file is a public-accessible plain HTML document, it might not be an issue if the world can read the file. But if the file is a PHP file containing passwords, it is.

NOTE: in the below solutions, I've granted www-data write privileges. However, /usr/share/doc/base-passwd/users-and-groups.txt.gz states:

www-data

Some web servers run as www-data. Web content should not be owned by this user, or a compromised web server would be able to rewrite a web site. Data written out by web servers will be owned by www-data.

Where possible, do not grant write permissions to the www-data group. www-data only needs to be able to read the files so the webserver can serve it. The only case where www-data needs write permissions is for directories storing uploads and other locations which needs to be written.

Solution 1

Add yourself to the www-data group and set the setgid bit on the /var/www directory such that all newly created files inherit this group as well.

sudo gpasswd -a "$USER" www-data

Correct previously created files (assuming you to be the only user of /var/www):

sudo chown -R "$USER":www-data /var/www
find /var/www -type f -exec chmod 0660 {} \;
sudo find /var/www -type d -exec chmod 2770 {} \;

(even safer: use 640 or 2750 and manually chmod g+w file-or-dir that needs to be writable by the webserver)

Solution 2

Create a symlink for each project to your home directory. Say your project is located at ~/projects/foo and you want to have it located at /var/www/foo, run:

sudo ln -sT ~/projects/foo /var/www/foo

If your home directory has no execute bit (descend) set for other (for security reasons), change the group of it to www-data, but set the execute bit only (no read/write). Do the same for the ~/projects folder as it may contain other projects than www. (You don't need sudo if you have previously added your user to the www-data group.)

sudo chgrp www-data ~ ~/projects
chmod 710 ~ ~/projects

Set the group to www-data on ~/projects/foo and allow the webserver to read and write to files and files+directories and descend into directories:

sudo chgrp www-data ~/projects/foo
find ~/projects/foo -type f -exec chmod 660 {} \;
find ~/projects/foo -type d -exec chmod 2770 {} \;

Even safer: use 640 and 2750 by default and manually chmod files and directories that need to be writable by the webserver user. The setgid bit should be added only if you want every newly created file in ~/projects/foo to be accessible by the group.

From now on, you can access your site at http://localhost/foo and edit your project files in ~/projects/foo.

See also

Eliah Kagan
  • 117,780
Lekensteyn
  • 174,277
  • What do you think about a www-session in a terminal by sudo su www-data? Combined with a differently colored prompt, to make it more obvious that it is the shell of a different user, and a policy always to put the corresponding xterm on - for example - the virtual desktop 4, so that you get used to it, to avoid confusion? – user unknown Jun 01 '11 at 15:18
  • @user unknown: if you do everything in the terminal fine as you've a clear separation between user-accounts. But it's not going to work if you use a GUI program like gedit. I've never researched whether running a GUI program under an other user in the current session is safe or not, it would be an interesting question. – Lekensteyn Jun 01 '11 at 15:26
  • can you split your 2 solutions up into separate responses so they can be voted/selected independently? – ImaginaryRobots Jun 01 '11 at 20:25
  • 1
    @imaginaryRobots: if I was going to post different solutions for every question, Askubuntu would be full of answers of three lines. I'll keep it as is unless you can convince me to split it. – Lekensteyn Jun 02 '11 at 12:32
  • @Lekensteyn, a few questions: sudo chown -R "$USER":www-data /var/www, $USER will be the logged in user right? find /var/www -type f -exec chmod 0660 {} \; what does the {} \; do? – Jiew Meng Dec 23 '11 at 12:59
  • $USER will be the user you see in the shell, e.g. user in user@machine:~$. You can fill it in if you prefer that. {} \; is a characteristic of the find. {} is substituted for the path to the file, ; ends the arguments for -exec. The backslash is necessary to escape the ; because it has a special meaning in bash. You could have used '\' as well. – Lekensteyn Dec 23 '11 at 13:44
  • I realize this is old, but it seems to me that "Solution 1" is not useful. What purpose does it serve to add to the group "www-data", since files written by www-data usually have read-only access, same as the world permissions? – Marty Fried Oct 07 '12 at 17:45
  • @MartyFried The default umask is 022 which makes files indeed world-writable. I tend to set a more stricter umask, like 027 and adjust the existing permissions accordingly (as you can see in the example, I use 640 for files and 750 for dirs). Otherwise, if you allow the world to see your file source, why not put it on Github or something? – Lekensteyn Oct 07 '12 at 20:03
  • How do you know the umask? But more importantly, why is it that the files I see written by Apache are not world writable, or even group writable? What files are you referring to that are world writable? If this is getting too one-on-one, we could create a chat, but unless I'm missing something basic, it seems like it might be useful to others. There's so much mis-information everywhere about this (including right here, as you mentioned). – Marty Fried Oct 07 '12 at 20:21
  • Sorry, I misunderstood the umask default - I thought you meant for Apache, but it seems you mean for all files. Doesn't Apache change this? – Marty Fried Oct 07 '12 at 20:40
  • No sane configuration should make a file world-writable. IIRC apache has a umask setting in /etc/apache2/... (envvars?). grep for it, or look in the init script that it uses. – Lekensteyn Oct 07 '12 at 22:18
  • Solution 1 => It works for installing web software without sudo => After installation, added files does not serve! I mean if I add a local folder to translate software, I should manually change folder Group from my username to www-data to make folder be served by the software! how can I get rid of this manual swapping of permissions on new files & folders? – mini Mar 27 '14 at 15:33
  • @onrea When you move a folder, the permissions do not change. Either copy them or make a script that automates this for you. – Lekensteyn Mar 27 '14 at 22:20
  • @Lekensteyn - I only ask because I'm not sure: For Solution 2, should the setguid bit be set just like Solution 1, so that new files and directories inherit the group www-data? – Andrew Cheong Apr 29 '14 at 12:27
  • @AndrewCheong I've updated the answer. Now solution 2 will also set the setgid bit for directories. This has as consequence that files created by the user will get the www-data group. If the web user creates a file, then it will also be in the www-data group, but you (as a user) will probably be unable to modify it unless you change the owner (or add write permissions). – Lekensteyn Apr 29 '14 at 13:36
  • @Lekensteyn - Ah, thank you! I'm currently putting together a survey of all the "canonical" webserver permissions answers on askubuntu.com, SO, SF, SU, unix.se, and webmasters.se, so I'm trying to make sure things like that are merely missed details, not something on purpose e.g. "Do not set the setgid bit in this method." Not meaning to be nitpicky for no reason; I like your method a lot. – Andrew Cheong Apr 29 '14 at 13:44
  • @AndrewCheong It's indeed something I overlooked, thanks for your feedback. Actually, since the default umask is 022, it did not really matter whether the setgid bit was set or not. In either case, the world (including www-data) could read it. – Lekensteyn Apr 29 '14 at 15:22
  • For solution 1: would it be a good idea to apply setfacl -d -m u::rwX,g::r,o::- /var/www too? – berbt Feb 15 '16 at 21:55
  • 1
    @berbt setfacl -d u::rwX,g::rX /var/www has the funny effect that the default mode becomes 0750 (or 0640) even if the umask is zero. It might be a good idea if you want to avoid world-writable files, but if /var/www is already inaccessible by the world it is not needed. – Lekensteyn Feb 16 '16 at 10:38
  • I tried solution 1, and Wordpress wouldn't update because owner and apache user didn't match. – Menasheh Sep 24 '17 at 07:12
  • Solution 1 totally broken my webserver. My html works but python scripts are no longer callable. – Eamonn Kenny May 02 '18 at 13:38
  • @EamonnKenny if you Python scripts require execute permissions, try 0750 instead of 0640 (or 0770 instead of 0660). – Lekensteyn May 03 '18 at 11:00
  • @Lekensteyn shouldn't need execute because I'm using python3 from a virtualenv to call the scripts. It just goes completely screwy and its difficult to debug. I did try making them executable but that didn't work either. Unfortunately don't have an hour to debug it now so I'll just stick to running sudo -u www-data for the moment. – Eamonn Kenny May 03 '18 at 14:45
  • 1
    Is there an issue with inverting the process in solution 1? By that I mean, /var/www/app01 has ownership app01:app01, and then the www-data user is added to the app01 group? Or will that break something? – Jack_Hu May 31 '18 at 18:07
  • @Jack_Hu For /var/www/app01, that should work equally well, but be careful with other directories that are also accessible by the app01 group. The benefit of the www-data group is that it has very little privileges. If you have, say /home/app01/.bashrc writable by the app01 group, then your proposed approach might introduce additional risks. Similarly, if you have a /home/app01/.pgql_history file containing sensitive queries that is readable by the group, there is an information leak risk. (This can be mitigated via Apparmor/SELinux policies or readonly bind mounts.) – Lekensteyn Jun 02 '18 at 07:18
  • Solution 1 also works on Ubuntu with NGINX for WordPress files and folders. I replaced var/www with the path to WordPress's /wp-content, and also added the file wp-config.php. WordPress admin functions as usual; plugins can be added and removed. The only limitation I see is that they are installed with www-data as owner, which means they cannot be managed via FTP without first manually changing permissions again as per Solution 1. Not typical to need to manually manage plugin files directly though and the fix is easy. Have not tested any Python scripts however. – MQuiggGeorgia Jan 29 '21 at 14:26
  • which means / and var/www/dir, instead of /var/www/dir—please do not attempt) I once did this. my root went black hole. Luckily, I follow other good practices so my data was safe. pheww! – omer Jul 16 '21 at 09:37
11

Rather than storing my web sites in /var/www I place links there to the sites which are located in my home folder. I can freely edit, or add pages to my sites. When I happy with changes I then FTP to a hosting company where my domain name links.

fragos
  • 3,503
9

Don'ts

  • Don't set file permissions to 777 (world-writable)

    This is a significant security flaw, especially if you enable server-side scripting such as PHP. Unprivileged processes should not be able to write to files that would affect the website or, in the case of server-side scripting being used, execute arbitrary code.

  • Don't add yourself as a member of the www-data group and give it write permissions

    The purpose of that group is that it is an unprivileged group that the server processes run as. They should only have read access to the website files where possible, for the same reasons as above.

  • Don't change the permissions of the Apache processes

    The Apache child processes run as the www-data user and group by default, and this should not be altered. This is just a way of giving them no write permission to the filesystem.

    In certain circumstances you want your server-side scripts to be able to write to files, in which case only those files should be made writable by www-data and care needs to be taken to ensure security.

Dos

  • Set the files to be owned by yourself

    If you are the only one, or the usual one, to modify certain files on the website, then it makes total sense just to take ownership of those files. Set their owner to <your username>.

    You don't have to modify the server permissions for this, as the server will continue to get read-only access even when the files are owned by you.

  • Choose a sensible place to house the files (using DocumentRoot)

    If /var/www doesn't make sense, you are welcome to place them elsewhere. If they are specific to your own development or testing, you could place them in your home directory. Or you can set up some directories in /srv.

  • If you want to give group write access, create a new group for the purpose

    Don't re-use a system group, because these are typically designed to have the access they currently have, and no more, for security reasons.

thomasrutter
  • 36,774
8

It's this simple. You neither need to enable apache 'UserDir' (not recommended) nor messing up with 'www-data' groups (apache group in case on Fedora)

Just create your project directory inside /var/www/html

cd /var/www/html
sudo mkdir my_project

Then just chown the project directory to your user.

sudo chown your_username my_project

Now you can start working on your project folder as a regular user with any editor, IDE of your choice. No more sudos : )

Gayan Weerakutti
  • 3,770
  • 26
  • 38
7

If you make /var/www writeable by its group and add yourself to the group, you will not have to use sudo while still being fairly secure. Try this:

sudo adduser <username> www-data
sudo chown -R www-data:www-data /var/www
sudo chmod -R g+rw /var/www

You should then be able to edit /var/www/ files without hassle.

The first line adds you to the www-data group, the second line clears up any files with messed up ownership, and the third makes it so that all users who are members of the www-data group can read and write all files in /var/www.

muru
  • 197,895
  • 55
  • 485
  • 740
Azendale
  • 11,891
  • 6
    This is a very bad idea for security and this advice should not be followed, for reasons explained in other answers. www-data is supposed to be an unprivileged group, without write access. – thomasrutter Nov 23 '16 at 23:45
2

chmod in /var on www to allow the owner access, and chown to make sure you own it. Probably a stupid idea, but it would definitely work.

Daniel
  • 1,899
  • 2
    Not a stupid idea, it's a sensible idea security-wise. Note: You don't need to (and shouldn't) change the permissions of /var, just /var/www and/or its contents. – thomasrutter Nov 23 '16 at 23:43
1

You could start a www-session in a terminal by

sudo su www-data

Combined with a differently colored prompt*, to make it more obvious that it is the shell of a different user, and a policy always to put the corresponding xterm (and editor and such) on - for example - the virtual desktop 4, so that you get used to it, to avoid confusion.

*) For a differently colored prompt with a differnt character, create a file /etc/prompt like this:

# PROMPTING
#       When  executing  interactively, bash displays the primary prompt PS1 when it is ready to read a command, and the sec-
#       ondary prompt PS2 when it needs more input to complete a command.  Bash allows these prompt strings to be  customized
#       by inserting a number of backslash-escaped special characters that are decoded as follows:
#              \a     an ASCII bell character (07)
#              \d     the date in "Weekday Month Date" format (e.g., "Tue May 26")
#              \D{format}
#                     the  format is passed to strftime(3) and the result is inserted into the prompt string; an empty format
#                     results in a locale-specific time representation.  The braces are required
#              \e     an ASCII escape character (033)
#              \h     the hostname up to the first `.'
#              \H     the hostname
#              \j     the number of jobs currently managed by the shell
#              \l     the basename of the shell's terminal device name
#              \n     newline
#              \r     carriage return
#              \s     the name of the shell, the basename of $0 (the portion following the final slash)
#              \t     the current time in 24-hour HH:MM:SS format
#              \T     the current time in 12-hour HH:MM:SS format
#              \@     the current time in 12-hour am/pm format
#              \A     the current time in 24-hour HH:MM format
#              \u     the username of the current user
#              \v     the version of bash (e.g., 2.00)
#              \V     the release of bash, version + patchelvel (e.g., 2.00.0)
#              \w     the current working directory
#              \W     the basename of the current working directory
#              \!     the history number of this command
#              \#     the command number of this command
#              \$     if the effective UID is 0, a #, otherwise a $
#              \nnn   the character corresponding to the octal number nnn
#              \\     a backslash
#              \[     begin a sequence of non-printing characters, which could be used to embed a terminal  control  sequence
#                     into the prompt
#              \]     end a sequence of non-printing characters
#
#       The  command  number and the history number are usually different: the history number of a command is its position in
#       the history list, which may include commands restored from the history file (see HISTORY below),  while  the  command
#       number  is  the  position in the sequence of commands executed during the current shell session.  After the string is
#
# colors:
# \[...\]   wird benötigt, damit die shell weiß, daß hier kein printable output ist, und die Umbrüche richtig plaziert.
#
# ANSI COLORS
CRE="\[
[K\]"
NORMAL="\[[0;39m\]"
# RED: Failure or error message
RED="\[[1;31m\]"
# GREEN: Success message
GREEN="\[[1;32m\]"
# YELLOW: Descriptions
YELLOW="\[[1;33m\]"
# BLUE: System messages
BLUE="\[[1;34m\]"
# MAGENTA: Found devices or drivers
MAGENTA="\[[1;35m\]"
# CYAN: Questions
CYAN="\[[1;36m\]"
# BOLD WHITE: Hint
WHITE="\[[1;37m\]"
#
# default:
# postgres, oracle, www-data
#
# PS1=$BLUE"machine]->"$NORMAL\\w"$BLUE ø $NORMAL"
PS1=$BLUE"machine]:"$NORMAL\\w"$BLUE > $NORMAL"
#
# root, stefan:
#
case "$UID" in
    '0')
        PS1=$RED"machine:"$NORMAL\\w"$RED # $NORMAL"
    ;;
    '1000')
    PS1=$GREEN"machine:"$BLUE\\w$YELLOW" > "$NORMAL
    ;;
#    default)
#    ;;
esac

and source it from /etc/bash.bashrc for instance.

As additional tool to help distinction, you could always edit your files with an alias 'edit' or a symlink, which points, depending on your identity (taylor/www-data) to either gedit or mousepad, vim or pico. Or you could use different editor profiles, at least in gedit you may set your preferences to black text on white ground or white text on black ground for instance.

I only have such a policy for working as root, so I'm not sure how good it will fit to working with www-data. Combined with ssh-sessions to differnt hosts, which have their own prompts, it didn't stop me from being sometimes wrong, but if it happens, I realize fast, what is wrong, and it happens rarely.

note: The prompt-script is partly a copy of the manpage of bash.

user unknown
  • 6,507
  • This will work, and will not (if used carefully) negatively impact security, but may not be the most straightforward solution. It's a valid solution for some people though. – thomasrutter Nov 23 '16 at 23:47
0

This variation is much like Lekensteyn's first solution, where www-data is given sticky read-only access, and a specific user has write access. It also allows directory traversal in cases where you might grant specific privileges on certain files or subdirectories, after setting the base permissions.

The general form is like this:

(
u=YOURUSER
g=www-data
d=/var/www/html
chown -R "$u:$g" "$d" &&
    find "$d" \! -type d -print0 | sudo xargs -r0 chmod u=rwX,g=r,o= &&
    find "$d" -type d -print0 | sudo xargs -r0 chmod u=rwx,g=rxs,o=x
)

The parentheses are only if you run this from your regular shell so the variables don't pollute it. Using xargs for such operations is more efficient as it will invoke as few chmod commands as possible (probably just one), whereas -exec in find will run a separate command for every single file & dir. Another difference is that the chmod invocations don't use the less-legible numeric permissions, and the X preserves the execute bit on files that already have it, e.g. scripts. You can put that in a script to run as necessary, or in a cron job, but it would have to been run as root, so you would remove the sudo from it.

If YOURUSER is you, you should no longer need sudo. If it's some application-specific, isolated account, then you still use sudo, but not as root, e.g.:

sudo -u YOURUSER bash
Walf
  • 398