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.
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.
- Step 1 is building the project, with
npm run build, done. -
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
sftphere, you need to havesshaccess 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
sftpto transfer file, let's say I havedist/directory in the/home/yasa/frontend/dist/and I'm going to put the files in the server user directory asmyfiles/(/home/ubuntu/myfiles/):- 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> quitNow I have successfully uploaded the files to the server.
-
Install & Configure Nginx
Now you have the files on the server, the next step is to install and configure the
web servertoservethose files to the user. There are many options for web server, but I'm going to useNginxbecause 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 nginxInstalling 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:
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:
-
You can see the default configuration at
/etc/nginx/sites-available/defaultor/etc/nginx/conf.d/default.conf.
# or cat /etc/nginx/sites-available/default cat /etc/nginx/conf.d/default.confProbably 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/htmlor sometimesvar/www/html.
root /usr/share/nginx/html;You can do it in two ways:
-
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 -
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/htmlAnd 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.confIt'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 ... }
-
-
-
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,
iptablesandnftablesare 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,ufwandfirewall-cmdrespectively. 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 ufwEnable the firewall:
-
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 -
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.
-
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 thanufw.Install, start and enable on start
firewalld:
sudo dnf update sudo dnf install -y firewalld sudo systemctl start firewalld sudo systemctl enable firewalldSSH 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-servicesNow, 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)