← Back to list

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…

SSK · 2026-03-08 07:56 · 3 claps · 4.5 min read
#linux #production #deployment #backup #ubuntu
Open on Medium ↗
Wiki topics: 🔓 · Open Source

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.

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 Type                | Standard Location         | Owner    | Permissions | Backup Priority |
|---------------------------|---------------------------|----------|-------------|-----------------|
| Application binaries/code | `/opt/app-name/`          | app-user | 0755        | Medium          |
| System configuration      | `/etc/app-name/`          | root     | 0644        | Critical        |
| Sensitive credentials     | `/etc/app-name/secrets/`  | root     | 0600        | Critical        |
| Persistent data           | `/var/lib/app-name/`      | app-user | 0750        | Critical        |
| Application logs          | `/var/log/app-name/`      | app-user | 0755        | Low             |
| Cache/temporary data      | `/var/cache/app-name/`    | app-user | 0755        | None            |
| Static web assets         | `/srv/app-name/`          | www-data | 0755        | Medium          |
| Maintenance scripts       | `/usr/local/sbin/`        | root     | 0750        | Medium          |

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 the 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, GO, 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 :

| Database        | Data Directory            | Config File                              | Log 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

| Issue               | Symptom                           | Root Cause                          | Resolution                                            |
|---------------------|-----------------------------------|-------------------------------------|-------------------------------------------------------|
| Permission denied   | App can't write to data directory | Wrong ownership                     | `sudo chown -R user:group /var/lib/app/`              |
| Config not found    | App fails to load configuration   | Incorrect path in systemd           | Verify `Environment=CONFIG_PATH=/etc/app/config.yaml` |
| Disk full           | `/var` partition at 100%          | Log/cache accumulation              | `du -sh /var/log/* /var/cache/*`, run logrotate       |
| Service won't start | Systemd activation fails          | Missing dependencies or permissions | `journalctl -u app.service -n 50`                     |
| SELinux blocking    | AVC denial messages               | Incorrect security context          | `ausearch -m avc -ts recent`, add policy              |
| Port conflict       | Address already in use            | Multiple apps on same port          | `sudo ss -tlnp | grep :port`, change config           |

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 standard 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.


메타데이터
post_id
75fa5ee05a28
slug
production-linux-deployment-guide-where-to-put-your-files-75fa5ee05a28
url
https://medium.com/@2ssk/production-linux-deployment-guide-where-to-put-your-files-75fa5ee05a28
canonical_url
https://medium.com/@2ssk/production-linux-deployment-guide-where-to-put-your-files-75fa5ee05a28
author_url
https://medium.com/@2ssk
status
ok
fetched_at
2026-06-09 18:04:40