Hardware FixRecommendedDevice not working? Your driver may be the problemCheck updates for common hardware issues.Fix DriversOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsSlow PC?RecommendedPC slow today? Run a repair scan before it gets worseResolve common Windows issues and optimize system performance.Scan Now×
Skip to content
World desk10 min

Best Way to Set File Ownership for a Web Root on Linux (Apache and Nginx)

Keep a Linux web root owned by root or a deployment account, not the web server. This guide shows how to set service-group permissions, isolate uploads, account for directory traversal and SELinux, and fix 403 errors.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  1. 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.
  2. Inspect the service configuration. Apache uses User and Group directives; Nginx uses a user directive. The effective setting can be in an included configuration file rather than the main file.
  3. 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.
  4. 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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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 root or 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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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

  1. Back up the metadata. Save the current owner, group, mode, and (where applicable) SELinux labels before making a recursive change. A recursive chown or chmod affects every descendant, including files that may intentionally differ.
  2. Confirm the target path. Resolve the virtual host’s actual document root. Do not run a recursive command against /var/www merely because one site happens to live below it.
  3. Confirm the service identity. Use the account and group from the active Apache or Nginx configuration, not a remembered default.
  4. Set ownership. Assign the deployment owner and service group, for example root:nginx for a static Nginx tree.
  5. Set directory and file modes separately. Use find -type d for directory modes and find -type f for file modes. This avoids accidentally giving ordinary files directory execute bits or leaving directories without traversal.
  6. Handle writable exceptions. Apply a deliberately different policy only to the upload, cache, or generated-content directories that need it.
  7. Check labels. On SELinux systems, inspect ls -Z output and correct the context using the distribution’s documented policy-management procedure.
  8. 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.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

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 find commands 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 -Z on 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.

Leave a Reply

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

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.