A safe checklist for deploying a static site on a shared server
Still Brewing UAPublished: Updated:
Adding a site to an empty server is easy. Adding one to a server that already runs other people’s working projects is a different job: the goal is not only that the new site works, but that nothing else changed. This is the checklist I follow.
Preflight before touching anything
Start read-only. Confirm the repository is on the expected branch, the working tree is clean, and the commit you are about to ship is the one already pushed. If any of that is off, stop and resolve it before the server is involved at all.
Then look at the server without changing it: operating system, uptime, free memory and disk, failed units, running services, listening ports, and whether the configuration currently parses.
systemctl --failed
sudo ss -lntp
sudo nginx -t
sudo ls -l /etc/nginx/sites-enabled/Record a baseline you can compare against
Before any change, capture what "working" looks like for everything already on the server. Afterwards, "I did not break anything" becomes a comparison instead of an opinion.
- a checksum of every configuration file you must not modify
- the process id of each running service
- the list of listening sockets
- the status code, redirect target and content type of each existing site
- the certificates that exist and when they expire
Process ids are the most useful of these. If a service was restarted when it should not have been, the id changes and you will see it immediately.
A separate virtual host, in a new file
The new site gets its own configuration file and its own symlink. Existing files are not edited. If the new site has to be removed, the change is one symlink and a reload, and nothing else was ever touched.
Give the new host a hostname of its own and never add the server’s bare IP address to it. The IP usually already belongs to whichever site was there first, and claiming it twice creates a conflict that resolves in load order rather than by intent.
Do not add `default_server`
The default server answers requests whose Host header matches nothing. On a shared server that role already belongs to an existing site, whether it was set deliberately or simply fell to whichever block loads first.
Adding `default_server` to a new virtual host silently takes that traffic away from the site that had it. Nothing errors, the configuration test passes, and the change only shows up as somebody else’s unexplained traffic drop. Leave it alone.
Back up before editing
Before changing a configuration file you own, copy it aside with a timestamp and verify the copy matches. It takes a moment and turns a bad edit into a one-command recovery.
sudo cp -p /etc/nginx/sites-available/example \
/etc/nginx/sites-available/example.backup-$(date -u +%Y%m%d-%H%M%SZ)Test, then reload — never restart
Always validate the configuration before applying it. A syntax error caught by the test is harmless; the same error applied to a running server takes every site on it down.
sudo nginx -t && sudo systemctl reload nginxReload replaces the worker processes while the master keeps running and connections are finished cleanly. Restart stops the server and starts it again, which is a visible outage for every site it hosts. Check afterwards that the master process id is unchanged — that is the proof it was a reload.
And if you only changed content, not configuration, do not reload at all. There is nothing to re-read.
A separate certificate for a separate hostname
Issue a new certificate for the new hostname instead of extending an existing one. Extending rewrites a certificate other sites depend on; a separate one can be renewed, replaced or removed without touching anything else.
Do a staging dry run first, confirm it succeeds, and only then request the real certificate. Afterwards, check that the existing certificate is untouched — comparing its serial number against the baseline settles it.
Avoid the standalone method on a shared server: it needs port 80 to itself and would stop the running web server to get it. Use the web server plugin, which validates through the server that is already running.
Verify the new site
Check both protocols and the failure cases, not just the happy path.
- HTTP redirects to HTTPS on the same path
- the certificate matches the hostname and verifies cleanly
- the expected pages return 200 with sensible content types
- following redirects ends somewhere, with no loop
- an address that does not exist returns a real 404
- no URL redirects to a different site on the same server
Verify the projects that were already there
This is the step that is easiest to skip and most valuable to keep. Repeat every baseline measurement and compare.
- configuration checksums unchanged
- service process ids unchanged
- no new failed units
- listening sockets unchanged
- existing sites returning the same status codes and redirects
- existing certificates unchanged, by serial number
Know the rollback before you need it
Write the exact rollback command down as part of the plan. For a configuration change it is restoring the backup, testing and reloading. For a content change it is pointing the symlink back at the previous release.
Rollback should never delete a certificate or a release directory. Undo the smallest thing that restores service, and leave the investigation for afterwards.
Do not touch what is not yours
The most useful rule on a shared server is the least technical one: change only what the task requires. Not the firewall, not DNS, not another project’s configuration, not the packages installed, not a certificate you did not create.
When something unexpected appears — a path that already exists, a service you did not expect, a configuration that differs from the last audit — stop and report it instead of adapting around it. An unexplained difference is information, and overwriting it destroys the only copy.
Related notes
- Deploying a React and Vite site to Nginx with versioned releasesHow to ship a static React and Vite site to an Nginx server using versioned release directories, checksum verification and an atomic symlink switch.Read the note
- Bilingual SEO for a React and Vite websiteHow to give a React and Vite site two properly indexable language versions with prerendered HTML, per-language metadata, canonical URLs and mutual hreflang.Read the note
Want something like this built?
These notes come from work I have shipped. If you need the same done properly, tell me what you have in mind.