While both are designed to contain files not belonging to the operating system, /opt
and /usr/local
are not intended to contain the same set of files.
/usr/local
is a place to install files built by the administrator, typically by using the make
command (e.g., ./configure; make; make install
). The idea is to avoid clashes with files that are part of the operating system, which would either be overwritten or overwrite the local ones otherwise (e.g., /usr/bin/foo
is part of the OS while /usr/local/bin/foo
is a local alternative).
All files under /usr
are shareable between OS instances, although this is rarely done with Linux. This is a part where the FHS is slightly self-contradictory, as /usr
is defined to be read-only, but /usr/local/bin
needs to be read-write for local installation of software to succeed. The SVR4 file system standard, which was the FHS' main source of inspiration, is recommending to avoid /usr/local
and use /opt/local
instead to overcome this issue.
/usr/local
is a legacy from the original BSD. At that time, the source code of /usr/bin
OS commands were in /usr/src/bin
and /usr/src/usr.bin
, while the source of locally developed commands was in /usr/local/src
, and their binaries in /usr/local/bin
. There was no notion of packaging (outside tarballs).
On the other hand, /opt
is a directory for installing unbundled packages (i.e. packages not part of the Operating System distribution, but provided by an independent source), each one in its own subdirectory. They are already built whole packages provided by an independent third party software distributor. Unlike /usr/local
stuff, these packages follow the directory conventions (or at least they should). For example, someapp
would be installed in /opt/someapp
, with one of its command being /opt/someapp/bin/foo
, its configuration file would be in /etc/opt/someapp/foo.conf
, and its log files in /var/opt/someapp/logs/foo.access
.
This change was introduced by BSD after 1985 (BSD 4.2 was still documenting /usr
) and in or before 1988 (BSD 4.3/SunOS 4.1 hier(7)
manual page already documents /home
). It was quickly followed by Solaris 2.0 (which kind of merged System V and BSD) and was later adopted by most other Unix vendors.
This is from the Solaris 2.0 useradd
manual page:
-D Display the default values for group, basedir, skel, shell,
inactive, and expire. When used with the -g, -b, -f, or -e
options, the -D option sets the default values for the
specified fields. The default values are:
group other (GID of 1)
basedir /home
skel /etc/skel
shell /sbin/sh
inactive 0
expire Null (unset).
Before that, older Unixes were using either the traditional /usr
directory or some variants like /user1 documented in SVR3 and SVR4.0. Unix version 7 hier(7)
manual page defines /usr
as the default location for user's home directory:
/usr/wd/ initial working directory of a user, typically wd is the
user's login name
Unix version 6, the first Unix to be widely released outside of the Bell Labs had not the hier
manual page yet but was already using and documenting /usr
.
There are several reasons that explain the move from /usr
to something else, including:
With some Unix versions, upgrading the OS was blowing away the /usr
directory.
Usernames like tmp
, src
, bin
, local
and the likes were forbidden as they clashed with existing directories under /usr
.
Using /usr
as an automounter base directory was not possible as it was not empty (Thanks to Johan for pointing this)
Diskless machines were expected to use a read only NFS share for /usr
but read-write home directories
Best Answer
There is no standard location for software installed by a non-root user.
A common location include using
$HOME/local
or$HOME/opt
(withbin
,lib
etc. subdirectories). Some software seems to use$HOME/.local
by default (the Pythonpip
tool and others), which may mean that using that hidden directory might be a less good choice as installing into it may overwrite existing files not managed directly by you.Another alternative (especially if you compile from sources) is to use GNU Stow and install with e.g.
$HOME/local/stow/package_dir-version
as the installation prefix (rather than$HOME/local
). GNU Stow would then populate the hierarchy above thestow
directory with symbolic links pointing into the various directories under thestow
directory.See the question "How to correctly deal with locally built binaries?" for more information.