DEV Community

Cover image for Deploying Single Page Application (SPA) or Static Site Generation (SSG) with Nginx
Muhammad Ilyasa Fadhlih
Muhammad Ilyasa Fadhlih

Posted on

Deploying Single Page Application (SPA) or Static Site Generation (SSG) with Nginx

Today, I'm going to share a way to deploy single page application or SPA with Nginx. This is a common way to deploy your frontend especially when you work for a small company or startup.

What's SPA?

Single Page Application (SPA) usually refers to frontend, the web app that only consist of a single HTML page (index.html) but with many javascript scripts. It works by modifies the DOM elements inside it with JavaScript, could be removing, adding and changing HTML elements.

This is great for user interactivity but not so good for Search Engine Optimizations or SEO (how likely it is for your web app to be shown when you search it up on Google or any other search engines) as most of web crawlers don't execute JavaScript, so it only saw that empty index.html with the title and empty root element <div id="root"></div>.

If you really want to have good SEO for your app, you might need to consider using Server-Side Rendering (SSR) instead, or Static Site Generator (SSG). Thanks to the community we can now have many options of web frameworks that support SSG and SSR while still able to use your favorite stack.

How do I know, if I'm using SPA/SSG?

Well, if you use React or Vue and Vite as a bundler, then you could say that you already use SPA or SSG, you can see the final output inside the dist/ directory after executing the build command npm run build.
The good thing about this is your app has small in size, and it is portable, you just need the dist/ directory to deploy your app, you don't need the fat node_modules/ or src/ directory anymore, just the dist/ and you're good to deploy.

The other thing about SPA and SSG is you don't need a server running to make your web works. Well, you still need a server to serve the request from users, but your server doesn't execute the JavaScript, the client (user's browser) does. This is making it possible to deploy them as static files at edge using Content Delivery Network (CDN) for faster retrieval time.

Prerequisites

First thing you need to have the frontend ready, I mean you don't want to deploy a broken site and hoping people don't see it, right?

Second thing you need is a server. A server is basically just a computer, but always active 24/7, doesn't have keyboard, mouse or monitor, just the thing to do computations, you just need to rent them from a hosting provider. Although it's possible to build your own server.

Server be like

You need a server to make your website accessible to public. Usually, you could just upload your dist/ directory to a CDN service like Cloudflare CDN or AWS CloudFront + S3, but that's not what we're going to do today. We're going to use a self-managed server, which still going to cost you some money.

If you can't afford a server just yet, it's fine, you can still run it from your computer, but it won't be accessible to public. Some cloud providers also offer free tier.

Third thing is a domain (optional). Domain is like this: www.example.com. When you purchase a server, it doesn't usually come with the domain. You can access it, but only through the IP address of that server.

Getting Started

Before we dive into the steps, let me show you a map to give you a clear picture about what we're trying to achieve.

Procedure

  1. Step 1 is building the project, with npm run build, done.
  2. Now we go to the 2nd step, copy the build files (dist directory) into the server.

    You can do this with multiple ways, but I'm going to use sftp here, you need to have ssh access first to the server before being able to use sftp.

    SSH File Transfer Protocol, also known as Secure File Transfer Protocol (SFTP), is a network protocol that provides file access, file transfer, and file management over any reliable data stream. Source: wikipedia

    Using sftp to transfer file, let's say I have dist/ directory in the /home/yasa/frontend/dist/ and I'm going to put the files in the server user directory as myfiles/ (/home/ubuntu/myfiles/):

    1. Using SFTP is like using SSH:
    # Connect sftp
    sftp -i "./Downloads/demopurpose.pem" ubuntu@98.81.71.240
    Connected to 98.81.71.240.
    
    # Print current server working directory
    sftp> pwd
    Remote working directory: /home/ubuntu
    
    # Upload directory to server with "put -r"
    sftp> put -r /home/yasa/frontend/dist/ myfiles
    Uploading /home/yasa/frontend/dist/ to /home/ubuntu/myfiles
    Entering /home/yasa/frontend/dist/vite.svg
    100% 1497 2.5KB/s 00:00    
    Entering /home/yasa/frontend/dist/assets
    index-CwjKBBbM.js 
    100% 96KB 72.9KB/s 00:01    
    index-CtZswya4.css
    100% 15KB  53.6KB/s 00:00    
    index.html
    100% 457 0.8KB/s 00:00    
    
    # Quit connection
    sftp> quit
    

    Now I have successfully uploaded the files to the server.

  3. Install & Configure Nginx

    Now you have the files on the server, the next step is to install and configure the web server to serve those files to the user. There are many options for web server, but I'm going to use Nginx because it's the most popular, open source and insanely fast too!

    Install Nginx:
    Installing Nginx is pretty straightforward in most linux distros, here I'm using ubuntu on the server:

    # Login to server
    ssh -i "./Downloads/demopurpose.pem" ubuntu@98.81.71.240
    
    # Update cache
    sudo apt update 
    
    # Install nginx
    sudo apt install -y nginx
    
    # Check if nginx service is running
    sudo systemctl status nginx
    
    # Start service if it's not
    sudo systemctl start nginx
    
    # (Optional) Auto start on system reboot
    sudo systemctl enable nginx
    

    Installing done! Just need to configure.

    Configure Nginx:

    These are what we have so far:

    • dist/ directory at server /home/ubuntu/myfiles/
    • nginx installed on the server

    Now, if nginx installed correctly, you should be able to see the nginx default webpage through the browser, type your Server IP in the browser:

    Browser shows default nginx page

    It might not show if you have firewall blocking the http port. See how to configure firewall below.

    We have to configure it to show our page instead of the default page:

    1. You can see the default configuration at /etc/nginx/sites-available/default or /etc/nginx/conf.d/default.conf.

      # or cat /etc/nginx/sites-available/default
      cat /etc/nginx/conf.d/default.conf
      

      Probably look like this:

      server {
          listen       80;
          server_name  localhost;
      
          location / {
              root   /usr/share/nginx/html;
              index  index.html index.htm;
          }
      }
      

      It's pretty easy to read right?

      server {
          # listening on port 80, standard http server.
          listen       80; 
      
          # you can set it according to your domain (after you do domain registration), 
          # usually when you have multiple domains pointing to this server ip.
          server_name  localhost; 
      
          # url location
          location / {
              # root directory
              root   /usr/share/nginx/html;
      
              # automatically looking for index.html or index.htm if not specified in the url.
              index  index.html index.htm;
          }
      }
      

      First, you can see the root is in /usr/share/nginx/html or sometimes var/www/html.

      root   /usr/share/nginx/html;
      

      You can do it in two ways:

      1. Move the dist/ to that directory.

        mv /path/to/dist /usr/share/nginx/html; 
        # or /var/www/html depending on your "root" in the nginx configuration
        
      2. Change the configuration root.

        root   /path/to/your/dist;
        

        I'm usually sticking with the default, so I'm going to leave it as is and move my dist/ to the default directory instead.

        mv /home/ubuntu/myfiles /usr/share/nginx/html
        

        And then I'm going to add this line in the nginx configuration:

        # First attempt to serve request as file, then
        # as directory, as url, then fall back to displaying a 404.
        try_files $uri $uri/ / =404;
        

        Edit the configuration file with nano:

        sudo nano /etc/nginx/conf.d/default.conf
        

        It's going to look like this:

        server {
            listen       80;
            server_name  localhost;
        
            # other config  ...
        
            location / {
                root   /usr/share/nginx/html;
                index  index.html index.htm;
                try_files $uri $uri/ / =404; # Added this line
            }
        
            # other config ...
        }
        
  4. Configure firewall.

    Firewall is a network security system that monitors and controls incoming and outgoing network traffic based on configurable security rules. (Source: wikipedia)

    There are multiple firewalls available, iptables and nftables are usually the built in firewall in linux, so you don't need to install anything, but it is quite low level and not easy to work with. So, I'm going to use the higher level ones, ufw and firewall-cmd respectively. You should only use either of them not both.

    ufw (unclomplicated firewall):
    This is typically the firewall most Ubuntu user use.

    Install ufw (if you haven't):

    sudo apt update
    sudo apt install -y ufw
    

    Enable the firewall:

    1. Allowing ssh port (important!):

      Make sure you're allowing the ssh port first before enabling the firewall (it can lock you out of the system). Do as follows:

      sudo ufw allow ssh
      # or sudo ufw allow 22/tcp
      
      sudo ufw enable
      
    2. Check firewall status:

      sudo ufw status
      
      # example output:
      Status: active
      
      To                         Action      From
      --                         ------      ----
      22/tcp                     ALLOW       Anywhere                  
      22/tcp (v6)                ALLOW       Anywhere (v6)             
      

      In this step you shouldn't be able to access your server through the browser anymore because there is no firewall rule to allow http port, we're going to allow that in the next step.

    3. Allowing HTTP port:

      sudo ufw allow http
      # and allow "https" if necessary
      
      sudo ufw status
      # example output
      Status: active
      
      To                         Action      From
      --                         ------      ----
      22/tcp                     ALLOW       Anywhere                  
      80/tcp                     ALLOW       Anywhere                                
      22/tcp (v6)                ALLOW       Anywhere (v6)             
      80/tcp (v6)                ALLOW       Anywhere (v6)                     
      
      

      Now you can access your web again in the browser.

    firewalld:
    Firewalld is usually being used in Red Hat linux distributions, I personally like this more than ufw.

    Install, start and enable on start firewalld:

    sudo dnf update
    sudo dnf install -y firewalld
    
    sudo systemctl start firewalld
    sudo systemctl enable firewalld
    

    SSH port is usually allowed by default.

    Allow HTTP port:

    # Permanent rule will stay upon restart
    sudo firewall-cmd --permanent --add-service=http
    
    # Permanent config need to reload
    sudo firewall-cmd --reload
    
    # Check if http service has been allowed
    sudo firewall-cmd --list-services
    

    Now, you could access your web app in the browser once again.

Next step

There are more steps you need to do, but I'm not going to cover them in this article, here are some of them:

  • Registering domain for your server.
  • Allow port 443 (HTTPS) in the firewall configuration.
  • Configuring TLS (after domain registration).
  • And many more.

Conclusion

Deploying frontend app (SPA/SSG) in the server is quite easy with Nginx. You could utilize tools like SFTP to transfer the files to your server, and use UFW/firewall-cmd to easily configure the firewall.

Top comments (0)