
"Permission denied" on Linux is not a sign that a file is broken, corrupted, or that something is wrong with the operating system. It means the kernel checked the permission bits on a file or directory against the user and group you are currently running as, and the match failed. Every file on a Linux filesystem has exactly one owning user, one owning group, and three sets of read, write, and execute bits — one set for the owner, one for the group, and one for everyone else. When you hit "permission denied" while opening, editing, uploading to, or executing something, the fix is almost never to reinstall software or restart a service. It is to work out which user actually needs access, then make sure that user's ownership or group membership lines up with the file. The rest of this article walks through the exact commands to diagnose the mismatch and correct it safely, without opening up access you did not intend to grant.
Before changing anything, find out who owns the file and who you actually are. Run ls -la /path/to/file to see the owner, group, and permission string on one line, for example -rw-r--r-- 1 www-data www-data 4096 wp-config.php. The first character tells you whether it is a file (-) or a directory (d); the next nine characters are three groups of rwx, covering the owner, the group, and everyone else in that order. Run whoami to confirm who you are logged in as, and id to see your uid, gid, and every group you belong to. If the file's owner and group do not appear anywhere in your id output, and the "others" bits do not grant the access you need, that mismatch is your answer — as far as the kernel is concerned, you are not authorized. For more detail, including the permission mode written in numeric octal form, run stat /path/to/file, which prints a line like Access: (0644/-rw-r--r--) alongside the exact Uid and Gid values. Every fix below targets whatever mismatch this step reveals, so do not skip it and guess.
The most common cause of permission denied on a website is that files were uploaded or created as one Linux user, while the web server process reads and writes as a different one. On stock Ubuntu and Debian servers running Nginx or Apache with PHP-FPM, that process user is typically www-data. If you uploaded files over SFTP or SSH as your own account, PHP-FPM will try to read them as www-data and get denied, even though the files look completely normal to you in a file manager.
Run that against the site's actual web root, not against / or your home directory. The -R flag applies the change to every file and subdirectory underneath, so one command re-owns an entire site in a single pass.
Ownership alone does not guarantee access — the permission bits still have to allow the right operations for that owner and group. Directories and files need different modes: a directory needs its execute bit set so a process can traverse into it, while a regular file only needs read, and sometimes write; it never needs to be "executable" just to be served or edited. Applying the same mode to both is one of the most common mistakes people make when they try to fix permissions in one shot.
A mode of 755 on directories gives the owner full access and gives everyone else read plus traverse; 644 on files gives the owner read and write, and everyone else read-only. If you are running WordPress and uploads still fail after this, wp-content/uploads specifically often needs to be group-writable at 775 when the web server's group differs from the file owner's group, so PHP can write new media into it without needing full ownership of the directory.
This one is worth calling out on its own because it produces a confusing symptom: read permission looks fine on paper, yet Linux still refuses access. Execute permission on a directory does not mean "run this directory" — it controls whether a process is allowed to enter, or traverse through, that directory at all in order to reach anything inside it. If a directory was set to 644 by mistake, which happens often when someone runs chmod across a whole tree without separating directories from files, every file inside becomes technically readable in isolation, but nothing can reach them because the folder itself cannot be entered. The result looks exactly like a corrupted permission structure, but it is really just a directory missing the execute bit for whoever needs to pass through it.
Never fix a permissions error with chmod -R 777. It makes every file and directory on the tree readable, writable, and executable by literally anyone on the system, turning a permissions bug into a security hole. If a process needs write access, add its user to the right group or chown the path to it — do not throw open access to everyone just to make the error message disappear.
On CloudStick, every website you create gets its own isolated system user, and the PHP-FPM pool for that site always runs as that exact same user — never as a single shared www-data account serving every site on the box. That means anything created through the CloudStick dashboard, whether it is the File Manager, a Git-based deploy, or the WordPress installer, is already owned by the correct user with the correct group the moment it lands on disk, and this entire class of error mostly stops coming up.
The one case CloudStick users still run into this: uploading files through an SFTP or FTP account that is not the site's own isolated user. If you created a separate FTP login for a client or teammate and they uploaded through it, those files land owned by that FTP user instead of the site's user, and PHP-FPM will hit the same permission denied wall described above. The fix is identical — chown the uploaded files back to the site's user and group, then re-apply 755/644 with find if the FTP client also mangled the modes on the way in.
To summarize: check ls -la and stat before you change anything, chown to the process or account that actually needs access, use 755 for directories and 644 for files as a sane default, watch specifically for a directory missing its execute bit, and never reach for chmod -R 777 as a shortcut — it fixes the symptom by removing the security the permission system was there to provide. Get the owner and the mode right together, and the error stops coming back the next time a service restarts or a cron job runs.

