For a static Linux website, let root or a deployment account own the document tree, and give the configured web-server account read and directory-traverse access through its group. Do not make Apache or Nginx the owner of the entire web root unless an application requirement specifically demands it. On Ubuntu, Apache commonly runs as www-data; Fedora’s Nginx configuration commonly uses nginx. Verify the account configured on your host before changing anything.
A practical read-only layout is root:nginx (or root:www-data), mode 750 on directories and 640 on files. Use 755 and 644 instead when anonymous users or an intermediary process genuinely need world-read access. Ownership and mode bits are only part of the check: every parent directory must permit traversal, and SELinux can deny access even when Unix permissions look correct.
As an Amazon Associate I earn from qualifying purchases.
What the ownership model is protecting
The web server must read the files it publishes, but it normally should not be able to rewrite the site’s source, configuration, templates, or scripts. If a server process is compromised, ownership of the whole tree would give the attacker a straightforward way to replace the application or inject content. Apache’s filesystem guidance therefore separates read access from ownership and limits write access to directories that an application explicitly needs.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →On a typical Linux installation, the service starts with elevated privileges only long enough to bind and initialize, then serves requests as its configured unprivileged account. Ubuntu identifies www-data as the common Apache user and group. Fedora’s Nginx documentation uses nginx. These names are conventions, not universal rules: a packaged service, container, hosting panel, or local administrator may select another account.
#1 Best Overall
Static content
For HTML, CSS, JavaScript, images, downloads, and other files that visitors only read, keep the owner as root or as the account used by your deployment system. Put the web-server account in the owning group, or set the group on the tree to that service group, and grant only the read and traverse permissions required to serve the content.
Dynamic applications
A CMS, publishing platform, or other application may need to create uploads, cache entries, compiled assets, or generated content. That requirement does not justify making the entire document tree writable. Keep source code, configuration, templates, and scripts protected, then create a separate writable directory for each required function.
Identify the account that actually serves requests
Never assume that www-data or nginx is correct merely because it is common on a distribution. Find the service definition and inspect its configured user and group.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11- Determine the web server. Check whether the site is served by Apache, Nginx, or another front end. A reverse proxy may read static files while an application process reads a different tree.
- Inspect the service configuration. Apache uses
UserandGroupdirectives; Nginx uses auserdirective. The effective setting can be in an included configuration file rather than the main file. - Confirm the running identity. Compare the configuration with the user and group shown for the worker processes. This catches overrides made by a distribution package, a systemd unit, a container image, or a hosting control panel.
- Record the document root. The directory named by the virtual host or server block may not be
/var/www/html. Apply permissions to the actual path and to every parent directory leading to it.
Changing ownership before completing these checks is a common cause of a new 403 response: the files may be readable by one service account while the running workers use another.
A secure baseline for a static web root
The following pattern gives the service group read access without giving it ownership or write access. Replace nginx with the group configured on your machine and replace the path with the real document root.
sudo chown -R root:nginx /srv/my-site/html
sudo find /srv/my-site/html -type d -exec chmod 750 {} +
sudo find /srv/my-site/html -type f -exec chmod 640 {} +
With these modes, the owner can read and modify files, the group can read files and traverse directories, and users outside those two classes have no access. The web server therefore needs membership in the nginx group (or the equivalent service group). If the service account is not a member of that group, the group bits do not help; set the group to the service’s effective group or arrange group membership according to your system’s administration policy.
Ubuntu-style Apache example
sudo chown -R root:www-data /var/www/html
sudo find /var/www/html -type d -exec chmod 750 {} +
sudo find /var/www/html -type f -exec chmod 640 {} +
This is an example, not a claim that every Ubuntu host uses the same path or account. Check the Apache configuration first.
When 755 and 644 are appropriate
Some deployments require world-read access. An intermediary process, a separate service account, or a design that does not share the web-server group may need to read the tree as an ordinary user. In that case, use directory mode 755 and file mode 644:
sudo find /srv/my-site/html -type d -exec chmod 755 {} +
sudo find /srv/my-site/html -type f -exec chmod 644 {} +
These modes still reserve write permission for the owner. They expose file contents to every local user who can reach the path, so prefer the more restrictive group-readable pattern when it works for your architecture. Fedora’s Nginx guidance specifically warns against nginx:nginx ownership for static documents because it grants the server unnecessary write access.
Why directory permissions matter as much as file permissions
A readable file is not enough to serve a URL. Linux checks the path one directory at a time. The process needs execute (x) permission on the document root and on every parent directory so it can traverse the path. A file can show apparently correct read bits while a parent directory blocks the request and produces a 403.
For example, serving /srv/my-site/html/assets/logo.svg requires traversal permission on /srv, /srv/my-site, /srv/my-site/html, and /srv/my-site/html/assets, plus read permission on logo.svg. Inspect each component when debugging:
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →namei -l /srv/my-site/html/assets/logo.svg
If namei is unavailable, inspect the directories individually with ls -ld. Do not “fix” a blocked parent by making the entire filesystem world-writable; grant the narrowest traverse permission that lets the configured service account reach the root.
Keep writable areas narrowly scoped
Applications that accept uploads or generate files should write only to a designated directory. A safe layout keeps the application tree read-only and gives write permission to a purpose-built location such as uploads, cache, or generated.
Separate content from code
- Keep deployment-managed source, configuration, templates, and scripts owned by
rootor the deployment account. - Give the web server read and traversal access to those protected paths.
- Create a separate directory for user uploads or generated output.
- Do not place executable scripts or configuration files in a directory that must be writable by request-handling workers.
- Document which process writes the directory and remove write access when the feature is retired.
Example layout
/srv/my-site/html/ # root-owned, read-only to the server
/srv/my-site/html/uploads/ # narrowly scoped application data
/srv/my-site/html/cache/ # generated data, if required
Set the owner, group, and mode of each writable directory to match the application’s documented requirement. The key security property is scope: the worker may write only where it must, not to the complete web root. Apache’s guidance recognizes selected writable directories for publishing platforms and CMS installations while keeping configuration and content protected. Red Hat’s security guidance likewise recommends retaining root write permission for script or CGI directories unless an application requirement says otherwise.
SELinux: Unix permissions are not the whole decision
On SELinux-enabled systems, access is allowed only when both the Unix permission check and the SELinux policy permit it. Fedora documents the httpd_sys_content_t context for content Nginx must read, and Red Hat documents the same context as the normal type for content under /var/www.
Recommended Free Tools
Rank #4
Inspect labels alongside owner and mode:
ls -lZ /srv/my-site/html
ls -Zd /srv/my-site/html
A tree can be owned by root:nginx with mode 750 and still return 403 if its labels do not describe web-readable content. Conversely, changing labels does not compensate for missing Unix read or traversal permission. Treat the two controls independently: verify the configured service account and mode bits, then verify that the document root and its files have the SELinux type expected by the distribution’s web-server policy.
Apply a change without losing the current state
- Back up the metadata. Save the current owner, group, mode, and (where applicable) SELinux labels before making a recursive change. A recursive
chownorchmodaffects every descendant, including files that may intentionally differ. - Confirm the target path. Resolve the virtual host’s actual document root. Do not run a recursive command against
/var/wwwmerely because one site happens to live below it. - Confirm the service identity. Use the account and group from the active Apache or Nginx configuration, not a remembered default.
- Set ownership. Assign the deployment owner and service group, for example
root:nginxfor a static Nginx tree. - Set directory and file modes separately. Use
find -type dfor directory modes andfind -type ffor file modes. This avoids accidentally giving ordinary files directory execute bits or leaving directories without traversal. - Handle writable exceptions. Apply a deliberately different policy only to the upload, cache, or generated-content directories that need it.
- Check labels. On SELinux systems, inspect
ls -Zoutput and correct the context using the distribution’s documented policy-management procedure. - Test locally and externally. Request a known static file, test an index document, and exercise any upload path separately. A successful home page does not prove that every nested asset or write operation has the intended permissions.
Diagnose a 403 after changing permissions
A 403 means the request reached a policy or filesystem barrier; it does not by itself identify which one. Work from the service account outward.
1. The wrong user or group was selected
Recheck the active virtual host or server block and the worker-process identity. If the tree is root:nginx but Apache workers run as www-data, the group-read and group-execute bits apply to the wrong account. Correct the group or use the service’s actual group, then retest.
2. A parent directory blocks traversal
Use namei -l on the exact failing URL’s filesystem path. Look for a parent directory without execute permission for the owner, group, or applicable class. Add only the required traverse permission; do not broadly open unrelated directories.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
3. The file is not readable
Check the file’s owner, group, and mode. A directory can be traversable while a file remains unreadable. Compare a working asset with the failing one to find an accidental mode or ownership difference.
Best Value
4. SELinux denies the request
Inspect ls -Z output for the document root and the failing file. If the labels do not match the web-readable context expected by the distribution, Unix permission changes alone will not fix the response.
5. The server configuration points elsewhere
Verify that the URL maps to the directory you changed. Virtual hosts, aliases, and server blocks can send a request to a different path, making a correct permission change appear ineffective.
6. A directory index or application rule is involved
If a directory URL fails while a direct file URL works, inspect the server’s index and access rules. Do not make the directory writable as a workaround; ownership does not solve a configuration rule that intentionally denies listing or access.
Free tools Windows power users keep installed
One-click scans. No signup required.
Common ownership mistakes
| Mistake | Why it is a problem | Better approach |
|---|---|---|
Making the entire tree www-data:www-data or nginx:nginx |
The request-handling process can modify code, configuration, and static content if its account is compromised. | Keep ownership with root or deployment, and grant the service read/traverse access. |
Using chmod -R 755 on everything |
Every regular file receives execute permission, and all local users may read the content. | Set directory and file modes separately; use 755/644 only when world-read access is required. |
Using chmod -R 644 |
Directories need execute permission for traversal; files may become unreachable even when readable. | Apply directory and file modes with separate find commands. |
| Fixing only the leaf file | A parent directory without execute permission still blocks the request. | Check every path component from the filesystem root to the file. |
| Ignoring SELinux labels | Mandatory access control can deny a request after Unix checks succeed. | Inspect and maintain the web-readable SELinux context as well as owner and mode. |
| Granting write access to source or CGI directories | Uploaded or generated data can become a path to altering executable code. | Use a separate, narrowly scoped writable directory and retain root write control elsewhere. |
Choosing between 750/640 and 755/644
| Pattern | Owner | Service access | Use when | Trade-off |
|---|---|---|---|---|
root:service-group, directories 750, files 640 |
Root or deployment account can change content. | Service group can traverse directories and read files. | The web server is the only additional reader and group access can be configured correctly. | Requires the service to use the selected group; other local users cannot read the tree. |
root:service-group, directories 755, files 644 |
Root or deployment account retains write access. | Service and all local users can read; everyone can traverse directories. | An intermediary process or anonymous local readers genuinely require world-read access. | Exposes content more broadly and gives regular files execute bits only if you choose an incorrect recursive mode; apply 755 to directories and 644 to files separately. |
Neither pattern grants the web server write access to the static tree. If an application needs writes, model that as an exception for a specific directory rather than changing the baseline.
Quick Recap
Operational checklist
- Identify the actual Apache, Nginx, or application service account and group.
- Confirm the exact document-root path used by the active virtual host or server block.
- Keep static content owned by root or a deployment account.
- Grant the service group read permission on files and execute (traverse) permission on every required directory.
- Use separate
findcommands for directory and file modes. - Choose 755/644 only when world-read access is an intentional requirement.
- Isolate uploads, caches, and generated files in narrowly scoped writable directories.
- Keep scripts, configuration, templates, and CGI code protected from worker writes.
- Inspect SELinux labels with
ls -Zon systems enforcing SELinux. - After changes, request a known file, a nested asset, and each application write path, then investigate any 403 by checking identity, traversal, file readability, labels, and server mapping in that order.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




