<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Tech Tales | AI, MLOps & Software Engineering Insights]]></title><description><![CDATA[Explore practical guides, tutorials, and insights on AI, MLOps, and software engineering. Stay ahead with Tech Tales — your tech learning hub. of tech related blogs.]]></description><link>https://techtales.tilakr.dev</link><generator>RSS for Node</generator><lastBuildDate>Mon, 20 Apr 2026 10:31:36 GMT</lastBuildDate><atom:link href="https://techtales.tilakr.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How to host n8n on aws]]></title><description><![CDATA[Nowadays, many individuals and businesses are leveraging n8n to create diverse automation tools and systems. In this article, we will explore about n8n and how to host n8n for personal projects, providing you with the knowledge to take full control o...]]></description><link>https://techtales.tilakr.dev/how-to-host-n8n-on-aws</link><guid isPermaLink="true">https://techtales.tilakr.dev/how-to-host-n8n-on-aws</guid><category><![CDATA[n8n]]></category><category><![CDATA[automation]]></category><category><![CDATA[Docker]]></category><category><![CDATA[#Lightsail]]></category><category><![CDATA[AWS]]></category><dc:creator><![CDATA[Tilak raj Choubey]]></dc:creator><pubDate>Fri, 15 Aug 2025 07:21:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1755502168518/9761a5f3-0a55-4905-aba9-4579e3f2e452.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Nowadays, many individuals and businesses are leveraging n8n to create diverse automation tools and systems. In this article, we will explore about n8n and how to host n8n for personal projects, providing you with the knowledge to take full control of your automation needs and enjoy unlimited executions.</p>
<h2 id="heading-what-is-n8n">What is n8n</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755116243470/b276b5d7-5e17-4027-84cb-d5a588d64bef.png" alt class="image--center mx-auto" /></p>
<p>N8n is an open-source automation tool that allows users to connect various applications and services to automate workflows. It provides a flexible and user-friendly platform for creating complex workflows without the need for extensive coding knowledge. With n8n, users can streamline processes, enhance productivity, and integrate different systems to work together seamlessly.</p>
<p>You can visit <a target="_blank" href="https://github.com/n8n-io/n8n">n8n github</a> for open sourced version of N8N.</p>
<h2 id="heading-why-to-host-n8n-locally">Why to host n8n locally</h2>
<ol>
<li><p>N8n only provides 14 days of free trial of pro plans of n8n cloud SaaS. After which you are redirected to upgrade to a paid account. Failing to do so can lead to your data being deleted after warnings.</p>
</li>
<li><p>Even the lowest paid plans of n8n costs around 20 euros a month (starter pack paid yearly) whereas we can do better in even lesser price.</p>
</li>
<li><p>So choose n8n hosted locally if you want to use it for your <strong>personal projects</strong>, lower budget, unlimited executions, better data privacy (resides in your local machine) and to learn something new (how to host a local n8n).</p>
</li>
</ol>
<h2 id="heading-minimum-requirements">Minimum requirements</h2>
<p>Althrough we can run it on lower ends but for the proper and smooth functionality of the program, minimum requirements to run n8n for personal projects would be 2GBs of RAM 2 vCPUs and 20 GB SSD.</p>
<h2 id="heading-why-use-lightsail-and-not-ec2">Why use lightsail and not ec2?</h2>
<p>Since you are configuring it for your personal projects and use cases, lightsail offers several benefits over ec2 instance like:</p>
<ol>
<li><p>Fixed pricing with no surprise - Unlike ec2, it is fixed and pre calculated as it is not automatically scalable, perfect for our use case.</p>
</li>
<li><p>Pre-configured networking and firewall settings - Unlike ec2 all firewalls are preconfigured like port 22 and 80.</p>
</li>
<li><p>More simplified - Unlike ec2 it is more rigid and provides less configurable parts and more preconfigured parts. So it is faster to setup than ec2 and all it takes is to start the instance.</p>
</li>
<li><p>FIrst 90 days free for our case - Unlike ec2, lightsail provides with basic requirements in the free tier to run the n8n locally. Whereas ec2 provides t2.mirco for free 12 months, it is not sufficient to run n8n freely.</p>
</li>
</ol>
<h2 id="heading-setup-dockerized-container-with-n8n-application">Setup dockerized container with N8N application</h2>
<ol>
<li><p>Create a lightsail with linux, os only and ubuntu (most used configuration). Select 2 GBs RAM, 2 vCPUs ane 60 GB SSD (free for 90 days).</p>
</li>
<li><p>Go to networking tab and attach a static IP to the instance. (Otherwise the IP would be changed everytime the instance is restarted).</p>
</li>
<li><p>Connect to the instance using either browser or your own SSH client.</p>
</li>
<li><p>Install docker and docker compose in the system and create a folder for n8n</p>
<pre><code class="lang-bash"> <span class="hljs-comment"># Update system packages</span>
 sudo apt update &amp;&amp; sudo apt upgrade -y

 <span class="hljs-comment"># Install Docker using the official script (includes docker compose plugin)</span>
 curl -fsSL https://get.docker.com -o get-docker.sh
 sudo sh get-docker.sh

 <span class="hljs-comment"># Optional: Add your user to the docker group to avoid using 'sudo'</span>
 sudo usermod -aG docker <span class="hljs-variable">$USER</span>
 newgrp docker  <span class="hljs-comment"># or log out and log back in</span>
</code></pre>
<pre><code class="lang-bash">
 <span class="hljs-comment"># Test Docker Compose (new CLI plugin)</span>
 docker compose version

 <span class="hljs-comment"># Create a folder for n8n</span>
 mkdir -p ~/n8n-docker

 <span class="hljs-comment"># move into the newly created folder</span>
 <span class="hljs-built_in">cd</span> ~/n8n-docker

 mkdir n8n-data postgres-data

 sudo chown -R 1000:1000 ./n8n-data
 sudo chown -R 999:999 ./postgres-data
</code></pre>
</li>
<li><p>Either you can directly run docker command to create a container out of the latest n8n image online, or you can use <strong>docker-compose</strong> method to run a series of containers (recommended). Below is the docker compose method. Inside of your newly created folder n8n-docker and create a file called docker-compose.yml and save the given content there.</p>
<pre><code class="lang-yaml"> <span class="hljs-attr">version:</span> <span class="hljs-string">'3.8'</span>
 <span class="hljs-attr">services:</span>
   <span class="hljs-attr">nginx:</span>
     <span class="hljs-attr">image:</span> <span class="hljs-string">nginx:alpine</span>
     <span class="hljs-attr">restart:</span> <span class="hljs-string">unless-stopped</span>
     <span class="hljs-attr">ports:</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">"80:80"</span>
     <span class="hljs-attr">volumes:</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">./nginx.conf:/etc/nginx/nginx.conf</span>
     <span class="hljs-attr">depends_on:</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">n8n</span>
   <span class="hljs-attr">postgres:</span>
     <span class="hljs-attr">image:</span> <span class="hljs-string">postgres:13</span>
     <span class="hljs-attr">restart:</span> <span class="hljs-string">unless-stopped</span>
     <span class="hljs-attr">environment:</span>
       <span class="hljs-attr">POSTGRES_DB:</span> <span class="hljs-string">${POSTGRES_DB}</span>
       <span class="hljs-attr">POSTGRES_USER:</span> <span class="hljs-string">${POSTGRES_USER}</span>
       <span class="hljs-attr">POSTGRES_PASSWORD:</span> <span class="hljs-string">${POSTGRES_PASSWORD}</span>
     <span class="hljs-attr">volumes:</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">./postgres-data:/var/lib/postgresql/data</span>
     <span class="hljs-attr">healthcheck:</span>
       <span class="hljs-attr">test:</span> [<span class="hljs-string">'CMD-SHELL'</span>, <span class="hljs-string">'pg_isready -h localhost -U ${POSTGRES_USER} -d ${POSTGRES_DB}'</span>]
       <span class="hljs-attr">interval:</span> <span class="hljs-string">5s</span>
       <span class="hljs-attr">timeout:</span> <span class="hljs-string">5s</span>
       <span class="hljs-attr">retries:</span> <span class="hljs-number">10</span>
   <span class="hljs-attr">n8n:</span>
     <span class="hljs-attr">image:</span> <span class="hljs-string">n8nio/n8n</span>
     <span class="hljs-attr">restart:</span> <span class="hljs-string">unless-stopped</span>
     <span class="hljs-attr">extra_hosts:</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">"host.docker.internal:host-gateway"</span>
     <span class="hljs-attr">environment:</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">DB_TYPE=postgresdb</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">DB_POSTGRESDB_HOST=postgres</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">DB_POSTGRESDB_PORT=5432</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">DB_POSTGRESDB_DATABASE=${POSTGRES_DB}</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">DB_POSTGRESDB_USER=${POSTGRES_USER}</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">N8N_HOST=${LIGHTSAIL_IP}</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">WEBHOOK_URL=http://${LIGHTSAIL_IP}</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">N8N_BASIC_AUTH_ACTIVE=${N8N_BASIC_AUTH_ACTIVE}</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">N8N_BASIC_AUTH_USER=${N8N_BASIC_AUTH_USER}</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">N8N_BASIC_AUTH_PASSWORD=${N8N_BASIC_AUTH_PASSWORD}</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">GENERIC_TIMEZONE=${GENERIC_TIMEZONE}</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">N8N_RUNNERS_ENABLED=${N8N_RUNNERS_ENABLED}</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">N8N_PROXY_HOPS=1</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">N8N_SECURE_COOKIE=false</span> <span class="hljs-comment"># This is only for HTTP requests</span>
     <span class="hljs-attr">volumes:</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">./n8n-data:/home/node/.n8n</span>
     <span class="hljs-attr">depends_on:</span>
       <span class="hljs-attr">postgres:</span>
         <span class="hljs-attr">condition:</span> <span class="hljs-string">service_healthy</span>
</code></pre>
<p> Now create two folders for volumes as mentioned in the yml file: postgres-data and n8n-data.</p>
<p> This docker-compose file creates containers for postgres, n8n and nginx (as reverse proxy).</p>
</li>
<li><p>Create a .env file with something like this (add proper values there):</p>
<pre><code class="lang-plaintext"> # PostgreSQL Configuration
 POSTGRES_USER=your_postgres_user
 POSTGRES_PASSWORD=your_postgres_password
 POSTGRES_DB=n8n

 # n8n Configuration
 LIGHTSAIL_IP=your_lightsail_public_ipv4_address  #For example 123.45.67.890
 N8N_BASIC_AUTH_ACTIVE=true
 N8N_BASIC_AUTH_USER=your_n8n_user
 N8N_BASIC_AUTH_PASSWORD=your_n8n_password
 N8N_RUNNERS_ENABLED=true

 # General Settings
 GENERIC_TIMEZONE=Asia/Kolkata
</code></pre>
</li>
<li><p>Create a nginx.conf file in the same location as docker-compose.yml to look like this:</p>
<pre><code class="lang-nginx"> <span class="hljs-section">events</span> {
     <span class="hljs-attribute">worker_connections</span> <span class="hljs-number">1024</span>;
 }

 <span class="hljs-section">http</span> {
     <span class="hljs-attribute">upstream</span> n8n {
         <span class="hljs-attribute">server</span> n8n:<span class="hljs-number">5678</span>;
     }

     <span class="hljs-section">server</span> {
         <span class="hljs-attribute">listen</span> <span class="hljs-number">80</span>;
         <span class="hljs-attribute">server_name</span> _;

         <span class="hljs-attribute">client_max_body_size</span> <span class="hljs-number">50M</span>;

         <span class="hljs-attribute">location</span> / {
             <span class="hljs-attribute">proxy_pass</span> http://n8n;
             <span class="hljs-attribute">proxy_set_header</span> Host <span class="hljs-variable">$host</span>;
             <span class="hljs-attribute">proxy_set_header</span> X-Real-IP <span class="hljs-variable">$remote_addr</span>;
             <span class="hljs-attribute">proxy_set_header</span> X-Forwarded-For <span class="hljs-variable">$proxy_add_x_forwarded_for</span>;
             <span class="hljs-attribute">proxy_set_header</span> X-Forwarded-Proto <span class="hljs-variable">$scheme</span>;

             <span class="hljs-comment"># to support websockets connections required for n8n</span>
             <span class="hljs-attribute">proxy_http_version</span> <span class="hljs-number">1</span>.<span class="hljs-number">1</span>;
             <span class="hljs-attribute">proxy_set_header</span> Upgrade <span class="hljs-variable">$http_upgrade</span>;
             <span class="hljs-attribute">proxy_set_header</span> Connection <span class="hljs-string">"upgrade"</span>;
         }
     }
 }
</code></pre>
</li>
<li><p>Run the docker compose</p>
<pre><code class="lang-bash"> docker compose up -d
</code></pre>
</li>
</ol>
<p>You can now access it from your browser by going to <strong>http://your-lightsail-ip</strong> and you would see something like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754499472279/6a76670b-b0d7-44dd-864d-052630057c51.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-potential-risks-of-http">Potential risks of HTTP</h2>
<p>This instance that we just started is only advisable for development environment and personal use. You should always consider upgrading to HTTPS over HTTP.</p>
<p>Advantages of HTTPS over HTTP:</p>
<ul>
<li><p>Https encrypts all the communication between client and server, which also include your API keys used in the n8n workflows. Using unencrypted keys in HTTP may lead to security leaks.</p>
</li>
<li><p>HTTPS uses SSL certificate that are issued by a trusted certificate authority.</p>
</li>
<li><p>Many browsers block or warn against accessing HTTP sites.</p>
</li>
</ul>
<h2 id="heading-how-to-set-up-https-in-the-existing-setup">How to set up HTTPS in the existing setup?</h2>
<h3 id="heading-prerequisite">Prerequisite:</h3>
<p>You need to buy a domain name in order to setup https request because SSL/TLS certificates are issued for domain names.</p>
<h3 id="heading-steps-required">Steps required:</h3>
<ul>
<li><p>Buy a domain name if you don’t have one already.</p>
</li>
<li><p>Create a dns record to point to your lightsail public ip-address.</p>
</li>
<li><p>Update the <strong>.env</strong> file to add <strong>DOMAIN_NAME</strong> variable</p>
<pre><code class="lang-bash">  <span class="hljs-comment"># remove this line:</span>
  LIGHTSAIL_IP=your_lightsail_public_ipv4_address

  <span class="hljs-comment"># add this line instead:</span>
  DOMAIN_NAME=subdomain.domain.com     <span class="hljs-comment"># domain name you registed in your dns record</span>
</code></pre>
</li>
<li><p>Update <strong>docker-compose.yml</strong> to change the nginx configuration</p>
<pre><code class="lang-yaml">  <span class="hljs-comment"># Replace the nginx configuration with this.</span>
  <span class="hljs-attr">nginx:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">nginx:alpine</span>
    <span class="hljs-attr">restart:</span> <span class="hljs-string">unless-stopped</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"80:80"</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"443:443"</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./nginx.conf:/etc/nginx/nginx.conf</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./ssl:/etc/nginx/ssl</span>
    <span class="hljs-attr">depends_on:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">n8n</span>
</code></pre>
<p>  Also update n8n environment variable</p>
<pre><code class="lang-yaml">  <span class="hljs-comment"># Replace these lines in n8n service:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">N8N_HOST=${LIGHTSAIL_IP}</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">WEBHOOK_URL=http://${LIGHTSAIL_IP}</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">N8N_SECURE_COOKIE=false</span> <span class="hljs-comment"># This is only for HTTP requests</span>

  <span class="hljs-comment"># With these:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">N8N_HOST=${DOMAIN_NAME}</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">WEBHOOK_URL=https://${DOMAIN_NAME}</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">N8N_SECURE_COOKIE=true</span>
</code></pre>
<p>  Here is the <strong>updated docker-compose.yml</strong> file:</p>
<pre><code class="lang-yaml">  <span class="hljs-attr">version:</span> <span class="hljs-string">'3.8'</span>
  <span class="hljs-attr">services:</span>
    <span class="hljs-attr">nginx:</span>
      <span class="hljs-attr">image:</span> <span class="hljs-string">nginx:alpine</span>
      <span class="hljs-attr">restart:</span> <span class="hljs-string">unless-stopped</span>
      <span class="hljs-attr">ports:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">"80:80"</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">"443:443"</span>
      <span class="hljs-attr">volumes:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">./nginx.conf:/etc/nginx/nginx.conf</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">./ssl:/etc/nginx/ssl</span>
      <span class="hljs-attr">depends_on:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">n8n</span>
    <span class="hljs-attr">postgres:</span>
      <span class="hljs-attr">image:</span> <span class="hljs-string">postgres:13</span>
      <span class="hljs-attr">restart:</span> <span class="hljs-string">unless-stopped</span>
      <span class="hljs-attr">environment:</span>
        <span class="hljs-attr">POSTGRES_DB:</span> <span class="hljs-string">${POSTGRES_DB}</span>
        <span class="hljs-attr">POSTGRES_USER:</span> <span class="hljs-string">${POSTGRES_USER}</span>
        <span class="hljs-attr">POSTGRES_PASSWORD:</span> <span class="hljs-string">${POSTGRES_PASSWORD}</span>
      <span class="hljs-attr">volumes:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">./postgres-data:/var/lib/postgresql/data</span>
      <span class="hljs-attr">healthcheck:</span>
        <span class="hljs-attr">test:</span> [<span class="hljs-string">'CMD-SHELL'</span>, <span class="hljs-string">'pg_isready -h localhost -U ${POSTGRES_USER} -d ${POSTGRES_DB}'</span>]
        <span class="hljs-attr">interval:</span> <span class="hljs-string">5s</span>
        <span class="hljs-attr">timeout:</span> <span class="hljs-string">5s</span>
        <span class="hljs-attr">retries:</span> <span class="hljs-number">10</span>
    <span class="hljs-attr">n8n:</span>
      <span class="hljs-attr">image:</span> <span class="hljs-string">n8nio/n8n</span>
      <span class="hljs-attr">restart:</span> <span class="hljs-string">unless-stopped</span>
      <span class="hljs-attr">extra_hosts:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">"host.docker.internal:host-gateway"</span>
      <span class="hljs-attr">environment:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">DB_TYPE=postgresdb</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">DB_POSTGRESDB_HOST=postgres</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">DB_POSTGRESDB_PORT=5432</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">DB_POSTGRESDB_DATABASE=${POSTGRES_DB}</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">DB_POSTGRESDB_USER=${POSTGRES_USER}</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">N8N_HOST=${DOMAIN_NAME}</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">WEBHOOK_URL=http://${DOMAIN_NAME}</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">N8N_BASIC_AUTH_ACTIVE=${N8N_BASIC_AUTH_ACTIVE}</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">N8N_BASIC_AUTH_USER=${N8N_BASIC_AUTH_USER}</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">N8N_BASIC_AUTH_PASSWORD=${N8N_BASIC_AUTH_PASSWORD}</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">GENERIC_TIMEZONE=${GENERIC_TIMEZONE}</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">N8N_RUNNERS_ENABLED=${N8N_RUNNERS_ENABLED}</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">N8N_PROXY_HOPS=1</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">N8N_SECURE_COOKIE=true</span>
      <span class="hljs-attr">volumes:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">./n8n-data:/home/node/.n8n</span>
      <span class="hljs-attr">depends_on:</span>
        <span class="hljs-attr">postgres:</span>
          <span class="hljs-attr">condition:</span> <span class="hljs-string">service_healthy</span>
</code></pre>
</li>
<li><p>Replace the whole <strong>nginx.conf</strong> with this new nginx.conf:</p>
<pre><code class="lang-nginx">  <span class="hljs-section">events</span> {
      <span class="hljs-attribute">worker_connections</span> <span class="hljs-number">1024</span>;
  }

  <span class="hljs-section">http</span> {
      <span class="hljs-attribute">upstream</span> n8n {
          <span class="hljs-attribute">server</span> n8n:<span class="hljs-number">5678</span>;
      }

      <span class="hljs-comment"># Redirect HTTP to HTTPS</span>
      <span class="hljs-section">server</span> {
          <span class="hljs-attribute">listen</span> <span class="hljs-number">80</span>;
          <span class="hljs-attribute">server_name</span> exp.tilakr.dev;
          <span class="hljs-attribute">return</span> <span class="hljs-number">301</span> https://<span class="hljs-variable">$server_name</span><span class="hljs-variable">$request_uri</span>;
      }

      <span class="hljs-comment"># HTTPS server</span>
      <span class="hljs-section">server</span> {
          <span class="hljs-attribute">listen</span> <span class="hljs-number">443</span> ssl;
          <span class="hljs-attribute">server_name</span> exp.tilakr.dev;

          <span class="hljs-attribute">ssl_certificate</span> /etc/nginx/ssl/fullchain.pem;
          <span class="hljs-attribute">ssl_certificate_key</span> /etc/nginx/ssl/privkey.pem;

          <span class="hljs-attribute">ssl_protocols</span> TLSv1.<span class="hljs-number">2</span> TLSv1.<span class="hljs-number">3</span>;
          <span class="hljs-attribute">ssl_ciphers</span> HIGH:!aNULL:!MD5;

          <span class="hljs-attribute">client_max_body_size</span> <span class="hljs-number">50M</span>;

          <span class="hljs-attribute">location</span> / {
              <span class="hljs-attribute">proxy_pass</span> http://n8n;
              <span class="hljs-attribute">proxy_set_header</span> Host <span class="hljs-variable">$host</span>;
              <span class="hljs-attribute">proxy_set_header</span> X-Real-IP <span class="hljs-variable">$remote_addr</span>;
              <span class="hljs-attribute">proxy_set_header</span> X-Forwarded-For <span class="hljs-variable">$proxy_add_x_forwarded_for</span>;
              <span class="hljs-attribute">proxy_set_header</span> X-Forwarded-Proto <span class="hljs-variable">$scheme</span>;

              <span class="hljs-comment"># To support websockets connection required for n8n</span>
              <span class="hljs-attribute">proxy_http_version</span> <span class="hljs-number">1</span>.<span class="hljs-number">1</span>;
              <span class="hljs-attribute">proxy_set_header</span> Upgrade <span class="hljs-variable">$http_upgrade</span>;
              <span class="hljs-attribute">proxy_set_header</span> Connection <span class="hljs-string">"upgrade"</span>;
          }
      }
  }
</code></pre>
</li>
<li><p>Install certbot and get SSL certificate:</p>
<pre><code class="lang-bash">  <span class="hljs-comment"># Stop the containers first</span>
  docker compose down

  <span class="hljs-comment"># Install Certbot</span>
  sudo apt update
  sudo apt install certbot -y

  <span class="hljs-comment"># Create SSL directory</span>
  mkdir -p ~/n8n-docker/ssl

  <span class="hljs-comment"># Get SSL certificate (replace with your email)</span>
  sudo certbot certonly --standalone \
    --email your-email@example.com \
    --agree-tos \
    --no-eff-email \
    -d exp.tilakr.dev

  <span class="hljs-comment"># Copy certificates to your project directory</span>
  sudo cp /etc/letsencrypt/live/exp.tilakr.dev/fullchain.pem ~/n8n-docker/ssl/
  sudo cp /etc/letsencrypt/live/exp.tilakr.dev/privkey.pem ~/n8n-docker/ssl/
  sudo chown <span class="hljs-variable">$USER</span>:<span class="hljs-variable">$USER</span> ~/n8n-docker/ssl/*

  <span class="hljs-comment"># Start the containers</span>
  <span class="hljs-built_in">cd</span> ~/n8n-docker
  docker compose up -d
</code></pre>
</li>
<li><p>Setup automatic certificate renewal:</p>
<pre><code class="lang-bash">  <span class="hljs-comment"># Edit crontab</span>
  crontab -e

  <span class="hljs-comment"># Add this line to renew certificates automatically:</span>
  0 3 * * * sudo certbot renew --quiet &amp;&amp; sudo cp /etc/letsencrypt/live/exp.tilakr.dev/*.pem ~/n8n-docker/ssl/ &amp;&amp; sudo chown <span class="hljs-variable">$USER</span>:<span class="hljs-variable">$USER</span> ~/n8n-docker/ssl/* &amp;&amp; <span class="hljs-built_in">cd</span> ~/n8n-docker &amp;&amp; docker compose restart nginx
</code></pre>
</li>
</ul>
<h3 id="heading-important">Important:</h3>
<p>Remember to edit the IPV4 firewall for your lightsail instance and add a new rule for port 443 (https), else you won't be able to access through HTTPS.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754930029830/2a986375-6b56-4da8-8199-8b4d2cab4cd7.png" alt class="image--center mx-auto" /></p>
<p>You can now visit https://DOMAIN_NAME (DOMAIN_NAME is the one you registered in your DNS to point to the IP of the instance).</p>
<p>Congratulations 🎉, you just setup a remote n8n in aws which you can access over HTTPs.</p>
<h2 id="heading-cloudflare-extra-security-optional">Cloudflare extra security (Optional)</h2>
<p>You can also use cloudflare as an extra layer of added security. You can follow the steps below to setup cloudflare:</p>
<ol>
<li><h3 id="heading-add-your-domain-to-cloudflare">Add your domain to cloudflare</h3>
<p> - Sign up / Log in into cloudflare account.</p>
<p> - Click “Add a site“</p>
<p> - Enter your domain and select free plan.</p>
</li>
<li><h3 id="heading-dns-record-import">DNS record import</h3>
<p> - Cloudflare will automatically import your dns records</p>
<p> - <strong>Important :</strong> Check if your your A record pointing to your lightsail ip is there or not with proxy enabled (orange cloud)</p>
</li>
<li><h3 id="heading-update-nameservers">Update nameservers</h3>
<p> - Update the nameservers in your domain manager with the nameservers provided by the cloudflare.</p>
<p> - The propagation could take upto 48 hours</p>
</li>
<li><h3 id="heading-security-optimizations">Security optimizations</h3>
<p> - In cloudflare dashboard → SSL/TLS → Overview, set encryption mode to <strong>Full(Strict)</strong></p>
<p> - Go to security section → set <strong>Security Level:</strong> Medium, <strong>Bot Fight Mode:</strong> On</p>
</li>
</ol>
<p>You have just added cloudflare as an extra layer of security for your setup.</p>
<h2 id="heading-firewall-considerations-optional">Firewall considerations (Optional)</h2>
<p>You can add/modify firewall settings for further better security.</p>
<p>For example ssh is open for all IPs by default. Althrough it requires ssh keys to connect to the instance, you can further restrict the ssh by setting port 22 to only be accessible to a specific IP or a range of IPs.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755114442455/5d23c90b-b378-417e-89e4-14c4ea37bcac.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-important-1">Important :</h3>
<p>Idle static IPs are subject to charge. Until a static IP is connected to an instance, it is free but as soon as you delete the instance or by any means detach the static IP and it becomes idle it will be charged. So it is better to just delete any idle static IPs to avoid any <strong>surprise charge!!</strong></p>
<p>So you have just setup your n8n application which you could access through HTTPs connection. You can have unlimited executions and your data is also secured. Enjoy creating some amazing automations 🤖🤖 .</p>
]]></content:encoded></item></channel></rss>