sed -i and the backup you forgot

Two sites, one VPS, one nginx.conf. You're consolidating: blog.oldsite.com is moving off its own droplet and onto the box that already runs oldsite.com, and you want the config renamed to match before you rebrand the domain next week. One command, right?
sed -i 's/oldsite.com/newsite.com/g' nginx.conf
It runs instantly and prints nothing, which feels like success!
You reload nginx.
Nothing feels like success right up until it doesn't.
$ systemctl reload nginx
Job for nginx.service failed because the control process exited with error code.
nginx -t tells you why:
nginx: [emerg] cannot load certificate "/etc/letsencrypt/live/newsite.com/fullchain.pem": BIO_new_file() failed (SSL: error:02001002:system library:fopen:No such file or directory)
Here's what actually happened. Your regex didn't just touch the two server_name lines you meant to change, the ones with oldsite.com and blog.oldsite.com in them. It touched every occurrence of the string oldsite.com, anywhere in the file, including the ssl_certificate and ssl_certificate_key paths:
ssl_certificate /etc/letsencrypt/live/oldsite.com/fullchain.pem;
became
ssl_certificate /etc/letsencrypt/live/newsite.com/fullchain.pem;
sed doesn't know the difference between a hostname in a server_name directive and a hostname baked into a filesystem path. It has no concept of nginx.conf as a config file with meaning, only as a stream of characters to match against. You renamed the domain in your config, but Certbot never renamed the actual directory on disk, so now nginx is pointed at a certificate that doesn't exist. Two working sites are down over a rename that should have taken thirty seconds.
And here's the part that turns "annoying" into "bad night": you ran sed -i with no backup suffix.
Not sed -i.bak, not sed -i.orig, just -i.
On Linux, that's GNU sed's in-place mode with no backup at all. The original file is gone the moment the command returns. You don't have a copy to diff against, you don't remember every line the global match touched, and you're now reconstructing a working nginx.conf from memory at whatever hour this is happening.
This is the exact shape of the thread that resurfaces on LowEndSpirit every few months: someone ran a one-line sed against a live config, it matched more than they expected, and the backup they meant to take never happened because the command felt too small to need one. It's never the complicated multi-line sed script that does this. It's always the quick one-liner you were sure was safe.
The fix costs one extra flag. sed -i.bak writes the modified file in place and leaves the untouched original sitting right next to it:
$ sed -i.bak 's/oldsite.com/newsite.com/g' nginx.conf
$ ls nginx.conf*
nginx.conf nginx.conf.bak
If the replace goes wrong, you're one cp away from a working config again:
cp nginx.conf.bak nginx.conf
That's it. That's the whole insurance policy, and it costs you five characters.
Better still, don't run -i blind in the first place. Drop the flag and pipe straight into diff to see exactly what would change before you commit to it:
$ sed 's/oldsite.com/newsite.com/g' nginx.conf | diff nginx.conf -
3c3
< server_name oldsite.com www.oldsite.com;
---
> server_name newsite.com www.newsite.com;
5,6c5,6
< ssl_certificate /etc/letsencrypt/live/oldsite.com/fullchain.pem;
< ssl_certificate_key /etc/letsencrypt/live/oldsite.com/privkey.pem;
---
> ssl_certificate /etc/letsencrypt/live/newsite.com/fullchain.pem;
> ssl_certificate_key /etc/letsencrypt/live/newsite.com/privkey.pem;
Right there in the diff output, before you've touched anything, you can see the certificate lines are about to get rewritten to paths that don't exist. That's the moment to stop and narrow the regex, maybe anchor it to server_name specifically instead of matching the domain everywhere it appears, rather than the moment you find out from a failed nginx -t at 1 am.
Neither habit takes longer than the reckless version. -i.bak is five extra characters.
The dry-run pipe is one extra pipe. The only thing either one costs you is the two seconds it takes to type them, and that's cheaper than every version of this story that ends with, "and then I remembered I hadn't backed up nginx.conf since I set the server up."
“Technology is best when it brings people together.” – Matt Mullenweg



