// Tutorial //

How To Deploy a React Application with Nginx on Ubuntu 20.04

Published on December 18, 2020 · Updated on June 14, 2022
Default avatar
By Joe Morgan
Developer and author at DigitalOcean.
How To Deploy a React Application with Nginx on Ubuntu 20.04

The author selected Creative Commons to receive a donation as part of the Write for DOnations program.


You can quickly deploy React applications to a server using the default Create React App build tool. The build script compiles the application into a single directory containing all of the JavaScript code, images, styles, and HTML files. With the assets in a single location, you can deploy to a web server with minimal configuration.

In this tutorial, you’ll deploy a React application on your local machine to an Ubuntu 20.04 server running Nginx. You’ll build an application using Create React App, use an Nginx config file to determine where to deploy files, and securely copy the build directory and its contents to the server. By the end of this tutorial, you’ll be able to build and deploy a React application.


Step 1 — Creating a React Project

In this step, you’ll create an application using Create React App and build a deployable version of the boilerplate app.

To start, create a new application using Create React App in your local environment. In a terminal, run the command to build an application. In this tutorial, the project will be called react-deploy:

  1. npx create-react-app react-deploy

The npx command will run a Node package without downloading it to your machine. The create-react-app script will install all of the dependencies needed for your React app and will build a base project in the react-deploy directory. For more on Create React App, check out out the tutorial How To Set Up a React Project with Create React App.

The code will run for a few minutes as it downloads and installs the dependencies. When it is complete, you will receive a success message. Your version may be slightly different if you use yarn instead of npm:

Success! Created react-deploy at your_file_path/react-deploy Inside that directory, you can run several commands: npm start Starts the development server. npm build Bundles the app into static files for production. npm test Starts the test runner. npm eject Removes this tool and copies build dependencies, configuration files and scripts into the app directory. If you do this, you can’t go back! We suggest that you begin by typing: cd react-deploy npm start Happy hacking!

Following the suggestion in the output, first move into the project folder:

  1. cd react-deploy

Now that you have a base project, run it locally to test how it will appear on the server. Run the project using the npm start script:

  1. npm start

When the command runs, you’ll receive output with the local server info:

Compiled successfully! You can now view react-deploy in the browser. Local: http://localhost:3000 On Your Network: Note that the development build is not optimized. To create a production build, use npm build.

Open a browser and navigate to http://localhost:3000. You will be able to access the boilerplate React app:

React project template running locally

Stop the project by entering either CTRL+C or ⌘+C in a terminal.

Now that you have a project that runs successfully in a browser, you need to create a production build. Run the create-react-app build script with the following:

  1. npm run build

This command will compile the JavaScript and assets into the build directory. When the command finishes, you will receive some output with data about your build. Notice that the filenames include a hash, so your output will be slightly different:

Creating an optimized production build... Compiled successfully. File sizes after gzip: 41.21 KB build/static/js/2.82f639e7.chunk.js 1.4 KB build/static/js/3.9fbaa076.chunk.js 1.17 KB build/static/js/runtime-main.1caef30b.js 593 B build/static/js/main.e8c17c7d.chunk.js 546 B build/static/css/main.ab7136cd.chunk.css The project was built assuming it is hosted at /. You can control this with the homepage field in your package.json. The build folder is ready to be deployed. You may serve it with a static server: serve -s build Find out more about deployment here: https://cra.link/deployment

The build directory will now include compiled and minified versions of all the files you need for your project. At this point, you don’t need to worry about anything outside of the build directory. All you need to do is deploy the directory to a server.

In this step, you created a new React application. You verified that the application runs locally and you built a production version using the Create React App build script. In the next step, you’ll log onto your server to learn where to copy the build directory.

Step 2 — Determining Deployment File Location on your Ubuntu Server

In this step, you’ll start to deploy your React application to a server. But before you can upload the files, you’ll need to determine the correct file location on your deployment server. This tutorial uses Nginx as a web server, but the approach is the same with Apache. The main difference is that the configuration files will be in a different directory.

To find the directory the web server will use as the root for your project, log in to your server using ssh:

  1. ssh username@server_ip

Once on the server, look for your web server configuration in /etc/nginx/sites-enabled. There is also a directory called sites-allowed; this directory includes configurations that are not necessarily activated. Once you find the configuration file, display the output in your terminal with the following command:

  1. cat /etc/nginx/sites-enabled/your_domain

If your site has no HTTPS certificate, you will receive a result similar to this:

server { listen 80; listen [::]:80; root /var/www/your_domain/html; index index.html index.htm index.nginx-debian.html; server_name your_domain www.your_domain; location / { try_files $uri $uri/ =404; } }

If you followed the Let’s Encrypt prerequisite to secure your Ubuntu 20.04 server, you will receive this output:

server { root /var/www/your_domain/html; index index.html index.htm index.nginx-debian.html; server_name your_domain www.your_domain; location / { try_files $uri $uri/ =404; } listen [::]:443 ssl ipv6only=on; # managed by Certbot listen 443 ssl; # managed by Certbot ssl_certificate /etc/letsencrypt/live/your_domain/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/your_domain/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot } server { if ($host = www.your_domain) { return 301 https://$host$request_uri; } # managed by Certbot if ($host = your_domain) { return 301 https://$host$request_uri; } # managed by Certbot listen 80; listen [::]:80; server_name your_domain www.your_domain; return 404; # managed by Certbot }

In either case, the most important field for deploying your React app is root. This points HTTP requests to the /var/www/your_domain/html directory. That means you will copy your files to that location. In the next line, you can see that Nginx will look for an index.html file. If you look in your local build directory, you will see an index.html file that will serve as the main entry point.

Log off the Ubuntu 20.04 server and go back to your local development environment.

Now that you know the file location that Nginx will serve, you can upload your build.

Step 3 — Uploading Build Files with scp

At this point, your build files are ready to go. All you need to do is copy them to the server. A quick way to do this is to use scp to copy your files to the correct location. The scp command is a secure way to copy files to a remote server from a terminal. The command uses your ssh key if it is configured. Otherwise, you will be prompted for a username and password.

The command format will be scp files_to_copy username@server_ip:path_on_server. The first argument will be the files you want to copy. In this case, you are copying all of the files in the build directory. The second argument is a combination of your credentials and the destination path. The destination path will be the same as the root in your Nginx config: /var/www/your_domain/html.

Copy all the build files using the * wildcard to /var/www/your_domain/html:

  1. scp -r ./build/* username@server_ip:/var/www/your_domain/html

When you run the command, you will receive output showing that your files are uploaded. Your results will be slightly different:

asset-manifest.json 100% 1092 22.0KB/s 00:00 favicon.ico 100% 3870 80.5KB/s 00:00 index.html 100% 3032 61.1KB/s 00:00 logo192.png 100% 5347 59.9KB/s 00:00 logo512.png 100% 9664 69.5KB/s 00:00 manifest.json 100% 492 10.4KB/s 00:00 robots.txt 100% 67 1.0KB/s 00:00 main.ab7136cd.chunk.css 100% 943 20.8KB/s 00:00 main.ab7136cd.chunk.css.map 100% 1490 31.2KB/s 00:00 runtime-main.1caef30b.js.map 100% 12KB 90.3KB/s 00:00 3.9fbaa076.chunk.js 100% 3561 67.2KB/s 00:00 2.82f639e7.chunk.js.map 100% 313KB 156.1KB/s 00:02 runtime-main.1caef30b.js 100% 2372 45.8KB/s 00:00 main.e8c17c7d.chunk.js.map 100% 2436 50.9KB/s 00:00 3.9fbaa076.chunk.js.map 100% 7690 146.7KB/s 00:00 2.82f639e7.chunk.js 100% 128KB 226.5KB/s 00:00 2.82f639e7.chunk.js.LICENSE.txt 100% 1043 21.6KB/s 00:00 main.e8c17c7d.chunk.js 100% 1045 21.7KB/s 00:00 logo.103b5fa1.svg 100% 2671 56.8KB/s 00:00

When the command completes, you are finished. Since a React project is built of static files that only need a browser, you don’t have to configure any further server-side language. Open a browser and navigate to your domain name. When you do, you will find your React project:

Browser with React Project on Server

In this step, you deployed a React application to a server. You learned how to identify the root web directory on your server and you copied the files with scp. When the files finished uploading, you were able to view your project in a web browser.


Deploying React applications is a quick process when you use Create React App. You run the build command to create a directory of all the files you need for a deployment. After running the build, you copy the files to the correct location on the server, pushing your application live to the web.

If you would like to read more React tutorials, check out our React Topic page, or return to the How To Code in React.js series page.

Want to deploy your application quickly? Try Cloudways, the #1 managed hosting provider for small-to-medium businesses, agencies, and developers - for free. DigitalOcean and Cloudways together will give you a reliable, scalable, and hassle-free managed hosting experience with anytime support that makes all your hosting worries a thing of the past. Start with $100 in free credits!

Learn more here

Tutorial Series: How To Code in React.js

React is a popular JavaScript framework for creating front-end applications, such as user interfaces that allow users to interact with programs. Originally created by Facebook, it has gained popularity by allowing developers to create fast applications using an intuitive programming paradigm that ties JavaScript with an HTML-like syntax known as JSX.

In this series, you will build out examples of React projects to gain an understanding of this framework, giving you the knowledge you need to pursue front-end web development or start out on your way to full stack development.

About the authors
Default avatar
Developer and author at DigitalOcean.

Default avatar
Senior Technical Editor

Editor at DigitalOcean, fiction writer and podcaster elsewhere, always searching for the next good nautical pun!

Still looking for an answer?

Was this helpful?

This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

I agree with @epichtchalnikov’s comment that this series has been incredibly helpful, and it’d be a sad if the author didn’t (if they haven’t already) realize the extent of this success:

People get DO platforms to solve thier problems – and while getting a droplet is relatively straight-forward and even UI-backed, their “journey” from that point onwards may not be, which is why they have to Google for hours, and eventually get stuck.

This series managed to changed that! Given the standardized DO Op. systems, the author(s) managed to pipeline that was easy enough to follow, easy enough to teach things along the way, and to look for recourse if you messed up a step. Usually, it was evident which step I’d messed up and what I needed to do to fix things from that point onwards.

At the end of it, I – at the very least – feel that I’ve learned much more than I expected and feel far more comfortable/confident than I did a while ago. I’d love for you guys to write more – and even to help should you guys need it!

This comment has been deleted

I had a problem with page refresh and 404 return and such excerpt of nginx.conf for location and redirect to index.html resolved it.

location / {
    root /usr/share/nginx/html;
    index index.html index.htm;
    try_files $uri $uri/ /index.html =404;

This comment has been deleted

I followed this guide but when i navigate to my domain I get a 502 Bad Gateway error.

I have previously set up a node.js application using this tutorial (https://www.digitalocean.com/community/tutorials/how-to-set-up-a-node-js-application-for-production-on-ubuntu-20-04) but when I try to stop that pm2 process, i get the same error.

Have I missed something?

Hello, I followed this tutorial. But routes not working, sub page can’t access. ex: your_domain/about or your_domain/contact with error: 404 Not Found.

I found some similar topics but they do it with the App Platform not with Droplets

I have found this article very useful just one question, it this the best practice for deploying react apps? Is there an option where (on updating the react page) you use git instead of npm run build?

Thanks in advantage

I just written a long detailed comment about how i like this series of articles, and then digital ocean asked me to log in, and i expected that it will save my comment, but it actually didn’t… In a nutshell, these cross-linked articles are just awesome, you’re doing the right thing, thank you, Joe, and other authors.