Halloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix NowHalloween DealsAmazon USOctober picks are moving - compare before checkoutAmazon US: current deals, useful picks and tech finds.See Picks×
FREEDOM251

Freedom251 › Blog › 403 errors

How to Move an Nginx Web Root to a New Location (Safely)

By Freedom251 Team · · 10 min read

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

To move an Nginx web root, copy the site files to the new directory, change the active server block’s root directive, check any location-specific overrides, test the configuration, and reload Nginx. Keep the old directory until you have verified the home page, a nested asset, and an application route.

A typical migration changes root /var/www/html; to something such as root /srv/my-site/html;. Nginx then maps each request URI beneath that filesystem directory. A 403 after the move usually means a parent directory cannot be traversed, a file is not readable by the worker account, a symlink target is inaccessible, or mandatory access control is blocking access.

As an Amazon Associate I earn from qualifying purchases.

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

What changes when you move the root?

Nginx’s root directive defines the filesystem base for a server or location. For a request such as /images/logo.svg, Nginx appends that URI to the configured root. With root /srv/my-site/html;, the expected file is therefore /srv/my-site/html/images/logo.svg.

The move affects only the path Nginx uses to find content. Your DNS records, domain name, listening port, TLS configuration, index directive, and application handlers can remain unchanged unless your site’s design requires otherwise. The important exception is a nested location block: a more-specific location can define its own root or alias and bypass the server-level setting.

Before you start

  • Have shell access with permission to read the current site and write the destination.
  • Know which Nginx server block answers the hostname you are testing.
  • Choose a destination on a mounted filesystem that will be available after reboot.
  • Keep enough free space for a complete copy, including hidden files and symlink targets that live inside the site.
  • Plan a short verification window. A reload applies the new configuration without intentionally stopping the running service, but a bad configuration must be corrected before it can be loaded.

Do not delete or rename the old root first. Keeping it intact provides an immediate rollback path and lets you compare a failing request with the previous layout.

1. Find the active configuration

Editing the wrong file is one of the most common causes of a move appearing to have no effect. Linux packages often use an /etc/nginx hierarchy, while source builds and other operating systems may use a different configuration path.

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.

Ubuntu and Debian-style layouts

On Ubuntu, the default site is commonly enabled through /etc/nginx/sites-enabled/default, with the editable file in /etc/nginx/sites-available/. The enabled file may be a symlink. Inspect both the link and the server block before changing anything:

ls -l /etc/nginx/sites-enabled/
sudo sed -n '1,220p' /etc/nginx/sites-enabled/default

If your domain uses a separate file, search the enabled configuration for the hostname and current root:

sudo grep -RInE 'server_name|root[[:space:]]' /etc/nginx

Other installations

Ask the installed binary which configure arguments were compiled into it. The output includes the compiled configuration path:

nginx -V 2>&1 | awk -F: '/configure arguments/ {print $2}'

Use the reported --conf-path and any included files to trace the server block that is actually loaded. The file you edit must be included by the main configuration; an unused file in another directory will not change live traffic.

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

2. Create the destination and copy the site

The destination can be anywhere Nginx can access. Ubuntu’s server documentation demonstrates /srv/my-site/html as a valid web-root location:

sudo mkdir -p /srv/my-site/html

Copy the existing document-root contents, including dotfiles. The trailing /. form below means “copy the contents” rather than creating an extra html directory inside the destination:

sudo cp -a /var/www/html/. /srv/my-site/html/

The archive option preserves ordinary ownership, modes, timestamps, and symlinks. For a production site, also account for extended attributes and any deployment metadata your system uses. If a symlink points outside the old root, confirm that its target remains present and accessible from the new arrangement; copying the link does not copy its external target.

After copying, compare the trees and check for hidden files:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
sudo find /var/www/html -maxdepth 2 -printf '%M %u:%g %p -> %ln' | sort | less
sudo find /srv/my-site/html -maxdepth 2 -printf '%M %u:%g %p -> %ln' | sort | less

The exact comparison command is optional; the essential check is that the destination contains the same entry point, asset directories, upload directories, and application files required by the site.

3. Make the new path traversable and readable

Nginx needs execute (traverse) permission on every parent directory and read permission on files it serves. The worker account also needs permission to follow symlinks and read the target directories. A directory can look readable while still producing 403 because one parent directory denies traversal.

Ubuntu’s basic example uses a recursive 755 mode for the sample web root:

sudo chmod -R 755 /srv/my-site/html

Use that only when it matches your security model. Recursive 755 grants read and traverse access broadly and may be inappropriate for private uploads, configuration files, or application data. A safer deployment commonly separates public files from secrets, assigns ownership deliberately, and grants write access only to the process that needs it. Do not place database passwords or private keys under a directory intended for direct HTTP serving.

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

Inspect the complete path when diagnosing access:

namei -l /srv/my-site/html/index.html

This shows permissions on each parent component. Check the Nginx worker account used by your distribution and make sure it can read the requested file. If your system enforces SELinux, AppArmor, or another mandatory-access-control policy, the policy may need to be updated for the new path. There is no single command that applies to every distribution; consult that operating system’s policy tooling and audit logs rather than disabling the control.

4. Change the server block

Open the active server-block file and replace the old root line. Keep the existing index directive and application handlers unless you have a separate reason to change them.

server {
    listen 80;
    server_name example.com www.example.com;
    root /srv/my-site/html;
    index index.html index.htm;

    location / {
        try_files $uri $uri/ =404;
    }
}

The semicolon is required. Avoid changing unrelated directives during the migration; limiting the edit makes validation and rollback easier.

How the example resolves requests

Request Filesystem lookup with the example root Result with try_files
/ /srv/my-site/html/, then the configured index file Serves the index if present; otherwise follows the location’s normal directory handling
/about.html /srv/my-site/html/about.html Serves the file when it exists
/assets/app.css /srv/my-site/html/assets/app.css Serves the stylesheet when it exists
/missing /srv/my-site/html/missing Returns 404 when neither a file nor directory exists

5. Audit location, alias, and fallback rules

Changing the server-level root is not enough if a more-specific location supplies another path. Review every location block, especially those handling static assets, uploads, PHP or other application handlers, and single-page-application fallbacks.

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

Specific locations can override the root

server {
    root /srv/my-site/html;

    location / {
        try_files $uri $uri/ =404;
    }

    location /uploads/ {
        root /var/lib/my-site;
    }
}

In this example, a request for /uploads/photo.jpg is resolved under the location’s root rather than the server-level root. Decide whether that separate storage path is intentional. If it is not, remove or update the override.

try_files uses the current root or alias

try_files checks candidate paths using the root or alias in effect for that location. A fallback such as try_files $uri $uri/ /index.html; must point to an index file that exists in the new layout. If the fallback still names a file that was not copied, application routes will fail even though the home page works.

When alias is the right tool

root appends the complete request URI to its configured path. alias replaces the matching location prefix with the alias path. Use alias when the URI prefix should not appear in the filesystem path.

Directive URI-to-filesystem behavior Typical use Details to recheck
root /srv/my-site/html; Appends the entire URI Whole-site document root Parent permissions, index handling, and nested location overrides
location /images/ { alias /data/site-images/; } Replaces the matched /images/ prefix Mapping a URL prefix to a differently named directory Trailing slashes, exact location matching, and whether the alias path is a file or directory

Trailing-slash details matter with directory aliases. Test both the directory URL and a file beneath it, and keep the slash conventions consistent between the location and alias declarations. Do not replace a straightforward site-wide root with multiple aliases unless the URI-to-filesystem mapping genuinely requires it.

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

6. Validate before reloading

Always test the complete configuration first:

sudo nginx -t

A successful test reports that the syntax is valid and the configuration test succeeded. If it fails, read the filename and line number in the error, correct that file, and run the test again. Do not reload a configuration that has not passed.

Once the test succeeds, reload Nginx:

sudo systemctl reload nginx

Use the equivalent service-manager command on systems that do not use systemd. Reloading applies the new workers while avoiding an intentional full stop. It does not copy files, repair permissions, or change a server block that is not included.

7. Verify real requests

Test more than the home page. A root move can leave one location or one asset directory pointing at the old tree.

  1. Request the site root and confirm the expected index document is returned.
  2. Request a representative nested static file, such as a stylesheet, image, or JavaScript bundle.
  3. Request an application route that depends on try_files or another fallback.
  4. Check a path served by every special location, including uploads or API handlers.
  5. Confirm the response status, content, and redirects from the intended server block and hostname.

For a local check, send the correct Host header when several sites share an address:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -I -H 'Host: example.com' http://127.0.0.1/
curl -I -H 'Host: example.com' http://127.0.0.1/assets/app.css

Use HTTPS and the public hostname when TLS, redirects, or a reverse proxy are part of the path. A successful response from localhost alone does not prove that the public virtual host selected the same server block.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Why Nginx returns 403 after the move

Parent directory traversal is denied

Every directory in /srv/my-site/html must be traversable by the Nginx worker account. Use namei -l on the exact file and correct the restrictive parent rather than granting broad permissions to the entire filesystem.

The file or symlink target is unreadable

Check the mode and owner of the requested file. A copied symlink can point to an old location, a path outside the new root, or a target that the worker account cannot read. Confirm the target exists and test its permissions separately.

A mandatory-access-control rule rejects the new path

SELinux, AppArmor, or another policy can deny access even when Unix modes look correct. Inspect the relevant audit or denial logs and assign an approved label or profile rule for the new location. Do not assume that changing mode bits resolves a policy denial.

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

A directory has no index and listing is disabled

If a request ends at a directory and no configured index file exists, Nginx may reject it rather than list contents. Confirm that the destination contains the expected index file and that the index directive still names it.

When the old content is still served

The request selected another server block

Nginx chooses a server block using the listen address, port, and hostname. A test using an unexpected hostname can therefore reach a different root. Check server_name values and send the intended Host header while testing.

A nested location still points to the old path

Search for every root and alias, not just the first one you see. A more-specific location wins for matching requests and can continue serving a subset of files from the old directory.

A deployment symlink or mount still targets the old tree

Some deployments expose a stable path through a symlink or mounted release directory. Inspect the link target and mount arrangement. Update the deployment pointer deliberately, then retest the representative URLs.

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.

The configuration was edited but not loaded

Run sudo nginx -t, reload successfully, and check the service status. If the reload failed, the running workers may still be using the prior configuration. A file outside the compiled or included configuration path has no effect.

Reading logs when a request fails

Nginx’s access and error logs are the first diagnostic tools when behavior is unexpected. The access log tells you which URI and status code were received; the error log often identifies permission failures, missing files, redirect loops, or an upstream problem.

sudo tail -f /var/log/nginx/access.log /var/log/nginx/error.log

Log locations can be customized in the configuration, so use the paths declared by your active access_log and error_log directives. Reproduce one failing request while watching the logs, then correlate its timestamp and URI with the filesystem path you expect Nginx to use.

Rollback plan

  1. Keep /var/www/html or the original root untouched until verification is complete.
  2. Restore the previous root line in the active server block.
  3. Run sudo nginx -t to verify the reverted configuration.
  4. Run sudo systemctl reload nginx.
  5. Confirm the original representative URLs work, then investigate the destination copy, permissions, location overrides, or policy rules before attempting the migration again.

Once the new root has served all required traffic successfully and you have a separate backup, remove the old directory only according to your retention and rollback policy. Deleting it immediately removes your simplest recovery option.

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

Migration checklist

  • Identify the compiled and included Nginx configuration path.
  • Identify the server block for the hostname being tested.
  • Create the destination directory.
  • Copy all site content, preserving required ownership, modes, symlinks, and extended attributes.
  • Check parent-directory traversal and file readability for the Nginx worker account.
  • Change the server-level root directive.
  • Audit nested location blocks, alias directives, and try_files fallbacks.
  • Run sudo nginx -t.
  • Reload Nginx only after a successful test.
  • Test the root URL, a nested asset, an application route, and every special location.
  • Use access and error logs for any 403, 404, or unexpected content.
  • Retain the old root until verification and rollback needs have passed.

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.

403 errorsLinuxNGINXserver administrationweb server

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.

Recommended PC Tool
Recommended PC Tool
Windows Errors? Fix Them Before They SpreadFree repair scan
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.