Blog

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
On this page
  1. Why File Placement Matters
  2. Quick Reference: Standard Directory Mapping
  3. Decision Matrices
  4. When to use /opt/app-name/ vs /usr/local/
  5. When to use /srv/ vs /var/www/
  6. Configuration File Precedence
  7. Common Application Types
  8. Web Applications (Node.js, Python, Ruby, etc.)
  9. Database Services
  10. Monitoring Tools (Prometheus, Grafana, etc.)
  11. Security Standards
  12. Mandatory Permission Requirements
  13. Firewall Best Practices
  14. Maintenance Essentials
  15. Backup Strategy
  16. Log Rotation
  17. Common Issues & Quick Fixes
  18. Quick Diagnostics
  19. Deployment Verification Checklist
  20. Quick Command Reference
  21. Key Takeaways

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 blog 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:

sh
/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.)

shell
/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

bash
# 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

bash
# 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:

shell
/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:

bash
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

bash
# 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:

bash
# ✓ 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:

bash
# 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.

Keep reading