{"id":417,"date":"2026-01-13T08:17:49","date_gmt":"2026-01-12T20:17:49","guid":{"rendered":"https:\/\/www.berserkir.net\/wordpress\/?p=417"},"modified":"2026-01-13T08:17:51","modified_gmt":"2026-01-12T20:17:51","slug":"reverse-proxy-with-nginx","status":"publish","type":"post","link":"https:\/\/www.berserkir.net\/wordpress\/reverse-proxy-with-nginx\/","title":{"rendered":"Reverse Proxy (with Nginx)"},"content":{"rendered":"\n<p>I did a little write-up on how I achieved <a href=\"https:\/\/www.berserkir.net\/wordpress\/reverse-proxy-with-iis\/\" target=\"_blank\" rel=\"noopener\" title=\"Reverse Proxy (with IIS)\">reverse proxy nirvana with IIS<\/a> quite a while ago now. It made things a lot nicer for me. Like, <em>a lot.<\/em> Then I took it further, and <a href=\"https:\/\/www.berserkir.net\/wordpress\/reverse-proxy-with-apache\/\" title=\"Reverse Proxy (with Apache)\">moved to Apache<\/a> (with <a href=\"https:\/\/certbot.eff.org\/\" target=\"_blank\" rel=\"noopener\" title=\"certbot\">certbot<\/a>, for that sweet SSL).<\/p>\n\n\n\n<p>Now I have a few friends\/colleagues\/acquaintances who run Nginx (I run Apache in my homelab environment nowadays, which is why I migrated from IIS to Apache), so I figured I&#8217;d look into how I can help them achieve a reverse proxy with Nginx instead.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>Firstly, you&#8217;ll need to have a functional Nginx installation. We&#8217;re not covering that here, there are plenty of write-ups about that out there. It&#8217;s fairly straightforward to do, and simply requires you have root access to the shell on your server.<br><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Deactivating the default config<\/h3>\n\n\n\n<p>Secondly, you&#8217;ll need to unlink the default linked configuration\/virtualhost file (assuming this is a fresh Nginx instance, not serving other sites. If it&#8217;s in use for other sites, then this guide could provide a base to build from but will break the existing site if it&#8217;s using the default config file <em>which I strongly recommend against doing<\/em>).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo unlink \/etc\/nginx\/sites-enabled\/default<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Creating and activating the reverse proxy config file<\/h3>\n\n\n\n<p>Now that&#8217;s out of the way, we can create a config for the reverse proxy page (I tend to use the name of the site as the name of the config file)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo nano \/etc\/nginx\/sites-available\/reverse-proxy<\/code><\/pre>\n\n\n\n<p>In this config file, we will start with something like the following:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>server {\n    listen 80;\n    server_name site.example.com;\n    location \/ {\n        proxy_pass http:\/\/127.0.0.1:8000;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n    }\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Configuration directives<\/h4>\n\n\n\n<p>The configuration consists of a\u00a0<code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">server {...}<\/code>\u00a0block that handles all requests matching the specified conditions. It contains the following data:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>listen 80<\/code>. The server listens for incoming\u00a0HTTP\u00a0requests on\u00a0port\u00a080 (the default HTTP port). <\/li>\n\n\n\n<li><code>server_name site.example.com<\/code> The\u00a0domain name\u00a0for which the server block is responsible. The example uses\u00a0site.example.com to demonstrate how the reverse proxy works. This needs to be a valid name for the web server to reply to the correct site when it is requested. This is also used by tools like Certbot when requesting SSL certificates.<\/li>\n\n\n\n<li><code>location \/ {...}<\/code>. The configuration for the specified URI path. It matches all requests (<code>\/<\/code>) in this case.<\/li>\n\n\n\n<li><code>proxy_pass http:\/\/127.0.0.1:8000<\/code>. The backend server to which NGINX will pass requests to (which is what a reverse proxy does). The example references an alternative service listening on port 8000 on the same server (<code>127.0.0.1:8000<\/code>) as a replacement backend. This will change depending on what you&#8217;re reverse proxy is proxying to &#8211; it should be replaced with whatever your internal URL for the service you wish to proxy is.<\/li>\n\n\n\n<li><code>proxy_set_header<\/code>. The directive for setting HTTP headers for the proxied request. The headers pass to the backend server and provide additional information about the client&#8217;s request. The example includes the\u00a0Host\u00a0header, the client&#8217;s\u00a0IP address, and the scheme (HTTP or HTTPS).<\/li>\n<\/ul>\n\n\n\n<p>Replace the\u00a0port number, server name, and the backend server with the actual data. The example forwards all requests made to\u00a0<code>site.example.com<\/code>\u00a0to the\u00a0<code>http:\/\/127.0.0.1:8000<\/code>\u00a0address.<\/p>\n\n\n\n<p>Save the file and\u00a0exit nano.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Activating the new config<\/h4>\n\n\n\n<p>Now that the file is ready for use, we have to activate it. This is done by linking the file from <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">\/etc\/nginx\/sites-available<\/code> to <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">\/etc\/nginx\/sites-enabled<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo ln -s \/etc\/nginx\/sites-available\/reverse-proxy \/etc\/nginx\/sites-enabled\/<\/code><\/pre>\n\n\n\n<p>With the file activated, we can tell Nginx to test the config with <code data-enlighter-language=\"asm\" class=\"EnlighterJSRAW\">sudo nginx -t<\/code>. <br>Assuming this passes successfully, we can make it go live with a restart of Nginx (<code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">sudo systemctl restart nginx<\/code>).<\/p>\n\n\n\n<p>Awesome! Nginx is now running as a proxy, which means that (assuming your network is pointing traffic to the right location with port forwards and DNS and such), you should be able to browse to the  address you specified in the config and you&#8217;ll get whatever the proxied application was using the new &#8216;pretty&#8217; URL. Much nicer.<\/p>\n\n\n\n<p>It also means you can set up an SSL connection to secure it &#8211; but that&#8217;s a topic for another writeup (maybe). For now, the magic term is &#8220;<a href=\"https:\/\/certbot.eff.org\/\" title=\"\">certbot<\/a>&#8221; &#8211; as it can automate it and take most of the pain away.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I did a little write-up on how I achieved reverse proxy nirvana with IIS quite a while ago now. It made things a lot nicer for me. Like, a lot. Then I took it further, and moved to Apache (with certbot, for that sweet SSL). Now I have a few friends\/colleagues\/acquaintances who run Nginx (I &hellip; <\/p>\n<p><a class=\"more-link btn\" href=\"https:\/\/www.berserkir.net\/wordpress\/reverse-proxy-with-nginx\/\">Continue reading<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,124,41,16,78],"tags":[125,56,13,26,45,48],"class_list":["post-417","post","type-post","status-publish","format-standard","hentry","category-helpful-hints","category-nginx","category-servers","category-software","category-web-systems","tag-nginx","tag-ports","tag-server","tag-software","tag-useful","tag-web-page","item-wrap"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.berserkir.net\/wordpress\/wp-json\/wp\/v2\/posts\/417","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.berserkir.net\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.berserkir.net\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.berserkir.net\/wordpress\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.berserkir.net\/wordpress\/wp-json\/wp\/v2\/comments?post=417"}],"version-history":[{"count":3,"href":"https:\/\/www.berserkir.net\/wordpress\/wp-json\/wp\/v2\/posts\/417\/revisions"}],"predecessor-version":[{"id":420,"href":"https:\/\/www.berserkir.net\/wordpress\/wp-json\/wp\/v2\/posts\/417\/revisions\/420"}],"wp:attachment":[{"href":"https:\/\/www.berserkir.net\/wordpress\/wp-json\/wp\/v2\/media?parent=417"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.berserkir.net\/wordpress\/wp-json\/wp\/v2\/categories?post=417"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.berserkir.net\/wordpress\/wp-json\/wp\/v2\/tags?post=417"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}