<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Reverse-Proxy on MangoDriod</title><link>https://md.eknath.dev/tags/reverse-proxy/</link><description>Recent content in Reverse-Proxy on MangoDriod</description><generator>Hugo -- 0.141.0</generator><language>en-us</language><lastBuildDate>Sun, 07 Sep 2025 12:00:00 +0530</lastBuildDate><atom:link href="https://md.eknath.dev/tags/reverse-proxy/index.xml" rel="self" type="application/rss+xml"/><item><title>Advanced VPS Guide: Mastering Nginx, Subdomains, and Reverse Proxies</title><link>https://md.eknath.dev/posts/software-development/vps-setup-guide/</link><pubDate>Sun, 07 Sep 2025 12:00:00 +0530</pubDate><guid>https://md.eknath.dev/posts/software-development/vps-setup-guide/</guid><description>&lt;p>A Virtual Private Server (VPS) is your personal canvas on the internet. While basic setup is straightforward, unlocking its true potential requires mastering the web server. This guide dives deep into using Nginx to host multiple projects, manage subdomains, and route traffic to different services, transforming your single server into a multi-functional powerhouse.&lt;/p>
&lt;h2 id="1-initial-server-setup">1. Initial Server Setup&lt;/h2>
&lt;p>After acquiring a VPS, you&amp;rsquo;ll get an IP address and root access. Your first steps are to secure the server and create a non-root user for daily operations.&lt;/p></description><content:encoded><![CDATA[<p>A Virtual Private Server (VPS) is your personal canvas on the internet. While basic setup is straightforward, unlocking its true potential requires mastering the web server. This guide dives deep into using Nginx to host multiple projects, manage subdomains, and route traffic to different services, transforming your single server into a multi-functional powerhouse.</p>
<h2 id="1-initial-server-setup">1. Initial Server Setup</h2>
<p>After acquiring a VPS, you&rsquo;ll get an IP address and root access. Your first steps are to secure the server and create a non-root user for daily operations.</p>
<p>Connect to your server via SSH:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>ssh root@YOUR_SERVER_IP
</span></span></code></pre></div><h3 id="create-a-sudo-user">Create a Sudo User</h3>
<p>Operating as <code>root</code> is risky. Create a new user and grant administrative privileges.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Create the new user (replace &#39;devuser&#39; with your username)</span>
</span></span><span style="display:flex;"><span>adduser devuser
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Add the user to the &#39;sudo&#39; group</span>
</span></span><span style="display:flex;"><span>usermod -aG sudo devuser
</span></span></code></pre></div><p>Now, set up SSH key authentication for your new user for enhanced security and convenience, then log in as that user.</p>
<h2 id="2-essential-security-and-updates">2. Essential Security and Updates</h2>
<p>A public server is a constant target. Secure it immediately.</p>
<h3 id="configure-the-firewall">Configure the Firewall</h3>
<p><code>ufw</code> (Uncomplicated Firewall) makes this easy. We&rsquo;ll allow SSH, HTTP, and HTTPS traffic.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Allow OpenSSH (so you don&#39;t lock yourself out)</span>
</span></span><span style="display:flex;"><span>sudo ufw allow OpenSSH
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Allow Nginx to handle web traffic on ports 80 and 443</span>
</span></span><span style="display:flex;"><span>sudo ufw allow <span style="color:#e6db74">&#39;Nginx Full&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Enable the firewall</span>
</span></span><span style="display:flex;"><span>sudo ufw enable
</span></span></code></pre></div><p>After enabling, check its status to ensure it&rsquo;s active and your rules are loaded.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo ufw status
</span></span></code></pre></div><h3 id="update-your-server">Update Your Server</h3>
<p>Keep your system&rsquo;s packages current to patch security vulnerabilities.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo apt update <span style="color:#f92672">&amp;&amp;</span> sudo apt upgrade -y
</span></span></code></pre></div><h2 id="3-installing-and-understanding-nginx">3. Installing and Understanding Nginx</h2>
<p>Nginx is the heart of our setup. It&rsquo;s a high-performance web server that can also act as a reverse proxy, load balancer, and more.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Install Nginx</span>
</span></span><span style="display:flex;"><span>sudo apt install nginx -y
</span></span></code></pre></div><p>While the package should start and enable Nginx automatically, it&rsquo;s good practice to run the commands explicitly to be sure.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Start the Nginx service</span>
</span></span><span style="display:flex;"><span>sudo systemctl start nginx
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Enable Nginx to start automatically on boot</span>
</span></span><span style="display:flex;"><span>sudo systemctl enable nginx
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Now, check that it&#39;s running and enabled</span>
</span></span><span style="display:flex;"><span>sudo systemctl status nginx
</span></span></code></pre></div><p>You should see <code>active (running)</code> in the output. Visiting your server&rsquo;s IP in a browser should also show the Nginx welcome page.</p>
<h3 id="nginx-configuration-structure">Nginx Configuration Structure</h3>
<p>Nginx&rsquo;s configuration lives in <code>/etc/nginx</code>. The <code>-p</code> flag in the commands below ensures that the command does nothing if the directories already exist.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo mkdir -p /etc/nginx/sites-available
</span></span><span style="display:flex;"><span>sudo mkdir -p /etc/nginx/sites-enabled
</span></span></code></pre></div><p>The key directories are:</p>
<ul>
<li><code>/etc/nginx/nginx.conf</code>: The main configuration file. You rarely edit this.</li>
<li><code>/etc/nginx/sites-available/</code>: Where you store the configuration files for each of your sites (called &ldquo;server blocks&rdquo;).</li>
<li><code>/etc/nginx/sites-enabled/</code>: Where you create symbolic links to the configurations in <code>sites-available</code> that you want to be active.</li>
</ul>
<p>This structure lets you easily enable or disable sites without deleting their configuration files.</p>
<h2 id="4-advanced-hosting-subdomains-and-reverse-proxies">4. Advanced Hosting: Subdomains and Reverse Proxies</h2>
<p>This is where the magic happens. A single server can host a blog, a portfolio website, a web app, and several APIs, all neatly organized using subdomains.</p>
<p>The core concept is the <strong>Reverse Proxy</strong>. Your Nginx server listens on the standard web ports (80 for HTTP, 443 for HTTPS) and intelligently forwards incoming requests to the correct internal service based on the requested domain or subdomain.</p>
<h3 id="scenario">Scenario:</h3>
<p>Let&rsquo;s say we want to set up the following on our server:</p>
<ol>
<li><code>eknath.dev</code>: A static HTML/CSS website.</li>
<li><code>blog.eknath.dev</code>: A separate project, maybe a Hugo or Jekyll site.</li>
<li><code>api.eknath.dev</code>: A Node.js application running on port <code>3000</code>.</li>
</ol>
<h3 id="step-1-create-project-directories">Step 1: Create Project Directories</h3>
<p>Organize your projects in the <code>/var/www</code> directory.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Create directories for the main site and blog</span>
</span></span><span style="display:flex;"><span>sudo mkdir -p /var/www/eknath.dev/html
</span></span><span style="display:flex;"><span>sudo mkdir -p /var/www/blog.eknath.dev/html
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Set correct permissions</span>
</span></span><span style="display:flex;"><span>sudo chown -R $USER:$USER /var/www/eknath.dev
</span></span><span style="display:flex;"><span>sudo chown -R $USER:$USER /var/www/blog.eknath.dev
</span></span></code></pre></div><p>Verify that the directories were created with the correct ownership.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>ls -ld /var/www/eknath.dev/
</span></span><span style="display:flex;"><span>ls -ld /var/www/blog.eknath.dev/
</span></span></code></pre></div><p>Now, place some placeholder files.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;&lt;h1&gt;Welcome to Eknath&#39;s Site&lt;/h1&gt;&#34;</span> | sudo tee /var/www/eknath.dev/html/index.html
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;&lt;h1&gt;Welcome to Eknath&#39;s Blog&lt;/h1&gt;&#34;</span> | sudo tee /var/www/blog.eknath.dev/html/index.html
</span></span></code></pre></div><h3 id="step-2-create-nginx-server-blocks">Step 2: Create Nginx Server Blocks</h3>
<p>Now, we create a configuration file for each site in <code>sites-available</code>.</p>
<p><strong>For the main domain (<code>eknath.dev</code>):</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo nano /etc/nginx/sites-available/eknath.dev
</span></span></code></pre></div><p>Add the following server block:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-nginx" data-lang="nginx"><span style="display:flex;"><span><span style="color:#66d9ef">server</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">listen</span> <span style="color:#ae81ff">80</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">listen</span> <span style="color:#e6db74">[::]:80</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">server_name</span> <span style="color:#e6db74">eknath.dev</span> <span style="color:#e6db74">www.eknath.dev</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">root</span> <span style="color:#e6db74">/var/www/eknath.dev/html</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">index</span> <span style="color:#e6db74">index.html</span> <span style="color:#e6db74">index.php</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">location</span> <span style="color:#e6db74">/</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">try_files</span> $uri $uri/ =<span style="color:#ae81ff">404</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p><strong>For the blog subdomain (<code>blog.eknath.dev</code>):</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo nano /etc/nginx/sites-available/blog.eknath.dev
</span></span></code></pre></div><p>Add this configuration:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-nginx" data-lang="nginx"><span style="display:flex;"><span><span style="color:#66d9ef">server</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">listen</span> <span style="color:#ae81ff">80</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">listen</span> <span style="color:#e6db74">[::]:80</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">server_name</span> <span style="color:#e6db74">blog.eknath.dev</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">root</span> <span style="color:#e6db74">/var/www/blog.eknath.dev/html</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">index</span> <span style="color:#e6db74">index.html</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">location</span> <span style="color:#e6db74">/</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">try_files</span> $uri $uri/ =<span style="color:#ae81ff">404</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h3 id="step-3-configure-the-reverse-proxy-for-the-api">Step 3: Configure the Reverse Proxy for the API</h3>
<p>For <code>api.eknath.dev</code>, we&rsquo;ll proxy requests to our Node.js app, which we assume is running on <code>http://127.0.0.1:3000</code>.</p>
<p>Create the configuration file:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo nano /etc/nginx/sites-available/api.eknath.dev
</span></span></code></pre></div><p>Add the reverse proxy configuration:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-nginx" data-lang="nginx"><span style="display:flex;"><span><span style="color:#66d9ef">server</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">listen</span> <span style="color:#ae81ff">80</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">listen</span> <span style="color:#e6db74">[::]:80</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">server_name</span> <span style="color:#e6db74">api.eknath.dev</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">location</span> <span style="color:#e6db74">/</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">proxy_pass</span> <span style="color:#e6db74">http://127.0.0.1:3000</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">proxy_set_header</span> <span style="color:#e6db74">Host</span> $host;
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">proxy_set_header</span> <span style="color:#e6db74">X-Real-IP</span> $remote_addr;
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">proxy_set_header</span> <span style="color:#e6db74">X-Forwarded-For</span> $proxy_add_x_forwarded_for;
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">proxy_set_header</span> <span style="color:#e6db74">X-Forwarded-Proto</span> $scheme;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h3 id="step-4-enable-the-sites-and-test">Step 4: Enable the Sites and Test</h3>
<p>Now, link these configurations into <code>sites-enabled</code> to activate them.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo ln -s /etc/nginx/sites-available/eknath.dev /etc/nginx/sites-enabled/
</span></span><span style="display:flex;"><span>sudo ln -s /etc/nginx/sites-available/blog.eknath.dev /etc/nginx/sites-enabled/
</span></span><span style="display:flex;"><span>sudo ln -s /etc/nginx/sites-available/api.eknath.dev /etc/nginx/sites-enabled/
</span></span></code></pre></div><p>Test the Nginx configuration for syntax errors:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo nginx -t
</span></span></code></pre></div><p>If it&rsquo;s successful, restart Nginx to apply the changes:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo systemctl restart nginx
</span></span></code></pre></div><p>Check the status to ensure it restarted correctly.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo systemctl status nginx
</span></span></code></pre></div><p>After setting up your DNS records, you&rsquo;ll be able to access each service through its unique subdomain.</p>
<h2 id="5-securing-your-sites-with-ssl-https">5. Securing Your Sites with SSL (HTTPS)</h2>
<p>We&rsquo;ll use <strong>Let&rsquo;s Encrypt</strong>, a free and automated Certificate Authority, and <strong>Certbot</strong>, a tool that makes managing SSL/TLS certificates effortless.</p>
<h3 id="step-1-install-certbot">Step 1: Install Certbot</h3>
<p>Certbot has a dedicated Nginx plugin that automates the process.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Install Certbot and its Nginx plugin</span>
</span></span><span style="display:flex;"><span>sudo apt install certbot python3-certbot-nginx -y
</span></span></code></pre></div><h3 id="step-2-obtain-and-install-the-ssl-certificates">Step 2: Obtain and Install the SSL Certificates</h3>
<p>With your server blocks already configured, running Certbot is incredibly simple.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Run Certbot to get certificates for all configured domains</span>
</span></span><span style="display:flex;"><span>sudo certbot --nginx
</span></span></code></pre></div><p>Certbot will guide you through a few simple steps:</p>
<ol>
<li><strong>Enter your email address.</strong></li>
<li><strong>Agree to the Terms of Service.</strong></li>
<li><strong>Choose domains</strong> from the list Certbot finds.</li>
<li><strong>Choose to redirect HTTP to HTTPS.</strong> This is highly recommended.</li>
</ol>
<h3 id="step-3-verify-the-new-configuration">Step 3: Verify the New Configuration</h3>
<p>Certbot automatically modifies your Nginx files to enable HTTPS. You can check the new configuration by running <code>sudo nginx -t</code> and then reloading Nginx with <code>sudo systemctl reload nginx</code>.</p>
<h3 id="step-4-understanding-automatic-renewal">Step 4: Understanding Automatic Renewal</h3>
<p>Let&rsquo;s Encrypt certificates are valid for 90 days. The Certbot package automatically sets up a task to renew them. You can test the renewal process with a dry run:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo certbot renew --dry-run
</span></span></code></pre></div><p>If this command runs without errors, your auto-renewal is set up correctly.</p>
<h2 id="conclusion">Conclusion</h2>
<p>You have now transformed a basic VPS into a sophisticated, multi-tenant hosting platform. By leveraging Nginx&rsquo;s server blocks and reverse proxy capabilities, you can host and manage numerous projects, each on its own subdomain, from a single server. Happy hosting!</p>
]]></content:encoded></item></channel></rss>