Is it safe to chown `/usr/local`?

It is unusual that /usr/local isn't owned by root. But you can change the owner as you want.

But I advise to ensure that /usr/local/sbin is still owned by root to avoid a security problem. The commands here are usually invoked only by root.


I can't recommend becoming the owner of /usr/local; for most situations, it's probably less secure than using sudo.

Your question suggests two reasons you might want to chown /usr/local.

The first is to avoid having to use sudo to install software. This might read to some (such as the author of this answer) as saying you want to work efficiently, or save the keystrokes needed to type sudo and enter your password. But probably when you say "unnecessary," you are referring instead to the principle of least privilege:

By default, root owns the directory. This means that to install there, you need to use sudo. For a single-user or developer machine, this seems like unnecessary extra use of the command

I quite often hear/read folks opining/complaining along the lines of "I'm the only one who uses this system, so I shouldn't need to use sudo and enter a password." For readers who are of that view, and because it's relevant here, let's remind ourselves of a basic security reason for root to own things.

Most of the program files installed on an Ubuntu system have file mode 755, or in symbolic notation rwxr-xr-x, meaning that any user or program can execute them, but only the owner of the files, root, can modify them. (Technically this also requires that no one but root have the w permission on the directory that contains them, so other users can't delete or move them.)

This means that you, the humble user, may execute any program. If you try to use a program to do something you don't have permission to do, like perform a write operation on a file owned by root, it will error out. This makes a typo in some command, a buggy application, or malicious code, less likely to mess up your system - unless it's running as root, it won't have permission to do so. This is especially useful when running programs that interact with the internet.

If you chown /usr/local, any program running with your privileges could write files there, which might later get executed as root for some reason, such as by superseding another command of the same name. /usr/local/bin is in the default $PATH, and in sudo's secure_path, and it comes before other locations in both. So if I have two executables

/usr/local/bin/chown
/bin/chown

when I execute sudo chown ..., the chown in /usr/local/bin will be executed.

But you probably already knew all that, since your second reason is about security:

Additionally, if you have locally compiled software installed to /usr/local, the software currently needs root to modify themselves or install plugins. This seems unsafe - I want to only use sudo when I know EXACTLY what will happen.

Just in case it's necessary to mention this here, it's absolutely right (according to the FHS anyway) to install locally compiled software to /usr/local, but compiling itself should be done somewhere in your $HOME, without sudo, until the last step when you type sudo make install or equivalent.

I think you're suggesting that by running a program installed in /usr/local as its unprivileged owner, you could use specific permission errors thrown when it tries to update itself to see that it's trying to modify some other filesystem location not owned by you in a way you don't want, so that you could stop it from doing so.

This might be helpful. The implication is that you trust the program to do anything it likes within /usr/local, but not elsewhere. If it requests elevated permissions, you could refuse to allow it to update, or uninstall it. That makes some sense to me. But I think trying to use /usr/local as a kind of sandbox in this way is probably not a good idea, or at least it's unlikely to be the most secure solution. It's not a properly isolated location (/opt is a little more isolated, since it's not in the default $PATH). The program might write or delete something in /usr/local to cause harm. Other (potentially poorly written) programs you run may write and execute code there that you aren't aware of.

If you're worried about allowing a program to update itself securely, you should probably look for alternatives (specific to the program perhaps, as with python for example, or you could look for a snap or similar implementation that suits your needs, or use containers or a VM to test potentially unsafe software) before exposing a system location (even a relatively user-y one) to be written to by programs run by a normal user. That seems to me as likely to have unpredictable effects as allowing programs temporarily elevated permissions with sudo.


For software only you need, use your home directory instead of /usr/local.

Instead of changing the ownership of /usr/local or having to run commands as root when you don't want to, you should just configure your builds so they install in your home directory instead of /usr/local. This addresses all the potential problems with changing the ownership of /usr/local, including how its bin and sbin subdirectories are in root's path.

If you do need to allow other users to run your software, you can give them access. In fact, they will probably be able to already, because by default your home directory has permissive read and execute access. (If you don't want that, you can change it quite easily, just by using chmod on whatever files or directories you want to make private and possibly also changing your umask.)

With software installed in your home directory, binaries that would have gone in /usr/local/bin will instead go in /home/username/bin. You will get other subdirectories of your home directory corresponding to the subdirectories of /usr/local that the software you install needs. This will typically happen automatically when you install software from source code.

Configuring Your Builds

Most software you build from source code has a step where you run:

./configure

For the great majority of software that ships with a configure script that can be run like that, it defaults to configuring the build for installation inside /usr/local when you eventually run sudo make install to install it. The reason is that it is implicitly equivalent to running:

./configure --prefix=/usr/local

To configure a build for installation in your home directory, use this instead:

./configure --prefix="$HOME"

In practice, in Ubuntu, home directory paths don't contain spaces, other whitespace, or other characters that will be treated specially by the shell like *, so unless you've set up your user account quite oddly, you can just type:

./configure --prefix=$HOME

(I don't recommend getting in the habit of that for writing scripts, though. Also, on some other OSes--such as macOS--it's less uncommon for the paths to users' home directories to contain spaces.)

Or if you prefer you can type out your full home directory path:

./configure --prefix=/home/username

(Replace username with your actual username, of course. If for some reason your home directory isn't in /home then you'll have to adjust accordingly.)

Installing Your Builds

After you run make, you may be accustomed to running sudo make install, but when you install in your own home directory, you don't need to run it as root, so you can--and should--omit sudo. Just run:

make install

Similarly, for software that supports an uninstall target:

make uninstall

This is exactly what you were asking for... just in your home directory, not /usr/local.

Running Your Programs

Probably the bin subdirectory of your home directory is either:

  • already in your $PATH, or
  • will be in your $PATH if you just log out and back in.

The reason is that the .profile file in your home directory, which contains commands that run when you log in, contains this by default for user accounts created in most versions of Ubuntu (including the initial administrator account created when you install the OS):

# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; then
    PATH="$HOME/bin:$PATH"
fi

That code runs when you log in (because it's in .profile) and places your personal bin directory in $PATH only if it exists at that time. That's why you may need to log out and back in.

Older releases like Ubuntu 14.04, as well as newer releases like Ubuntu 17.10, come with that. However, Ubuntu 16.04, which is probably the most popular release as of this writing, has this instead:

# set PATH so it includes user's private bin directories
PATH="$HOME/bin:$HOME/.local/bin:$PATH"

That simply adds the bin subdirectory of your home directory---as well as the .local/bin subdirectory--to your $PATH, without checking if those directories actually exist. So if you use 16.04, or if you upgraded from a system that was 16.04 when your user account was created, then the bin subdirectory of your home directory is likely already in your $PATH.

Your .profile file is copied from the /etc/skel directory when your user account is created. If your user account was created on an older Ubuntu release, it got that version of .profile, and it was not changed--for your user account--by upgrading to a more recent release.

Once the bin subdirectory of your home directory is in your $PATH, you will be able to run programs whose executable files are installed there just by typing their names, just as you could do with programs installed by Ubuntu's package manager or installed inside /usr/local.

The .local Option

You may have noticed that the default .profile file for user accounts created in some Ubuntu releases, including in 16.04 as described above, adds not just $HOME/bin to your path, but also $HOME/.local/bin. If your .profile doesn't add that, but you want it to, then you can simply edit it in.

Though often used to store settings and cached data, you can also install software inside the .local subdirectory of your home directory. You should feel uninhibited in doing so, as from a usability and security standpoint, --prefix="$HOME/.local" is similar to --prefix="$HOME".

Remember that files and directories that start with . are not shown by default in graphical file browsers (use Ctrl+H to unhide and rehide them) or by the ls command (pass the -A or -a flag to show them). This may not be what you want, or it may be exactly what you want. This is a matter of personal preference.

However, I have observed that some automated source-based package managers that build and install software in one's home directory use $HOME/.local. I don't actually know how common this is--I hope to investigate further and update this answer--but you may prefer to just use $HOME for things you compile manually. That way it will be clear where things came from. And if there is a collision, the software is still likely to coexist acceptably.

You may also deliberately install some software in $HOME/.local and other software in $HOME. It's up to you. Whichever bin directory appears first in your $PATH environment variable is the one that a command will run from, in the event that commands of the same name exist in both.


Credit goes to Zanna and Videonauth for pointing out errors in a previous version of this answer, regarding which Ubuntu releases have which default code in .profile, and helping me to correct them (see also here).