cd ..
linux

Production Linux Deployment Guide: Where to Put Your Files

A practical guide to file placement on production Linux servers following the Filesystem Hierarchy Standard (FHS). Learn where to place applications, configs, logs, and data for consistent and maintainable deployments.

5 min read

Production Linux Deployment Guide: Where to Put Your Files

Why File Placement Matters

When deploying applications to production Linux servers, knowing where to put files isn't just about organization—it's about:

  • Consistency across your infrastructure and team workflows
  • Predictable maintenance, backup, and troubleshooting procedures
  • Compliance with the Filesystem Hierarchy Standard (FHS) 3.0
  • Portability across different Linux distributions

This guide covers production deployments for Ubuntu, Debian, RHEL, and CentOS systems.


Quick Reference: Standard Directory Mapping

Asset TypeStandard LocationOwnerPermissionsBackup Priority
Application binaries/code/opt/app-name/app-user0755Medium
System configuration/etc/app-name/root0644Critical
Sensitive credentials/etc/app-name/secrets/root0600Critical
Persistent data/var/lib/app-name/app-user0750Critical
Application logs/var/log/app-name/app-user0755Low
Cache/temporary data/var/cache/app-name/app-user0755None
Static web assets/srv/app-name/www-data0755Medium
Maintenance scripts/usr/local/sbin/root0750Medium

Decision Matrices

When to use /opt/app-name/ vs /usr/local/

Use /opt/app-name/ for:

  • Third-party software packages
  • Vendor-provided applications
  • Self-contained applications with multiple components
  • Applications managed independently from system packages

Use /usr/local/ for:

  • Locally compiled tools and utilities
  • Custom scripts used system-wide
  • Override or supplement system binaries
  • Single-binary applications

When to use /srv/ vs /var/www/

Use /srv/service/ for:

  • Service-specific data (FTP servers, Git repositories)
  • Application-specific static content
  • Multi-service environments

Use /var/www/ for:

  • Traditional web server document roots
  • Nginx/Apache default configurations
  • Simple static website hosting

Configuration File Precedence

Applications should check configuration in this order:

  1. /etc/app-name/ - System-wide configuration (highest priority)
  2. /opt/app-name/etc/ - Application-bundled defaults
  3. Environment variables - Runtime overrides

Common Application Types

Web Applications (Node.js, Python, Ruby, etc.)

Standard Structure:

/opt/myapp/                  # Application code
/etc/myapp/                  # Configuration files
  └── secrets/               # Sensitive credentials (0600)
/var/lib/myapp/              # Persistent data (uploads, sessions)
/var/log/myapp/              # Application logs
/var/cache/myapp/            # Cache data

Database Services

Standard locations for common databases:

DatabaseData DirectoryConfig FileLog Directory
PostgreSQL/var/lib/postgresql//etc/postgresql/*/main/postgresql.conf/var/log/postgresql/
MySQL/MariaDB/var/lib/mysql//etc/mysql/my.cnf/var/log/mysql/
MongoDB/var/lib/mongodb//etc/mongod.conf/var/log/mongodb/
Redis/var/lib/redis//etc/redis/redis.conf/var/log/redis/

Note: Package managers (apt/yum) automatically create FHS-compliant structures. Preserve these conventions for consistency.

Monitoring Tools (Prometheus, Grafana, etc.)

/opt/tool/                 # Binary and static assets
/etc/tool/                 # Configuration files
/var/lib/tool/             # Persistent data (databases, dashboards)
/var/log/tool/             # Application logs

Security Standards

Mandatory Permission Requirements

# Application directories
sudo chmod 0755 /opt/app/
sudo chmod 0750 /var/lib/app/
sudo chmod 0755 /var/log/app/
 
# Configuration files
sudo chmod 0644 /etc/app/*.{yaml,conf,ini}
sudo chmod 0600 /etc/app/secrets/*
sudo chown root:root /etc/app/secrets/*
 
# Verify with namei
namei -l /etc/app/secrets/credentials.json

Firewall Best Practices

# Only expose necessary ports
sudo ufw allow 80/tcp     # HTTP
sudo ufw allow 443/tcp    # HTTPS
sudo ufw allow 22/tcp     # SSH
 
# NEVER expose application ports directly
# Always use reverse proxy (Nginx/Apache)

Maintenance Essentials

Backup Strategy

Daily Backups (Critical):

  • /var/lib/app/ → Application state and databases
  • /etc/app/ → Configuration files and secrets

Weekly Backups (Important):

  • /opt/app/ → Application code (usually redundant with Git)

No Backup Required:

  • /var/cache/app/ → Regeneratable cache
  • /var/log/app/ → Archive separately, don't restore
  • /tmp/ → Temporary files

Backup Script Location: /usr/local/sbin/backup-app.sh

Log Rotation

Create /etc/logrotate.d/app:

/var/log/app/*.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    create 0640 app-user app-user
    sharedscripts
    postrotate
        systemctl reload app > /dev/null 2>&1 || true
    endscript
}

Test configuration:

sudo logrotate -d /etc/logrotate.d/app  # Dry run
sudo logrotate -f /etc/logrotate.d/app  # Force rotation

Common Issues & Quick Fixes

IssueSymptomRoot CauseResolution
Permission deniedApp can't write to data directoryWrong ownershipsudo chown -R user:group /var/lib/app/
Config not foundApp fails to load configurationIncorrect path in systemdVerify Environment=CONFIG_PATH=/etc/app/config.yaml
Disk full/var partition at 100%Log/cache accumulationdu -sh /var/log/* /var/cache/*, run logrotate
Service won't startSystemd activation failsMissing dependencies or permissionsjournalctl -u app.service -n 50
SELinux blockingAVC denial messagesIncorrect security contextausearch -m avc -ts recent, add policy
Port conflictAddress already in useMultiple apps on same port`sudo ss -tlnp

Quick Diagnostics

# Check service status
systemctl status app
 
# View recent logs
journalctl -u app -n 50 --no-pager
 
# Check disk usage
df -h
du -sh /var/lib/app /var/log/app /var/cache/app
 
# Verify permissions
namei -l /etc/app/secrets/credentials.json
ls -la /var/lib/app/
 
# Check listening ports
sudo ss -tlnp | grep app
 
# SELinux troubleshooting
sudo ausearch -m avc -ts recent

Deployment Verification Checklist

Before marking any deployment as complete, verify:

# ✓ Directory structure exists
ls -la /opt/app/ /etc/app/ /var/lib/app/ /var/log/app/
 
# ✓ Ownership is correct
stat -c '%U:%G' /opt/app/
stat -c '%U:%G' /var/lib/app/
 
# ✓ Permissions are secure
namei -l /etc/app/secrets/credentials.json
find /etc/app/secrets/ -type f ! -perm 0600 -ls
 
# ✓ Systemd service is enabled and running
systemctl is-enabled app
systemctl is-active app
 
# ✓ Application is responding
curl http://localhost:port/health
 
# ✓ Logs are generating
ls -lh /var/log/app/
 
# ✓ Log rotation configured
test -f /etc/logrotate.d/app && echo "OK" || echo "MISSING"
 
# ✓ Backup script exists
test -x /usr/local/sbin/backup-app.sh && echo "OK" || echo "MISSING"

Quick Command Reference

Create standard directory structure for any application:

# Create standard app structure
create-app-structure() {
    APP=$1
    sudo useradd -r -s /bin/false "$APP"
    sudo mkdir -p /opt/"$APP" /etc/"$APP"/secrets /var/{lib,log,cache}/"$APP"
    sudo chown -R "$APP":"$APP" /opt/"$APP" /var/{lib,log,cache}/"$APP"
    sudo chown -R root:root /etc/"$APP"
    sudo chmod 700 /etc/"$APP"/secrets
}
 
# Usage: create-app-structure myapp

Key Takeaways

  1. Consistency is crucial - Always follow FHS standards for predictable operations
  2. Separate concerns - Keep code, config, data, and logs in their designated locations
  3. Security first - Protect secrets with proper permissions (0600) and ownership (root)
  4. Plan for backups - Critical data goes in /var/lib/app/ and /etc/app/
  5. Document everything - Use systemd service files and maintain clear documentation

Remember: Following these standards ensures predictable operations, easier troubleshooting, and smoother team collaboration. When in doubt, stick to the FHS conventions—they've been battle-tested across countless production deployments.

More to Read