Linux Permission Denied: How to Fix File Permission Errors When Deploying Apps
You deployed your app. Maybe you built it with an AI tool, maybe you followed a tutorial. You go to your site and something is broken. You check the logs and see:
Permission denied
Maybe your app can't read its own config file. Maybe Nginx can't serve your pages. Maybe your upload folder doesn't work. You ask the AI to fix it. It tells you to run chmod 777 on everything. That feels wrong. It is wrong.
Here's what's actually going on and how to fix it properly.
What "Permission denied" actually means
Linux has a permissions system. Every file and every folder on the server has an owner, and a set of rules about who is allowed to do what with it.
Think of it like an office building. Every room has a lock, and only certain people have keys. "Permission denied" means you walked up to a door and your keycard didn't work. You might be a legitimate employee who should have access. But right now, the system says no.
The error doesn't mean the file is broken or missing. It means the user trying to access it isn't allowed to.
The three types of permissions
Every file and folder in Linux has three types of permissions:
- Read — Can you look at the contents? For a file, this means opening it. For a folder, it means listing what's inside.
- Write — Can you change it? For a file, this means editing or overwriting it. For a folder, it means creating or deleting files inside it.
- Execute — Can you run it? For a file, this means running it as a program or script. For a folder, it means being able to enter it (you need execute permission on a directory to
cdinto it).
And these permissions are set separately for three categories of people:
- Owner — The user who owns the file. Usually whoever created it.
- Group — A set of users who share access. Every file belongs to a group.
- Everyone else — Any user on the system who isn't the owner and isn't in the group.
So when you see something like -rw-r--r-- in a file listing, that's saying: the owner can read and write, the group can only read, and everyone else can only read. Nobody can execute it.
Why deploying apps triggers this constantly
Here's the pattern that causes most permission denied errors during deployment:
- You follow the AI's deploy instructions. They tell you to run a bunch of commands with
sudo. sudoruns commands as root, the all-powerful admin user. So all the files that get created — your app code, config files, log directories — are now owned by root.- Your app doesn't run as root. It runs as a regular user like
www-data,node,deploy, orubuntu. - Your app tries to read its config file. That file is owned by root. Your app isn't root. Permission denied.
It's like the building manager set up all the offices, locked every door, and kept all the keys. Then your employees show up for work and can't get into any of the rooms.
This also works in reverse. Sometimes your app creates files (like uploads or logs) as its own user, and then Nginx — which runs as www-data — can't read them to serve them to visitors.
The most common scenarios
Your app can't read its config file
You deployed the config with sudo, so it's owned by root. Your app runs as a different user and can't read it. The app crashes on startup with "permission denied" pointing at something like /etc/yourapp/config.yml or .env.
Your app can't write to the log directory
The app tries to write log files to /var/log/yourapp/ but that directory is owned by root and your app user doesn't have write permission. The app either crashes or silently fails to log anything, which makes debugging everything else harder.
Your app can't execute a script
You have a startup script or a build script. It was created or transferred from another machine. Linux doesn't automatically make files executable. The file exists, the content is fine, but the system won't run it because the execute permission isn't set.
bash: ./start.sh: Permission denied
Nginx can't read your app's files
Your static files, images, or a built frontend are sitting in a directory that Nginx can't access. Nginx runs as www-data (on Ubuntu/Debian) or nginx (on CentOS/RHEL). If your files are owned by your deploy user and the permissions are too restrictive, Nginx gets "permission denied" and your visitors see 403 Forbidden errors.
Uploaded files aren't accessible
Users upload files through your app. The app saves them. But when someone tries to view or download the file, it doesn't work. The app created the files with permissions that only allow the app user to read them, not the web server user that needs to serve them.
How to fix it: chown and chmod
There are two tools you need to know. They do different things and you usually need both.
chown: Fix who owns the file
chown stands for "change owner." This is the fix for most permission problems. If your files are owned by root and your app runs as deploy, change the owner:
sudo chown -R deploy:deploy /path/to/your/app
The -R means "recursive" — do it for every file and folder inside that path, not just the top-level directory. The deploy:deploy part sets both the owner and the group to deploy.
Some common examples:
# Your app code should be owned by the user that runs the app
sudo chown -R deploy:deploy /var/www/myapp
# Log directory needs to be writable by the app user
sudo chown -R deploy:deploy /var/log/myapp
# If Nginx needs to read files, add it to the right group
# or make the files owned by www-data
sudo chown -R www-data:www-data /var/www/myapp/public
To find out what user your app runs as, check your systemd service file or your process manager config. Or just run:
ps aux | grep your-app-name
The first column shows the user.
chmod: Fix what's allowed
chmod stands for "change mode." It sets the read/write/execute permissions. Even if you own a file, the permissions might be too restrictive.
The numbers work like this:
- 7 = read + write + execute (full access)
- 6 = read + write
- 5 = read + execute
- 4 = read only
- 0 = no access
You specify three digits: owner, group, everyone else. So chmod 755 means the owner gets full access (7), the group can read and execute (5), and everyone else can read and execute (5).
Here are the two settings you need for almost everything:
# Directories should be 755 (owner: full, others: read + enter)
find /var/www/myapp -type d -exec chmod 755 {} \;
# Regular files should be 644 (owner: read + write, others: read only)
find /var/www/myapp -type f -exec chmod 644 {} \;
If you have scripts that need to be executable:
# Make a specific script executable
chmod +x start.sh
The right order: chown first, then chmod
Fix ownership first, then adjust permissions. Most of the time, fixing ownership alone solves the problem. You only need chmod when the permission bits themselves are wrong — like a script that isn't executable, or files that were created with overly restrictive permissions.
The sudo trap
This is the single biggest cause of permission problems in AI-assisted deployments, and it deserves its own section.
When the AI helps you deploy an app, almost every command starts with sudo. Install packages? sudo apt install. Copy files? sudo cp. Edit configs? sudo nano. Create directories? sudo mkdir.
Every one of those commands runs as root. Every file created or copied is now owned by root. Your entire application directory tree ends up owned by root.
Then the AI tells you to set up a systemd service that runs your app as a non-root user (which is correct — you should not run apps as root). But now your app can't access any of its own files because they all belong to root.
The fix isn't to run your app as root. The fix is to stop creating everything as root in the first place. Or, more practically, to fix the ownership after everything is set up:
# After deploying, fix ownership for the whole app directory
sudo chown -R youruser:youruser /var/www/myapp
# And the log directory
sudo chown -R youruser:youruser /var/log/myapp
If the AI tells you to run your app with sudo, that is almost always wrong. Running an app as root is a security risk. The right approach is to run it as a regular user that owns its own files.
Why AI makes this worse
Permission problems are one of the areas where AI advice actively makes things worse. Here's why:
The AI doesn't know what user your app runs as. It can't check. It has no idea if your app runs as deploy, ubuntu, node, www-data, or something else entirely. So it can't give you the right chown command. It guesses, and if it guesses wrong, the fix doesn't work.
The AI defaults to chmod 777. When it doesn't know the real fix, it tells you to make everything readable, writable, and executable by everyone. This "works" in the sense that the error goes away. But it means any user on the system — and any compromised process — can read, modify, or delete your files. Your database config with passwords in it? World-readable. Your upload directory? Anyone can write to it. On a shared hosting environment, this is genuinely dangerous. Even on your own VPS, it masks the real problem instead of fixing it.
The AI suggests sudo when ownership is the real fix. "Just put sudo in front of the command." Sure, that makes the command succeed right now. But it creates files owned by root, which causes more permission errors later, which leads to more sudo, which leads to more root-owned files. It's a cycle that makes the problem worse with every iteration.
The AI can't see your file permissions. A human engineer would run ls -la, see that the files are owned by root and the app runs as deploy, and immediately know the fix. The AI can't look. It gives you generic advice based on the error message alone, without seeing the actual state of your system.
A quick reference
When you hit "permission denied," work through this checklist:
- Who owns the file? Run
ls -la /path/to/fileand look at the owner and group columns. - What user is trying to access it? Check what user your app or service runs as.
- Do they match? If not,
chownis your fix. - Are the permission bits right? Directories need execute permission (755). Files need read permission (644). Scripts need execute permission (755 or
chmod +x). - Is this a parent directory issue? Even if a file has the right permissions, the user needs execute permission on every directory in the path leading to it. A locked parent directory blocks access to everything inside it.
Still getting "Permission denied"?
Permission problems can cascade in surprising ways, especially when AI advice has been layering sudo commands and chmod changes on top of each other. Press the MeatButton and a real expert will look at your actual file permissions and fix them properly. First one's free.
Get MeatButton