cmc/cleberg.net

My personal web garden & blog.

clone: git clone https://gitbay.org/cmc/cleberg.net.git

main: content/blog/2022-12-07-nginx-wildcard-redirect.org · raw

  1#+date:        [2022-12-07 Wed 00:00:00]
  2#+title:       Nginx Wildcard Redirects
  3#+description: Using regex-based redirects in Nginx for subdomain and path routing.
  4#+slug:        nginx-wildcard-redirect
  5#+filetags:    :web:
  6
  7* Problem
  8
  9I recently migrated domains and replaced the old webpage with a simple info page
 10with instructions to users on how to edit their bookmarks and URLs to get to the
 11page they were seeking.
 12
 13This was not ideal as it left the work up to the user and may have caused
 14friction for users who accessed my RSS (Really Simple Syndication) feed.
 15
 16* Solution
 17
 18Instead, I finally found a solution that allows me to redirect both subdomains
 19AND trailing content. For example, both of these URLs now redirect properly
 20using the logic I'll explain below:
 21
 22#+begin_src txt
 23# Example 1 - Simple base domain redirect with trailing content
 24https://domain1.com/blog/alpine-linux/ -> https://domain2.com/blog/alpine-linux/
 25
 26# Example 2 - Complex redirect with both a subdomain and trailing content
 27https://libreddit.domain1.com/r/history/comments/7z8cbg/new_discovery_mode_turns_video_game_assassins/
 28->
 29https://libreddit.domain2.com/r/history/comments/7z8cbg/new_discovery_mode_turns_video_game_assassins/
 30#+end_src
 31
 32Go ahead, try the URLs (uniform resource locators) if you want to test them.
 33
 34** Nginx Config
 35
 36To make this possible. I needed to configure a proper redirect scheme in my
 37Nginx configuration.
 38
 39#+begin_src sh
 40doas nano /etc/nginx/http.d/domain1.conf
 41#+end_src
 42
 43Within this file, I had one block configured to redirect HTTP requests to HTTPS
 44for the base domain and all subdomains.
 45
 46#+begin_src conf
 47server {
 48        listen [::]:80;
 49        listen 80;
 50        server_name domain1.com *.domain1.com;
 51
 52        if ($host = domain1.com) {
 53                return 301 https://$host$request_uri;
 54        }
 55
 56        if ($host = *.domain1.com) {
 57                return 301 https://$host$request_uri;
 58        }
 59
 60        return 404;
 61}
 62#+end_src
 63
 64For the base domain, I have another =server= block dedicated to redirecting all
 65base domain requests. You can see that the =rewrite= line is instructing Nginx
 66to gather all trailing content and append it to the new =domain2.com= URL.
 67
 68#+begin_src conf
 69server {
 70        listen [::]:443 ssl http2;
 71        listen 443 ssl http2;
 72
 73        server_name domain1.com;
 74
 75        rewrite ^/(.*)$ https://domain2.com/$1 permanent;
 76
 77        ssl_certificate     /etc/letsencrypt/live/domain1.com/fullchain.pem;
 78        ssl_certificate_key /etc/letsencrypt/live/domain1.com/privkey.pem;
 79}
 80#+end_src
 81
 82Finally, the tricky part is figuring out how to tell Nginx to redirect while
 83keeping both a subdomain and trailing content intact. I found that the easiest
 84way to do this is to give it a =server= block of its own.
 85
 86Within this block, we need to do some regex on the =server_name= line before we
 87can rewrite anything. This creates a variable called =subdomain=.
 88
 89Once the server gets to the =rewrite= line, it pulls the =subdomain= variable
 90from above and uses it on the new =domain2.com= domain before appending the
 91trailing content (=$request_uri=).
 92
 93#+begin_src conf
 94server {
 95        listen [::]:443 ssl http2;
 96        listen 443 ssl http2;
 97
 98        server_name ~^(?<subdomain>\w+)\.domain1\.com$;
 99
100        rewrite ^ https://$subdomain.domain2.com$request_uri permanent;
101
102        ssl_certificate     /etc/letsencrypt/live/domain1.com/fullchain.pem;
103        ssl_certificate_key /etc/letsencrypt/live/domain1.com/privkey.pem;
104}
105#+end_src
106
107That's all there is to it. With this, I simply restarted Nginx and watched the
108redirections work in-action.
109
110#+begin_src sh
111doas rc-service nginx restart
112#+end_src
113
114Looking back on it, I wish I had done this sooner. Who knows how many people
115went looking for my sites or bookmarks and gave up when they saw the redirect
116instructions page.
117
118Oh well, it's done now. Live and learn.