{"id":2984,"date":"2020-02-09T12:00:48","date_gmt":"2020-02-09T12:00:48","guid":{"rendered":"http:\/\/www.payneful.co.uk\/blogsplosion\/?p=2984"},"modified":"2020-01-26T16:41:13","modified_gmt":"2020-01-26T16:41:13","slug":"the-payneful-portfolio-redirecting-domain-names-to-mask-a-different-domain-path-using-nginx","status":"publish","type":"post","link":"https:\/\/www.payneful.co.uk\/blogsplosion\/2020\/02\/09\/the-payneful-portfolio-redirecting-domain-names-to-mask-a-different-domain-path-using-nginx\/","title":{"rendered":"The PAYNEful Portfolio &#8211; Redirecting Domain Names to Mask a Different Domain Path Using NGINX"},"content":{"rendered":"<p><strong>Note:<\/strong> I wrote this post probably about three or four years ago, I&#8217;ve been sat on it for a while because a) I don&#8217;t know if it&#8217;s all that interesting and b) it might reflect poorly on my server admin skills. In the interest of transparency (and because I&#8217;m committed to this one blog a week malarkey) it finally gets published today.<\/p>\n<hr \/>\n<p>Recently I have dabbling in some server fun, which means I&#8217;ve been engaging in activity that would make proper server admins cry with absolute rage.<\/p>\n<p>Let&#8217;s just say I have a website that makes use of RESTful URIs. We then have a system where we want to add a domain name but point it at a specific existing URI. For example&#8230;<\/p>\n<pre>http:\/\/www.main-website.com\/restful\/uri\/long-string-of-parameters<\/pre>\n<p>&#8230;becomes the following&#8230;<\/p>\n<pre>http:\/\/new-domain.com\/long-string-of-parameters<\/pre>\n<p>I could foresee a potential headache, as in my limited experience of tying domains to Linux servers you normally have to add stuff to sites-available and link it in sites-enabled. That could become an unscalable nightmare since we are looking at adding domains on a regular basis just to mask existing URLs!<\/p>\n<p>Poking around NGINX and the sites-available folder, I found a file called &#8220;catch-all&#8221; that contained the following&#8230;<\/p>\n<pre>server {\r\n     return 404;\r\n}<\/pre>\n<p>Given that the only other files were for the main site&#8217;s config, it seemed obvious that this was a file to deal with &#8220;any other traffic&#8221;, which was interesting.<\/p>\n<p>In the NGINX config I also noted that there were several &#8220;include&#8221; statements like the following:<\/p>\n<pre>include config-folder\/domain-name-here.com\/directory\/*;<\/pre>\n<p>This include seemed to be saying &#8220;include any config values from files in this directory&#8221;.<\/p>\n<p>Putting this new information together, I wondered if I could pass in a config file with directives for the domains we were looking to add. If I could, this should be easy enough to automate as it would just be a case of generating a new .conf file every time we add a domain!<\/p>\n<p>First, I pointed a test domain that we wanted to add to the system at the remote server&#8217;s ip in the domain registrar panel. This caused it to generate the default NGINX 404 page when accessing that domain, which made sense.<\/p>\n<div id=\"attachment_107\" class=\"wp-caption aligncenter\" style=\"width: 356px\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-107 size-full\" title=\"NGINX 404\" src=\"http:\/\/www.payneful.co.uk\/blogsplosion\/wp-content\/uploads\/2017\/01\/NGINX.png\" alt=\"NGINX 404\" width=\"346\" height=\"129\" \/><div class=\"wp-caption-text\">Quoth the server, 404.<\/div><\/div>\n<p>In the catch-all config file I added the following line at the top (note this was <em>above<\/em> the server directive, not inside the curly braces with the 404!):<\/p>\n<pre>include \/path\/to\/directory\/where\/we\/will\/add\/redirects\/*;\r\nserver {\r\n     return 404;\r\n}<\/pre>\n<p>This would mean that for any other traffic than the main domain, the config would check that directory for config files, and then just output a 404 if it couldn&#8217;t find or match anything.<\/p>\n<p>Then, in a new file in the freshly-created &#8220;redirects&#8221;<sup class='footnote'><a href='https:\/\/www.payneful.co.uk\/blogsplosion\/2020\/02\/09\/the-payneful-portfolio-redirecting-domain-names-to-mask-a-different-domain-path-using-nginx\/#fn-2984-1' id='fnref-2984-1' onclick='return fdfootnote_show(2984)'>1<\/a><\/sup> directory I referenced in the catch-all .conf I added the following to a file:<\/p>\n<pre>server {\r\n     listen 80;\r\n     server_name new-domain.com;\r\n     location \/ {\r\n          proxy_pass http:\/\/www.main-website.com\/restful\/uri\/;\r\n     }\r\n}<\/pre>\n<p>Actually, I tell a lie &#8211; I originally just put a redirect to the main domain in there and, once I&#8217;d restarted NGINX, found that it worked! I only found <a title=\"A really useful article!\" href=\"https:\/\/www.digitalocean.com\/community\/tutorials\/understanding-nginx-http-proxying-load-balancing-buffering-and-caching\" target=\"_blank\" rel=\"noopener noreferrer\">proxy_pass was a thing after Googling how to &#8220;mask&#8221; a URL with NGINX<\/a>.<\/p>\n<p>Please note I originally wanted to place these redirect files in the secure NGINX directory but that threw up a small permissions issue that I will explain in a bit &#8211; instead, the folder is placed above the public root but in a location accessible by scripts (PHP, cli, etc.). Please do feel free to tell me how <span style=\"color: #ff0000;\">bad<\/span> an idea this is in the comments, and most importantly why! I need to learn.<\/p>\n<p>So I now had one domain masking another. Using PHP scripts I experimented using <a title=\"exec() in the PHP manual.\" href=\"http:\/\/php.net\/manual\/en\/function.exec.php\" target=\"_blank\" rel=\"noopener noreferrer\">exec()<\/a> to create and populate a file with the details outlined above, and it worked, albeit after reloading the NGINX config each time to pick up on the changes. This wasn&#8217;t a problem &#8211; the domain redirecting process didn&#8217;t have to be instantaneous and I could just set a cronjob to run every hour and reload the config<sup class='footnote'><a href='https:\/\/www.payneful.co.uk\/blogsplosion\/2020\/02\/09\/the-payneful-portfolio-redirecting-domain-names-to-mask-a-different-domain-path-using-nginx\/#fn-2984-2' id='fnref-2984-2' onclick='return fdfootnote_show(2984)'>2<\/a><\/sup>.<\/p>\n<p>To reload the NGINX config is a one-liner&#8230;<\/p>\n<pre>service nginx reload<\/pre>\n<p>&#8230;and doesn&#8217;t require NGINX to restart, so the website never has to disappear while everything reloads. I stuck it in a .sh file, gave it executable permissions (chmod +x) and tried running it. Surprise! It didn&#8217;t work.<\/p>\n<p>This is because you need to run it with &#8220;sudo&#8221; for elevated permissions. <em>Bugger<\/em>. This is pretty much the problem I was having earlier when trying to generate the NGINX config files within the NGINX directory.<\/p>\n<p>You can automate sudo to run on the command line, but in almost every example given it requires either echoing out the root username and password (which doesn&#8217;t work if you&#8217;re doing it from a PHP script using PHP 5.6+ which, incidentally, is a <span style=\"color: #ff0000;\">BAD IDEA<\/span>) or you can have the username and password on the server in a file and read it in, which is a <span style=\"color: #ff0000;\">BAD IDEA<\/span>.<\/p>\n<p>After much Googling, <a title=\"StackOverflow to the rescue!\" href=\"http:\/\/stackoverflow.com\/questions\/3011067\/restart-nginx-without-sudo\" target=\"_blank\" rel=\"noopener noreferrer\">I found the following article on StackOverflow<\/a>, which explained that I could just make an exception for that file to run without a password.<\/p>\n<p>I added the line to \/etc\/sudoers and promptly broke sudo on the server<sup class='footnote'><a href='https:\/\/www.payneful.co.uk\/blogsplosion\/2020\/02\/09\/the-payneful-portfolio-redirecting-domain-names-to-mask-a-different-domain-path-using-nginx\/#fn-2984-3' id='fnref-2984-3' onclick='return fdfootnote_show(2984)'>3<\/a><\/sup> because of a syntax error.<\/p>\n<div id=\"attachment_108\" class=\"wp-caption aligncenter\" style=\"width: 529px\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-108 size-full\" title=\"Shit hitting a fan.\" src=\"http:\/\/www.payneful.co.uk\/blogsplosion\/wp-content\/uploads\/2017\/01\/ShitHittingFan.gif\" alt=\"Shit hitting a fan\" width=\"519\" height=\"360\" \/><div class=\"wp-caption-text\">An apt visual metaphor.<\/div><\/div>\n<p>Before I proceed any further, let me reiterate: DO NOT EDIT THE SUDOERS FILE FOR ANY REASON, NO, NOT EVEN FOR THAT REASON. NEVER <strong>EVER<\/strong> TOUCH IT!<\/p>\n<h2>I&#8217;ve touched the sudoers file and broken it. Erm. What do I do now?<\/h2>\n<p>*Sighs*<\/p>\n<p>A lot of solutions to fix the sudoer file <a title=\"AskUbuntu to the rescue!\" href=\"http:\/\/askubuntu.com\/questions\/209558\/how-can-i-fix-broken-sudo-sudo-parse-error-in-etc-sudoers-near-line-23\" target=\"_blank\" rel=\"noopener noreferrer\">involve using pkexec<\/a> or <a title=\"And here's how to do that.\" href=\"http:\/\/askubuntu.com\/questions\/209558\/how-can-i-fix-broken-sudo-sudo-parse-error-in-etc-sudoers-near-line-23\" target=\"_blank\" rel=\"noopener noreferrer\">rebooting the server in recovery mode<\/a>. For me, the former wasn&#8217;t installed (the cruel irony being that I needed sudo to install it) and the latter just completely locked me out as we rely on SSH keys for everything<sup class='footnote'><a href='https:\/\/www.payneful.co.uk\/blogsplosion\/2020\/02\/09\/the-payneful-portfolio-redirecting-domain-names-to-mask-a-different-domain-path-using-nginx\/#fn-2984-4' id='fnref-2984-4' onclick='return fdfootnote_show(2984)'>4<\/a><\/sup>.<\/p>\n<p>How I did fix it was to power down the box, reset the root password for the server using the hosting panel, boot it back up, &#8220;su&#8221; into the root account using the new password and then run &#8220;visudo&#8221; to remove the offending line that broke sudo in the first place. I resolved after that point to never, ever touch the sudoers file again.<\/p>\n<h2>So how do we allow NGINX to run without a password?<\/h2>\n<p>How to add the exception line? That&#8217;s where sudoers.d comes in. Much the same way I could extend the NGINX config with other config files, <a title=\"Here's a link to someone else's WordPress blog on how to do that.\" href=\"https:\/\/luiseth.wordpress.com\/2012\/04\/15\/in-a-nutshell-add-permissions-with-configuration-files-in-etcsudoers-d\/\" target=\"_blank\" rel=\"noopener noreferrer\">you can do the same with the sudoers file<\/a>.<\/p>\n<p>I created a file called &#8220;scripts_permissions&#8221; (you can call it anything as long as it has neither a &#8220;.&#8221; or &#8220;~&#8221; in it) and added the following:<\/p>\n<pre>#Allow nginx to reload config without a password\r\n[username] ALL=(root) NOPASSWD: \/usr\/sbin\/service nginx reload<\/pre>\n<p>Obviously you need to replace [username] with the user that needs access. This is when I found out that if you create a crontab file, the system will run those crontab functions as the user who created the file (not root)! Sound simple, but it can be confusing as I was putting the wrong user in the rule (I assumed it had to be the root account).<\/p>\n<p>This now means that I could run &#8220;sudo service nginx reload&#8221; on the command lineand it wouldn&#8217;t ask for a password. I set the cronjob to run once an hour during certain times on weekdays and hey presto! It now picks up on any new domain rules that I add to \/path\/to\/directory\/where\/we\/will\/add\/redirects\/ (obviously with a real filepath), albeit on an hourly refresh.<\/p>\n<p>The final point is to generate the redirects file containing the proxy_pass rules and move it to our redirects folder &#8211; this is simple enough to do in PHP using the exec() function or, if you want to be extra safe, dump the PHP-generated files to a directory and then have the system move the files to the sensitive directories so scrubby PHP isn&#8217;t soiling your file system with its treacherous clumsy fingers.<\/p>\n<h2>Can you just use a wildcard DNS entry rather than separate subdomain config entries each time?<\/h2>\n<p>You can! You can just point a DNS entry for any subdomain at a server and these rules will still allow certain subdomains to proxy_pass specific URLs.<\/p>\n<p>There&#8217;s one problem (one which I don&#8217;t know the cause of) &#8211; say you have the following subdomains:<\/p>\n<ul>\n<li>test1.otherdomain.com &#8211; proxy_pass set to http:\/\/maindomain.com\/url1<\/li>\n<li>test2.otherdomain.com &#8211; proxy_pass set to http:\/\/maindomain.com\/url2<\/li>\n<\/ul>\n<p>If you have a wildcard DNS entry and then try &#8220;test3.otherdomain.com&#8221; in your address bar with the above two subdomains in place using the setup outlined here, it will bafflingly point at one of the proxy_pass rules despite there only being rules for &#8220;test1&#8221; and &#8220;test2&#8221;. I have a feeling it points at the last rule that gets loaded, but I haven&#8217;t tested this.<\/p>\n<p>The solution I found was to create another, separate rule just for the domain as a whole:<\/p>\n<pre>server {\r\n     listen 80;\r\n     server_name *.otherdomain.com;\r\n     return 404;\r\n}<\/pre>\n<p>This blocks all unwanted wildcard traffic and still allows the other rules to work for proxy_pass.<\/p>\n<h2>Erm, one last thing. I&#8217;ve added a bunch of NGINX config files and now my app is broken in several places. Like, Google maps won&#8217;t load and stuff.<\/h2>\n<p>Ah, I had this problem too. We thought we&#8217;d got hacked or blocked by Google or something. As it turns out, basically we added a config file and the server decided that it should prioritise it over the main configuration file. Our website was basically masking all traffic via a different domain, which was really confusing the app.<\/p>\n<p>It&#8217;s a really, really simple fix. You basically need to<a title=\"It's on the official NGINX website for Pete's sake! How I overlooked this...\" href=\"http:\/\/nginx.org\/en\/docs\/http\/request_processing.html\" target=\"_blank\" rel=\"noopener noreferrer\"> add &#8216;default_server&#8217; to your main config<\/a> so that NGINX knows which of the myriad of config files is the one it should prioritise.<\/p>\n<hr \/>\n","protected":false},"excerpt":{"rendered":"<a href=\"https:\/\/www.payneful.co.uk\/blogsplosion\/2020\/02\/09\/the-payneful-portfolio-redirecting-domain-names-to-mask-a-different-domain-path-using-nginx\/\"><img width=\"125\" height=\"125\" src=\"https:\/\/www.payneful.co.uk\/blogsplosion\/wp-content\/uploads\/NGINX_Mask-150x150.png\" class=\"alignright tfe wp-post-image\" alt=\"NGINX Mask\" decoding=\"async\" loading=\"lazy\" srcset=\"https:\/\/www.payneful.co.uk\/blogsplosion\/wp-content\/uploads\/NGINX_Mask-150x150.png 150w, https:\/\/www.payneful.co.uk\/blogsplosion\/wp-content\/uploads\/NGINX_Mask.png 225w\" sizes=\"auto, (max-width: 125px) 100vw, 125px\" \/><\/a><p>How to use NGINX configs to mask URLs. It&#8217;s basically a means of &#8220;white-labelling&#8221; domains to specific web URLs on one server. If you understand what any of this means, this post is probably for you. Also, don&#8217;t feck with the sudoers file!<\/p>\n","protected":false},"author":1,"featured_media":2985,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[383,382],"tags":[409,410,411,412,413,414],"class_list":["post-2984","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-articles","category-portfolio-and-work","tag-404-not-found","tag-domain-masking","tag-how-to-break-a-server-by-faffing-with-the-sudoers-file","tag-linux","tag-nginx","tag-server-tinkering"],"_links":{"self":[{"href":"https:\/\/www.payneful.co.uk\/blogsplosion\/wp-json\/wp\/v2\/posts\/2984","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.payneful.co.uk\/blogsplosion\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.payneful.co.uk\/blogsplosion\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.payneful.co.uk\/blogsplosion\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.payneful.co.uk\/blogsplosion\/wp-json\/wp\/v2\/comments?post=2984"}],"version-history":[{"count":0,"href":"https:\/\/www.payneful.co.uk\/blogsplosion\/wp-json\/wp\/v2\/posts\/2984\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.payneful.co.uk\/blogsplosion\/wp-json\/wp\/v2\/media\/2985"}],"wp:attachment":[{"href":"https:\/\/www.payneful.co.uk\/blogsplosion\/wp-json\/wp\/v2\/media?parent=2984"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.payneful.co.uk\/blogsplosion\/wp-json\/wp\/v2\/categories?post=2984"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.payneful.co.uk\/blogsplosion\/wp-json\/wp\/v2\/tags?post=2984"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}