Journal

The Linux Filesystem Hierarchy Every Developer Should Know

The Linux filesystem follows a standard hierarchy (FHS) that dates back decades. Once you internalize it, navigating any Linux server feels familiar — whether it’s Ubuntu, Arch, or Alpine in a container.

The Directories That Matter

/etc — Configuration

System-wide configuration files live here. When you edit an Nginx config, a PHP-FPM pool, or an SSH daemon setting, you’re working in /etc.

/etc/nginx/nginx.conf
/etc/php/8.3/fpm/pool.d/www.conf
/etc/ssh/sshd_config
/etc/systemd/system/myapp.service

Rule of thumb: if a program reads a config file on startup, it’s probably in /etc.

/var — Variable Data

Data that changes during operation: logs, caches, mail spools, and databases.

/var/log/           # System and application logs
/var/www/           # Traditional web root
/var/lib/mysql/     # MySQL data directory
/var/cache/         # Application caches
/var/run/ → /run/   # Runtime data (PIDs, sockets)

This is where your web apps typically get deployed on conventional setups. It’s also where logs pile up if you’re not rotating them.

/opt — Optional Packages

Third-party software that doesn’t come from your package manager. If you install a self-contained application manually, /opt is the conventional home:

/opt/mycompany/app/
/opt/lampp/

/usr — User Programs

Despite the name, this isn’t about user home directories. It contains installed programs, libraries, and documentation:

/usr/bin/           # User binaries (most CLI tools)
/usr/lib/           # Libraries
/usr/local/bin/     # Locally compiled software
/usr/share/         # Architecture-independent data

The /usr/local/ subtree mirrors /usr/ but is reserved for software you compile yourself, keeping it separate from package-managed files.

/home — User Home Directories

Each user gets a directory here. Development tools, SSH keys, shell configs, and local projects live under your home:

/home/deploy/.ssh/authorized_keys
/home/deploy/.bashrc
/home/deploy/projects/

/tmp and /run

Both are for temporary data. /tmp is cleaned on reboot (and sometimes periodically). /run is a tmpfs mounted in RAM for runtime state like PID files and sockets.

Permissions: The Quick Version

Every file has an owner, a group, and three permission sets (read, write, execute):

ls -la /var/www/
# drwxr-xr-x 3 www-data www-data 4096 Jan 15 10:00 html

The pattern is owner-group-others. Common permission sets:

OctalMeaningTypical Use
755rwxr-xr-xDirectories, executables
644rw-r—r—Config files, web assets
600rw-------SSH keys, secrets
700rwx------.ssh directory

A frequent deployment mistake is getting the owner wrong:

# Web server can't read your files
sudo chown -R www-data:www-data /var/www/mysite
sudo chmod -R 755 /var/www/mysite
sudo chmod -R 644 /var/www/mysite/*.html

Where Web Apps Live

There’s no single right answer, but these are the conventions:

  • Traditional: /var/www/mysite owned by www-data
  • Capistrano/deployer style: /var/www/mysite/current → symlinked release
  • Container world: /app or /srv inside the image
  • User-space dev: ~/projects/mysite

What matters is consistency within your team and ensuring the web server user can read the files.

Finding Things

When you can’t remember where something is:

which nginx          # Find binary location
whereis php          # Binary, source, and man page
find /etc -name "*.conf" -mtime -7   # Recently modified configs
locate nginx.conf    # Fast search using mlocate db

The hierarchy is a convention, not a cage. But following it means any Linux-literate person joining your team can navigate your server without a map.