WordPress tag soup cleanup with nginx 301 redirects

WordPress tag cleanup with nginx 301s
Todays solution is: cleaning WordPress tag soup at scale.
Over the years this blog collected something like 170 tags. Half of them were one-off typos or “computer-name-changing-constantly” style junk. Nice for me in 2013. Terrible for SEO in 2026. Googlebot kept discovering thin tag archives that competed with real posts.
In this post i will show you how i collapsed that mess into about 25 hub tags and put the old URLs on permanent nginx 301 redirects. WordPress alone is too slow and too easy to break for hundreds of single-post tags.
Prerequisites:
- WordPress with a pile of useless tags (check Posts -> Tags).
- Nginx in front (Apache RewriteMap is another world).
- SSH and a backup. Seriously, backup first.
1. Decide hub tags, delete the noise
I kept hubs that match how people actually land here: debian, nginx, zfs, wordpress, varnish, openstack, proxmox, and friends. One-off tags got merged into those hubs or removed.
In wp-admin you can merge by hand for a few tags. At ~170 i scripted it with WP-CLI: reassign posts to the hub, then delete the empty tag. Whatever you use, end state on ispire.me is roughly 25 tags, not 170.
Dont noindex every tag archive blindly if you still want hubs to rank. Kill thin tags, keep fat ones.
2. Why nginx and not only Yoast / Redirection
Plugin redirect tables are fine for ten URLs. For hundreds of /tag/old-thing/ >/tag/hub/ pairs i prefer nginx. It answers before PHP boots. Less load, less “oops plugin deactivated”.
I dropped a snippet here:
/etc/nginx/snippets/ispire-tag-redirects.conf
and included it inside the server block for ispire.me:
include /etc/nginx/snippets/ispire-tag-redirects.conf;
Each old tag gets exact locations (with and without trailing slash):
location = /tag/apache2/ { return 301 /tag/debian/; }
location = /tag/apache2 { return 301 /tag/debian/; }
location = /tag/copy-zfs/ { return 301 /tag/zfs/; }
location = /tag/copy-zfs { return 301 /tag/zfs/; }On this host that file is ~320 return 301 lines. Ugly file. Fast redirects. I can live with ugly.
3. Generate, reload, spot check
I generate the snippet from a mapping list (hub <- old slugs), write the file, then:
nginx -t && systemctl reload nginx
Spot check a few losers:
curl -I https://ispire.me/tag/apache2/ # expect HTTP/1.1 301 and Location: .../tag/debian/
Also open a hub like /tag/zfs/ and make sure it still renders as a normal tag archive.
4. SEO angle in one sentence
Thin tag URLs stop wasting crawl budget, hubs keep topical juice, old backlinks to dead tags dont 404. Pair this with sane internal links from your real howtos (ZFS, Nginx, PHP-FPM) and you stop looking like a tag farm from 2012.
Related reading on this site while you are in cleanup mood: Bad value category tag for attribute rel and WordPress object cache with Redis on PHP 8 if MySQL is still sweating.
That should do it. Less tags, more hubs, nginx does the 301 work, WordPress stays boring.