7io SMS Directory Structure (Option 1) - DS1

1. Introduction

This document provides a detailed explanation of the "Option 1: Environment-First, then by Ownership/Purpose" directory structure. We will explore how it deviates from and improves upon default web server document root configurations, and why it is particularly well-suited for hosting environments that manage:

The core philosophy of this structure is to provide clear separation for deployment environments (production, staging, development) and then to categorize sites by their ownership and purpose, using conventional and understandable directory names.

2. Recap of Directory Structure: Option 1

The "Option 1: Environment-First, then by Ownership/Purpose (Revised with Conventional Names)" structure is as follows:

/var/www/
├── production/
│   ├── company/                # Your company's sites & applications
│   │   ├── internal/           # Non-public facing or internal tools
│   │   │   └── tool.mycompany.local/
│   │   │       ├── public_html/    # DocumentRoot
│   │   │       └── private/        # Logs, configs, backups
│   │   ├── public/             # Your main public-facing company websites
│   │   │   └── mycompany.com/
│   │   │       ├── public_html/
│   │   │       └── private/
│   │   │   └── ourbrand.com/
│   │   │       ├── public_html/
│   │   │       └── private/
│   ├── clients/                # For reseller clients or managed hosting clients
│   │   └── clientA-ID001/
│   │       ├── example-client-site.com/
│   │       │   ├── public_html/
│   │       │   └── private/
│   │       ├── another-client-domain.net/
│   │       │   ├── public_html/
│   │       │   └── private/
│   │   └── clientB-ID002/
│   │       └── clientb-main.org/
│   │           ├── public_html/
│   │           └── private/
│   ├── users/                  # For regular users with personal domains
│   │   └── userX-UID101/
│   │       ├── myblog.com/
│   │       │   ├── public_html/
│   │       │   └── private/
│   │       └── personalproject.dev/
│   │           ├── public_html/
│   │           └── private/
│   └── apps/                   # If you host shared SaaS instances, etc.
│       └── sharedcrm/
│           ├── public_html/
│           └── data/
├── staging/                    # Staging would mirror the production structure
│   ├── company/ # ... (similar sub-structure)
│   ├── clients/ # ...
│   ├── users/   # ...
│   └── apps/    # ...
├── development/                # Development would also mirror
│   ├── company/     # ...
│   ├── clients/     # ...
│   ├── users/       # ...
│   └── sandboxes/
│       └── dev_jane/
│           └── experimental_project/public_html/

# Associated Service/Automation User Homes (example)
/home/sys_deploy_bot/
/home/sys_backup_svc/
# Site-specific automation scripts might reside in:
# /var/www/production/clients/clientA-ID001/example-client-site.com/scripts/

Each individual website (e.g., mycompany.com, example-client-site.com) has its web-accessible files located within its respective public_html/ subdirectory. Non-web-accessible files like logs, backups, and private configuration scripts are typically stored in the sibling private/ directory or other designated non-public directories.

3. Understanding Default Document Roots

A DocumentRoot is a critical directive in web server configuration (e.g., Apache, Nginx). It specifies the top-level directory in the server's file system from which it will serve files for a particular website or domain. When a user requests http://example.com/page.html, the web server looks for page.html within the DocumentRoot defined for example.com.

Common Default Document Roots:

These defaults are suitable for a single site or as a fallback. For hosting multiple distinct websites, Virtual Hosts (Apache) or Server Blocks (Nginx) are essential. Each virtual host/server block defines its own specific DocumentRoot (Apache) or root (Nginx) directive.

4. How Option 1 Relates to Document Roots

The "Option 1" directory structure is designed with the explicit use of virtual hosts/server blocks for every website. It moves away from a single, global default DocumentRoot.

Key Principles:

5. Why Option 1 is Fit for Your Scenario

This structure is particularly well-suited for managing multiple company sites, client sites (including reseller scenarios), and individual user sites due to:

  1. Clear Environment Separation (production/, staging/, development/):
    • Safety & Workflow: Enables safe testing and a structured deployment pipeline.
    • Configuration Flexibility: Allows different server settings per environment.
  2. Granular Ownership and Purpose Tiers (company/, clients/, users/, apps/):
    • Company Sites (company/internal/, public/): Manages diverse company web properties distinctly. Each company site (e.g., mycompany.com) has its own isolated directory.
    • Client Hosting (clients/): Supports a reseller model where each client (e.g., clientA-ID001/) can host multiple domains (e.g., example-client-site.com/, another-client-domain.net/), each with its own public_html/ and private/ areas.
    • Individual User Accounts (users/): Provides dedicated space for users to host multiple personal domains.
    • Shared Applications (apps/): For centrally managed shared applications.
  3. Scalability: Easy to add new environments, clients, users, or sites without clutter.
  4. Enhanced Security and Permissions:
    • Isolation: Site files are contained.
    • Granular Permissions: Allows setting specific file system ownership and permissions per environment, client, or site.
    • private/ Directory: Reinforces separation of public web content from sensitive backend data.
  5. Simplified Automation and Management: Consistent paths aid scripting for backups, deployments, etc.
  6. Superior to Default Structures: Avoids the chaos, security risks, and management nightmares of trying to host multiple diverse sites within a single default document root.

6. Practical Examples: Apache & Nginx Configurations

Below are explicit examples showing how different paths within the Option 1 structure map to DocumentRoot (Apache) and root (Nginx) for various site types in the production environment.


Example 6.1: Company Public Site (mycompany.com)

Apache Virtual Host Snippet (<VirtualHost> block):

<VirtualHost *:80>
    ServerAdmin webmaster@mycompany.com
    ServerName mycompany.com
    ServerAlias www.mycompany.com

    DocumentRoot /var/www/production/company/public/mycompany.com/public_html

    ErrorLog /var/www/production/company/public/mycompany.com/private/logs/error.log
    CustomLog /var/www/production/company/public/mycompany.com/private/logs/access.log combined

    <Directory /var/www/production/company/public/mycompany.com/public_html>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    # Additional security for private directory (though it's outside DocumentRoot)
    <Directory /var/www/production/company/public/mycompany.com/private>
        Require all denied
    </Directory>
</VirtualHost>

Nginx Server Block Snippet (server block):

server {
    listen 80;
    listen [::]:80;

    server_name mycompany.com www.mycompany.com;

    root /var/www/production/company/public/mycompany.com/public_html;
    index index.html index.htm index.php;

    access_log /var/www/production/company/public/mycompany.com/private/logs/access.log;
    error_log /var/www/production/company/public/mycompany.com/private/logs/error.log;

    location / {
        try_files $uri $uri/ /index.php?$query_string; # Example for PHP apps
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        # Adjust to your PHP-FPM version/socket, e.g.:
        fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
    }

    # Deny access to .htaccess or other sensitive files if they exist in public_html
    location ~ /\.ht {
        deny all;
    }
}

Example 6.2: Client Site (example-client-site.com for clientA-ID001)

Apache Virtual Host Snippet:

<VirtualHost *:80>
    ServerAdmin admin@example-client-site.com
    ServerName example-client-site.com
    ServerAlias www.example-client-site.com

    DocumentRoot /var/www/production/clients/clientA-ID001/example-client-site.com/public_html

    ErrorLog /var/www/production/clients/clientA-ID001/example-client-site.com/private/logs/error.log
    CustomLog /var/www/production/clients/clientA-ID001/example-client-site.com/private/logs/access.log combined

    <Directory /var/www/production/clients/clientA-ID001/example-client-site.com/public_html>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
        # Consider specific PHP-FPM user for this client if using PHP
        # <FilesMatch \.php$>
        #     SetHandler "proxy:unix:/var/run/php/php8.2-fpm-clientA.sock|fcgi://localhost/"
        # </FilesMatch>
    </Directory>

    <Directory /var/www/production/clients/clientA-ID001/example-client-site.com/private>
        Require all denied
    </Directory>
</VirtualHost>

Nginx Server Block Snippet:

server {
    listen 80;
    listen [::]:80;

    server_name example-client-site.com www.example-client-site.com;

    root /var/www/production/clients/clientA-ID001/example-client-site.com/public_html;
    index index.html index.htm index.php;

    access_log /var/www/production/clients/clientA-ID001/example-client-site.com/private/logs/access.log;
    error_log /var/www/production/clients/clientA-ID001/example-client-site.com/private/logs/error.log;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        # Consider a separate PHP-FPM pool for this client for better isolation
        # fastcgi_pass unix:/var/run/php/php8.2-fpm-clientA.sock;
        fastcgi_pass unix:/var/run/php/php8.2-fpm.sock; # Default if not using per-client pools
    }

    location ~ /\.ht {
        deny all;
    }
}

Example 6.3: Individual User Site (myblog.com for userX-UID101)

Apache Virtual Host Snippet:

<VirtualHost *:80>
    ServerAdmin userx@myblog.com
    ServerName myblog.com
    ServerAlias www.myblog.com

    DocumentRoot /var/www/production/users/userX-UID101/myblog.com/public_html

    ErrorLog /var/www/production/users/userX-UID101/myblog.com/private/logs/error.log
    CustomLog /var/www/production/users/userX-UID101/myblog.com/private/logs/access.log combined

    <Directory /var/www/production/users/userX-UID101/myblog.com/public_html>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    <Directory /var/www/production/users/userX-UID101/myblog.com/private>
        Require all denied
    </Directory>
</VirtualHost>

Nginx Server Block Snippet:

server {
    listen 80;
    listen [::]:80;

    server_name myblog.com www.myblog.com;

    root /var/www/production/users/userX-UID101/myblog.com/public_html;
    index index.html index.htm index.php;

    access_log /var/www/production/users/userX-UID101/myblog.com/private/logs/access.log;
    error_log /var/www/production/users/userX-UID101/myblog.com/private/logs/error.log;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
    }

    location ~ /\.ht {
        deny all;
    }
}

In all these examples, the key takeaway is the consistent use of public_html/ as the web-accessible root, with private/ (or similar) for non-web data. The web server is explicitly told where to find the public_html/ for each domain.

7. Conclusion

The "Option 1: Environment-First, then by Ownership/Purpose" directory structure, when paired with correctly configured virtual hosts (Apache) or server blocks (Nginx), provides a highly organized, scalable, and secure method for hosting diverse websites. By defining a specific DocumentRoot (or root) pointing to each site's public_html/ directory, you ensure clear separation of web-accessible content from private data, which is fundamental to secure web server administration. This structured approach simplifies management, enhances security, and supports a robust development-to-production workflow.