Linux Where To Install Programs

Linux Where To Install Programs

Reading time1 min
#Linux#Software#OpenSource#LinuxInstallation#PackageManagement#FilesystemHierarchy

Mastering Linux Program Installation: Understanding Program Placement and Its Consequences

Misplacing software on a Linux system leads to opaque errors, upgrade conflicts, and avoidable downtime. File hierarchy discipline isn’t just academic—when a new kernel or glibc update lands, the smallest misalignment in executable paths or library placement can break a business-critical workload. Understanding where to install binaries and associated resources is as essential as understanding how to install them.

Consider this scenario: deploying a legacy build tool that needs to co-exist with a distribution-standard version. Careless installation overwrites /usr/bin binaries, and suddenly every automated build pipeline throws libfoo.so.2: cannot open shared object file: No such file or directory. The recovery? Often a frustrating mix of restore attempts and sifting through months of shell history.

This article outlines where to install programs on Linux, the rationale underlying the Filesystem Hierarchy Standard (FHS), and best practices for sustainable, maintainable systems—even when package managers can't solve all problems.


Core Principle: Installation Location Dictates Maintainability

Sloppy placement of applications accelerates system entropy. Place every program with future troubleshooting in mind:

  • System integrity: Prevent accidental overwrites during package upgrades.
  • Predictability: Standard paths aid in debugging, monitoring, and backup scripts.
  • Security boundaries: Reduce attack surface by limiting writable paths.

FHS Recap: Key Directories for Executables

DirectoryIntended UsageTypical Contents (by example)
/binRequired user binaries for single-user modecp, ls, sh
/sbinSystem binaries (mostly for root/admin)fsck, iptables
/usr/binNon-essential user binariesvim, python3, docker
/usr/sbinNon-essential system binariesapache2, sshd
/usr/local/binLocally-built/user-installed binariesCustom tools (htop if compiled manually)
/usr/local/sbinLocally-built system binariesCustom daemons, not shipped by distro
/optOptional/3rd-party self-contained appsgoogle/chrome, matlab
/home/<user>/binPer-user scripts and programsmy_sync_script.sh, custom_cli_tool

Side note: /usr/local/ is reserved for administrator actions and remains untouched by standard system package upgrades.


Package Managers: Default Placement & Guarantees

When using apt, dnf, pacman, you benefit from distribution-vetted paths:

  • Binaries: /usr/bin, /usr/sbin
  • Libs: /usr/lib (or variants: /usr/lib64 on x86_64)
  • Config: /etc
  • Manpages: /usr/share/man

Example:

sudo apt install jq
which jq
# /usr/bin/jq
dpkg -L jq | grep bin/
# /usr/bin/jq

Note: Package managers own those files. Manual modifications will break at the next upgrade.


Compiling from Source: /usr/local or Custom Prefix

By default, running ./configure && make && sudo make install places binaries in /usr/local/bin and libraries in /usr/local/lib. This prevents collisions with distribution packages.

Override with:

./configure --prefix=/opt/myapp-3.1.4
make
sudo make install

Now, binaries reside in /opt/myapp-3.1.4/bin. This approach is essential for running parallel versions (e.g., Python 3.8 alongside distro's 3.10).

Known issue: If you forget to update LD_LIBRARY_PATH or /etc/ld.so.conf.d/, you’ll hit runtime errors:

myapp: error while loading shared libraries: libxyz.so.5: cannot open shared object file: No such file or directory

Mitigate by exporting:

export LD_LIBRARY_PATH=/opt/myapp-3.1.4/lib:$LD_LIBRARY_PATH

or by adding a loader config.


/opt: The Right Place for Big, Third-Party Blobs

When installing commercial or standalone packages (e.g., VMware, JetBrains IDEs, Chrome), extract to /opt/<vendor>/<app>.

Example:

/opt/google/chrome/google-chrome
/opt/jetbrains/pycharm-2023.1/bin/pycharm.sh

This keeps unsanctioned dependencies out of system-wide paths and simplifies removals (just rm -rf).
Critical point: /opt apps rarely integrate with package management—manual patching is required for desktop launchers or MIME types.


User-Local Installs: Isolating CLI Tools in ~/bin

Scripts and binaries for personal use live in $HOME/bin. Add it to your PATH:

echo 'export PATH=$HOME/bin:$PATH' >> ~/.bashrc
source ~/.bashrc

Practical detail: Some distributions (e.g., Ubuntu ≥ 19.10) auto-add ~/bin if you create it.
Gotcha: Not all login shells respect this unless you restart the session or explicitly load your shell config.


Example: Building and Isolating a Legacy App

Suppose you're forced to build curl 7.70.0 from source while also retaining the distro’s version.

  1. Download and unpack:
    wget https://curl.se/download/curl-7.70.0.tar.gz
    tar xf curl-7.70.0.tar.gz
    cd curl-7.70.0
    
  2. Configure for /usr/local:
    ./configure --prefix=/usr/local
    make
    sudo make install
    
  3. Validation:
    /usr/local/bin/curl --version
    # curl 7.70.0
    
    The system-provided version remains at /usr/bin/curl.

Example: Extracting a Standalone Application to /opt

Download and install a proprietary tool:

cd /tmp
wget https://downloads.anydesk.com/linux/anydesk-6.3.0.tar.gz
sudo mkdir -p /opt/anydesk-6.3.0
sudo tar -xzvf anydesk-6.3.0.tar.gz -C /opt/anydesk-6.3.0 --strip-components=1
sudo ln -sf /opt/anydesk-6.3.0/anydesk /usr/local/bin/anydesk

Now, running anydesk launches the proprietary binary with zero risk to system versions.
Side note: When upgrading, point the symlink to the new version after extraction.


Practical Recommendations

  • Never use /usr/bin or /usr/sbin for manually installed software—let your package manager own these directories.
  • Create .deb or .rpm packages from source with checkinstall, enabling package-manager-based removal later:
    sudo checkinstall
    
  • For complex or conflicting environments, use containerization (Docker, Podman) or user-mode package managers (like Nix or Homebrew on Linux).
  • Harden /usr/local permissions to prevent accidental system-wide changes:
    sudo chmod o-w /usr/local/bin
    
  • Review $PATH order. A common, subtle problem: binaries in /usr/local/bin can unintentionally shadow system versions—always test with which or type -a.

Reference: Installation Path Cheat Sheet

Installation MethodBest Practice DirectoryManaged By
Distro package manager (apt etc)/usr/bin, /usr/sbinPackage manager
Manual build from source/usr/localLocal install only
Third-party/proprietary/opt/<vendor>/<app>Manual
User-specific tools/scripts$HOME/binUser only

Mastering Linux application placement reduces outages, aids debugging, and keeps ops engineers sane. Ignore the FHS, and spend your next Saturday parsing strace outputs for missing shared objects. Follow it, and upgrades, migrations, and compliance audits become routine.

Questions, corrections, pushback? Share them. There’s nuance here—and clean systems demand it.