CresignSys Learn — Lesson 043

Written by

in

Linux Filesystem & Permissions — The Foundation of Web Hosting

We now move below Nginx and PHP-FPM.

A web server ultimately depends on the Linux operating system being able to answer:

Who is allowed to read, write, execute, create, delete, and access this file?

For your hosting system, this is fundamental.


1. The Hosting Stack So Far

We have reached:

Browser
   ↓
DNS
   ↓
IP
   ↓
TCP
   ↓
TLS
   ↓
HTTP
   ↓
Nginx
   ↓
PHP-FPM
   ↓
WordPress
   ↓
MySQL

Now go one layer deeper:

PHP-FPM
   ↓
Linux filesystem
   ↓
Storage

2. Linux Is a Filesystem-Centered System

Linux represents many things through files or filesystem interfaces.

You will constantly work with:

/
├── etc/
├── var/
├── home/
├── usr/
├── run/
├── tmp/
└── storage/

The first:

/

is called:

Root directory

It is the top of the Linux filesystem hierarchy.


3. / Is Not /root

These are completely different.

/

means:

filesystem root

while:

/root

means:

home directory of the root user

This distinction is very important.


4. Your Website Path

Your hosting structure has looked like:

/storage/websites/

Inside:

/storage/websites/
├── domain1.com/
├── domain2.com/
└── domain3.com/

Each domain can have its own directory.


5. Example

Suppose:

/storage/websites/templates.cresignsys.com/public/

contains:

public/
├── index.php
├── wp-admin/
├── wp-content/
├── wp-includes/
└── wp-config.php

This is your WordPress document root.


6. Path

A path identifies where something exists.

For example:

/storage/websites/templates.cresignsys.com/public/index.php

Break it down:

/
└── storage
    └── websites
        └── templates.cresignsys.com
            └── public
                └── index.php

7. Absolute Path

A path beginning with:

/

is an absolute path.

Example:

/storage/websites/templates.cresignsys.com/public

It starts from filesystem root.


8. Relative Path

A relative path depends on your current directory.

If you are inside:

/storage/websites/templates.cresignsys.com/

then:

public/index.php

refers to:

/storage/websites/templates.cresignsys.com/public/index.php

9. pwd

To find your current directory:

pwd

Example:

/storage/websites/templates.cresignsys.com/public

pwd means:

Print Working Directory


10. ls

To see files:

ls

More detailed:

ls -l

Including hidden files:

ls -la

11. Example ls -l

You may see:

-rw-r--r-- 1 www-data www-data 1234 Aug 13 index.php

This line contains a lot of information.

Let’s decode it.


12. First Character

-rw-r--r--
^

The first character tells you the object type.

Common examples:

-

regular file.

d

directory.

l

symbolic link.

So:

-rw-r--r--

is a regular file.


13. Permission Characters

After the first character:

rw-r--r--

There are three groups:

rw-
r--
r--

These correspond to:

Owner
Group
Others

14. Read

r

means:

Read

For a file, read means the process can read its contents.

For a directory, read has a different meaning: it allows listing directory entries, subject to other permissions.


15. Write

w

means:

Write

For a file:

w

allows modifying its contents.

For a directory, write is related to creating, deleting, and renaming entries within it.


16. Execute

x

means:

Execute

For an ordinary executable file, it allows execution.

For a directory, x means the process can traverse/access entries within that directory, subject to other permissions.

This distinction is extremely important for web hosting.


17. Three Permission Groups

Consider:

rw-r--r--

Break it:

rw- | r-- | r--
 │     │     │
 │     │     └── Others
 │     └──────── Group
 └────────────── Owner

18. Example

-rw-r--r--

means:

Owner:
rw-

Group:
r--

Others:
r--

So:

Owner → read + write
Group → read
Others → read

19. Numeric Permissions

Linux also represents permissions numerically.

The values are:

r = 4
w = 2
x = 1

Add them.


20. 7

rwx

means:

4 + 2 + 1 = 7

21. 6

rw-

means:

4 + 2 = 6

22. 5

r-x

means:

4 + 1 = 5

23. 4

r--

means:

4

24. 0

---

means:

0

25. 755

A very common directory permission:

755

means:

Owner:
7 = rwx

Group:
5 = r-x

Others:
5 = r-x

So:

rwxr-xr-x

26. 644

A common file permission:

644

means:

Owner:
6 = rw-

Group:
4 = r--

Others:
4 = r--

Therefore:

rw-r--r--

27. Why 644 Is Common for Files

A normal web file such as:

index.php
style.css
logo.png

usually needs to be readable by the web server.

It doesn’t normally need to be executable as a Unix program.

Therefore:

644

is often appropriate.

But permissions must always be determined from the actual application and deployment model.


28. Why 755 Is Common for Directories

A directory generally needs:

r

to list entries and:

x

to traverse it.

A common configuration is:

755

allowing the owner full access and others read/traverse access.

Again, the correct permissions depend on the application.


29. Owner

Now consider:

-rw-r--r-- 1 www-data www-data index.php

The first:

www-data

is the owner.

The second:

www-data

is the group.


30. User

Linux identifies users.

Examples:

root
ubuntu
www-data

Each has a user ID.

The kernel uses these identities when enforcing permissions.


31. Group

A user can belong to one or more groups.

Groups allow permissions to be shared among multiple users/processes.

For example:

webadmins

could contain administrators who need access to website files.


32. Root

root is the superuser.

Conceptually:

root
 ↓
very high system privileges

Root can bypass many ordinary filesystem permission restrictions.

That power must be used carefully.


33. sudo

If you are logged in as:

ubuntu

you may use:

sudo command

to execute a command with elevated privileges if your account is authorized.

For example:

sudo systemctl reload nginx

34. Why sudo Matters

Changing:

/etc/nginx/

usually requires elevated privileges.

But editing your website’s own files may not require root.

A good principle is:

Use the minimum privileges required for the task.


35. www-data

On Debian/Ubuntu web servers, services such as Nginx and PHP-FPM commonly use:

www-data

as their service user, though the exact configuration should be checked.


36. Why www-data Matters

Suppose:

Browser
 ↓
Nginx
 ↓
PHP-FPM

and PHP-FPM runs as:

www-data

Then PHP processes access files as that Linux user.

Therefore:

PHP-FPM
 ↓
Linux permissions
 ↓
website files

37. WordPress Needs Write Access

WordPress may need to write files for things such as:

uploads
plugin installation
theme installation
updates
generated cache files
temporary files

Whether WordPress should have write access to all of the site is a security/design decision.

Giving the entire WordPress tree broad write access is generally undesirable.


38. Security Principle

Don’t simply do:

chmod -R 777 /storage/websites/example.com

This is a major mistake.

777 means:

Owner  = rwx
Group  = rwx
Others = rwx

Everyone gets broad read/write/execute access.


39. Why 777 Is Dangerous

Imagine an attacker finds a vulnerability in a website.

If everything is writable:

Attacker
 ↓
Web application vulnerability
 ↓
Write anywhere
 ↓
Upload/modify files
 ↓
Persistence

The impact can become much worse.


40. Principle of Least Privilege

A fundamental security principle:

Give a process only the permissions it actually needs.

For example:

Static assets
 ↓
read-only for web server

while:

wp-content/uploads
 ↓
write access where needed

This creates a smaller attack surface.


41. Directory Permissions Are Different

Suppose:

drwxr-xr-x

The x on a directory means:

Can traverse this directory.

Without directory execute permission, even if a user can read the directory listing, access to files inside can still fail.


42. Example

Imagine:

/storage
   ↓
/websites
   ↓
/example.com
   ↓
/public

The web-service user needs appropriate traversal permissions through every parent directory.

If one parent directory blocks traversal:

/storage
   ↓
permission denied

Nginx may fail to serve the website.


43. chmod

chmod changes permissions.

Example:

chmod 644 index.php

or:

chmod 755 public

44. Symbolic Permissions

Instead of:

chmod 644 file

you can use:

chmod u=rw,g=r,o=r file

This means:

u = user/owner
g = group
o = others

45. chown

chown changes ownership.

Example:

sudo chown www-data:www-data index.php

This sets:

owner = www-data
group = www-data

46. chgrp

chgrp changes the group without changing the owner.

Example:

sudo chgrp webadmins file.txt

47. Ownership vs Permissions

Don’t confuse these.

Ownership answers:

Who owns this?

Permissions answer:

What can the owner/group/others do?

48. Example

Suppose:

-rw-r----- 
root webadmins

Then:

Owner:
root → read/write

Group:
webadmins → read

Others:
no access

49. id

To see your current user and groups:

id

Example:

uid=1000(ubuntu) gid=1000(ubuntu) groups=...

50. Check www-data

You can inspect:

id www-data

This tells you the user ID and group memberships.


51. Find Nginx User

Inspect Nginx configuration:

grep -n "user " /etc/nginx/nginx.conf

You may see something like:

user www-data;

52. Find PHP-FPM User

The PHP-FPM pool configuration determines the worker user.

Depending on PHP version, inspect:

grep -R "^[[:space:]]*user[[:space:]]*=" /etc/php/*/fpm/pool.d/

and:

grep -R "^[[:space:]]*group[[:space:]]*=" /etc/php/*/fpm/pool.d/

You may see:

user = www-data
group = www-data

53. Nginx and PHP-FPM May Both Use www-data

A common architecture is:

Nginx
 ↓
www-data

PHP-FPM
 ↓
www-data

This simplifies access to website files.

But it also means you should carefully design write permissions.


54. Website Directory Design

A clean hosting structure could be:

/storage/websites/
│
├── example.com/
│   ├── public/
│   ├── logs/
│   └── private/
│
├── shop.example.com/
│   ├── public/
│   ├── logs/
│   └── private/
│
└── learn.example.com/
    ├── public/
    ├── logs/
    └── private/

The key principle is:

public/
=
web-accessible area

55. Public vs Private

Suppose:

/storage/websites/example.com/public/

is Nginx’s document root.

Anything inside this directory may potentially be served through HTTP if the Nginx configuration permits it.

Therefore don’t put secrets there.


56. Dangerous Files

Never intentionally expose things such as:

.env
private keys
database backups
SSH keys
application secrets
configuration credentials

through the public document root.


57. WordPress wp-config.php

WordPress has:

wp-config.php

which may contain database credentials and security secrets.

Therefore:

public/wp-config.php

must be protected by the web-server/application architecture.

Modern WordPress/Nginx setups generally prevent direct source disclosure of PHP files because PHP is executed rather than served as plain text, but defense-in-depth still matters.


58. PHP Source Must Not Be Downloadable

If a PHP file were accidentally served as:

text/plain

instead of being processed by PHP-FPM, its source code could be exposed.

Correct architecture:

.php
 ↓
Nginx
 ↓
PHP-FPM
 ↓
execute

not:

.php
 ↓
Browser downloads source

59. Permissions and WordPress

A typical security-oriented approach is:

WordPress core
 ↓
mostly read-only

Uploads/cache areas
 ↓
writeable as required

The exact strategy depends on how you administer WordPress.


60. Linux File Permissions Are Not the Only Layer

A file can be restricted by:

Unix permissions
+
ACLs
+
SELinux/AppArmor
+
Nginx rules
+
PHP-FPM restrictions
+
filesystem mount options

Ubuntu commonly uses AppArmor for some services.


61. ACL

ACL means:

Access Control List

ACLs can provide permissions beyond the simple:

owner
group
others

model.

For example:

user A → read/write
user B → read
group C → read

on the same file.


62. getfacl

To inspect ACLs:

getfacl file.txt

If your server doesn’t use custom ACLs, the output may closely resemble normal permissions.


63. setfacl

ACLs can be changed with:

setfacl

But don’t introduce ACL complexity unless you actually need it.

For a hosting platform, simple ownership/groups are often easier to maintain.


64. Symbolic Links

You may see:

lrwxrwxrwx

The first character:

l

means:

Symbolic link

A symbolic link points to another path.


65. Let’s Encrypt Uses Links

This is particularly relevant to your server.

Certbot commonly maintains:

/etc/letsencrypt/live/domain/

with symbolic links to files under:

/etc/letsencrypt/archive/domain/

Conceptually:

live/
 ↓
symbolic link
 ↓
archive/

This is one reason you should not casually delete or replace those files manually.


66. Inspect the Links

Run:

sudo ls -la /etc/letsencrypt/live/templates.cresignsys.com/

You may see entries similar to:

cert.pem -> ../../archive/.../cert1.pem
chain.pem -> ../../archive/.../chain1.pem
fullchain.pem -> ../../archive/.../fullchain1.pem
privkey.pem -> ../../archive/.../privkey1.pem

The exact numbering can vary.


67. Why live/ Exists

Certbot can maintain stable paths:

/etc/letsencrypt/live/domain/fullchain.pem

while the actual versioned certificate files live elsewhere.

Nginx can keep referencing the stable path.

When renewal occurs, the links can be updated to the latest version.


68. Certificate Renewal Connection

Now connect the filesystem lesson to TLS:

Certbot
 ↓
new certificate
 ↓
/etc/letsencrypt/archive/
 ↓
updates /live/ links
 ↓
Nginx reload
 ↓
new certificate used

This is why file permissions and symlinks matter to SSL automation.


69. ls -l Is a Core Skill

You should become comfortable reading:

ls -la

because it tells you:

file type
permissions
owner
group
size
timestamp
name
symlink target

70. stat

For deeper information:

stat index.php

You can see:

File
Size
Blocks
IO Block
Device
Inode
Links
Access
Uid
Gid
Access time
Modify time
Change time

71. Inode

Every filesystem object has an:

inode

The inode stores metadata associated with a filesystem object.

Conceptually:

Filename
   ↓
directory entry
   ↓
inode
   ↓
metadata + file data references

72. Filename vs Inode

A filename isn’t the file’s entire identity internally.

The filesystem maintains a relationship:

directory
   ↓
name → inode

This explains concepts such as hard links.


73. Hard Link

A hard link is another directory entry referring to the same inode.

Conceptually:

file1
  │
  ▼
inode 123

file2
  │
  ▼
inode 123

Both names refer to the same underlying inode.


74. Symbolic Link

A symbolic link is different:

link
 ↓
path to another object

It doesn’t point directly to the target inode in the same way a hard link does.


75. Why This Matters to Hosting

You will encounter symbolic links in:

Let's Encrypt
PHP configurations
Nginx configurations
Application deployments
Release management

Understanding them prevents many mistakes.


76. Disk Space

Website files ultimately consume storage.

Check:

df -h

This shows filesystem capacity.

Example:

Filesystem
Size
Used
Avail
Use%
Mounted on

77. Directory Size

To inspect a website:

du -sh /storage/websites/templates.cresignsys.com

For more detail:

du -sh /storage/websites/templates.cresignsys.com/*

This helps identify what is consuming disk space.


78. Disk vs Inode Exhaustion

A server can have free disk space but still run out of inodes.

Check:

df -i

This is particularly relevant to hosting servers with huge numbers of small files.


79. Why Hosting Servers Can Have Many Files

WordPress can contain:

Core files
Plugins
Themes
Uploads
Cache
Logs
Temporary files

A server hosting hundreds of sites can therefore contain millions of filesystem objects.


80. Permissions + Storage + Nginx

A web request ultimately becomes:

HTTP
 ↓
Nginx
 ↓
Filesystem
 ↓
Linux kernel
 ↓
Permission check
 ↓
Disk

The kernel decides whether the Nginx/PHP process is allowed to perform the operation.


81. Linux Kernel Is the Authority

This is a deep concept.

Nginx does not decide:

www-data is allowed to read this file.

The Linux kernel enforces filesystem access.

Conceptually:

Nginx process
 ↓
system call
 ↓
Linux kernel
 ↓
permission check
 ↓
filesystem

82. System Call

Programs interact with the kernel through system calls.

For example, a program may request:

open file
read file
write file

The kernel decides whether the operation is permitted.


83. Example

Nginx wants:

read:
/storage/websites/example.com/public/index.html

Conceptually:

Nginx
 ↓
open()
 ↓
Linux kernel
 ↓
check permissions
 ↓
allow/deny

If denied:

Permission denied

84. This Explains 403

Suppose Nginx receives:

GET /secret.html

but cannot read the file.

The result may become:

403 Forbidden

depending on the configuration and exact reason.


85. This Explains PHP Errors Too

Suppose PHP-FPM tries to write:

wp-content/uploads/

but doesn’t have permission.

Then:

WordPress
 ↓
PHP-FPM
 ↓
Linux permission check
 ↓
DENIED

WordPress may report an upload or filesystem error.


86. Three Different Users

On your server you might have:

ubuntu
root
www-data

They serve different purposes.

ubuntu

Administrative login user.

root

System superuser.

www-data

Web-service/application user.

The exact users on your system should be verified.


87. Why Don’t Run Everything as Root?

If PHP-FPM ran as root:

PHP vulnerability
 ↓
attacker
 ↓
root privileges
 ↓
potential full server compromise

Running services with restricted privileges limits the potential impact.


88. Security Model

A strong hosting architecture tries to separate:

Administrator
     ↓
root/sudo

Web server
     ↓
limited service user

Database
     ↓
database-specific account

Website
     ↓
restricted filesystem permissions

89. Database User Is Separate

WordPress doesn’t normally connect to MySQL as Linux root.

It uses database credentials stored in its configuration.

Conceptually:

WordPress
 ↓
MySQL credentials
 ↓
MySQL user
 ↓
specific database

This is another layer of least privilege.


90. Linux User vs MySQL User

Don’t confuse:

Linux:
www-data

with:

MySQL:
wordpress_user

They belong to different security systems.


91. Complete Security Boundary

Your website now has several independent layers:

Internet
 ↓
Cloud firewall
 ↓
Ubuntu networking
 ↓
Nginx
 ↓
TLS
 ↓
Linux user
 ↓
Filesystem permissions
 ↓
PHP-FPM
 ↓
WordPress
 ↓
MySQL user
 ↓
Database permissions

92. Practical Inspection

For your website, start with:

ls -ld /storage
ls -ld /storage/websites
ls -ld /storage/websites/templates.cresignsys.com
ls -ld /storage/websites/templates.cresignsys.com/public

This shows directory permissions and ownership at every level.


93. Inspect WordPress Files

ls -la /storage/websites/templates.cresignsys.com/public

Look for:

index.php
wp-config.php
wp-admin/
wp-content/
wp-includes/

94. Inspect Ownership

sudo stat /storage/websites/templates.cresignsys.com/public/index.php

Look for:

Uid
Gid
Access

95. Test Access as www-data

A very useful diagnostic:

sudo -u www-data ls \
/storage/websites/templates.cresignsys.com/public

This asks:

Can the www-data user actually list this directory?


96. Test Reading a File

sudo -u www-data cat \
/storage/websites/templates.cresignsys.com/public/index.php

If permission is denied, you have identified a filesystem-access problem.

Be careful with commands that print sensitive configuration files such as wp-config.php.


97. Test Directory Traversal

You can inspect each parent:

namei -l /storage/websites/templates.cresignsys.com/public/index.php

This is an excellent command.

It shows permissions/ownership along the entire path.


98. Why namei Is Powerful

Suppose:

/storage

is inaccessible to www-data.

Even if:

public/index.php

has:

644

Nginx may still fail.

namei -l helps find the exact blocking directory.


99. The Practical Permission Model

A useful starting principle for a typical WordPress hosting setup is:

Directories
≈ 755

Files
≈ 644

but don’t blindly apply these recursively to every file.

Sensitive files and writable directories may need different permissions.


100. Never Blindly Run Recursive Permission Commands

Avoid blindly doing:

chmod -R 777 ...

or:

chown -R www-data:www-data /

The second could be catastrophic.

Always specify the exact website directory and understand what you’re changing.


101. Your Hosting Platform

For your CresignSys Hosting Platform, a better model is:

/storage/websites/
│
├── site1/
│   ├── public/
│   ├── logs/
│   └── private/
│
├── site2/
│   ├── public/
│   ├── logs/
│   └── private/
│
└── site3/
    ├── public/
    ├── logs/
    └── private/

Then your automation can consistently create:

directory
ownership
permissions
Nginx configuration
PHP-FPM configuration
SSL configuration
logs

102. Hosting Automation Flow

Eventually your hosting-create script can do:

Create domain
     ↓
Create directories
     ↓
Set ownership
     ↓
Set permissions
     ↓
Create Nginx config
     ↓
Test Nginx
     ↓
Reload Nginx
     ↓
Create DNS record
     ↓
Issue Let's Encrypt certificate
     ↓
Install certificate
     ↓
Configure HTTPS
     ↓
Install WordPress

You are now learning the individual layers behind that automation.


103. Deep Architecture

We can now expand the stack:

                    INTERNET
                       │
                       ▼
                      DNS
                       │
                       ▼
                    ROUTING
                       │
                       ▼
                    TCP/UDP
                       │
                       ▼
                      TLS
                       │
                       ▼
                      HTTP
                       │
                       ▼
                     NGINX
                       │
                ┌──────┴──────┐
                ▼             ▼
           FILESYSTEM      PHP-FPM
                              │
                              ▼
                          WORDPRESS
                              │
                              ▼
                            MYSQL
                              │
                              ▼
                          STORAGE

And underneath everything:

Linux Kernel
     ↓
CPU
     ↓
RAM
     ↓
Disk/Storage
     ↓
Network Interface

104. The Next Level

We have now reached an important boundary.

We understand:

DNS
IP
TCP
TLS
HTTP
Nginx
Filesystem
Permissions

The next major component is:

PHP-FPM

because this is the bridge between:

Nginx

and:

WordPress

Lesson 043 Summary

The most important concepts are:

Path
=
location of a filesystem object

Owner
=
user associated with the object

Group
=
group associated with the object

Permissions
=
read/write/execute rules

www-data
=
common web-service user

root
=
superuser

chmod
=
change permissions

chown
=
change ownership

sudo
=
execute with elevated privileges

inode
=
filesystem metadata/object identifier

symlink
=
link pointing to another path

For your hosting server:

Browser
 ↓
Nginx
 ↓
PHP-FPM
 ↓
Linux kernel
 ↓
Filesystem

Linux permissions determine whether those processes can actually access the files they need.


Next Lesson — 044

PHP-FPM From Zero — How PHP Actually Runs on Your Server

We will trace:

Browser
 ↓
Nginx
 ↓
FastCGI
 ↓
PHP-FPM
 ↓
PHP worker process
 ↓
WordPress
 ↓
MySQL

and go deeply into:

PHP
PHP-FPM
FPM pools
workers
Unix sockets
FastCGI
php.ini
memory limits
execution limits
OPcache
PHP versions
PHP 8.x
process management
www-data
security isolation

This is the next major foundation for understanding why WordPress hosting works.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *