Hey there! Welcome to Hostman! 🎉

Deploy a React App

06.12.2023
Reading time: 8 min
Hostman Team
Technical writer

Sooner or later, software developers face the task of automatically deploying projects to a remote host. They also often use cloud servers because they're easy to scale. In this article, we will learn how to deploy React applications to web hosting or a cloud server and also review deployment using an archive.

Getting ready

We will need GitLab hosting with access for developers as users (without a secure SSH channel), a React project with regular updates, FTP support, and domain hosting. We'll also need a Node.js platform and a compiled project on a production computer. As soon as there are any changes in the repository, we should: 

  1. Compile React source code with the Node.js functionality.

  2. Clean the hosting from old information.

  3. Copy the newly compiled data there.

Git Hooks

You can check git hooks with the terminal command: 

git help hooks

Git hooks can be client and server hooks. The former are executed on the user's computer and the latter on the host. The client-side ones are located at .git/hooks. For any of them to function, you need to remove the .sample file. In our case, the pre-push will work to organize the auto-update of the repository, which is triggered before the start of copying information to the remote host.

In GitLab, server-side hooks are called WebHooks. They are used, for example, when a request like a repository update comes in and is sent to a given HTTP address. This approach simplifies tracking the events inside the project and allows you to handle them promptly when deploying applications.

Deploying the project to web hosting

The web-hosting functionality allows you to implement the following:

  1. Start a pre-push hook that activates React project processing. It will create a repository and then copy the finished product to GitLab, where we'll store it in compiled form.

  2. Set up WebHook, which calls a script from the host to create a copy of the repository to a user-specified location (the result will be a web portal update).

To connect to the repository, we'll use a login and password. Below, we will use this method of authentication as a basic one. Let's move on to creating a repository for the React project. For this purpose, we will generate a build.bash file in the source directory, and fill it with the following content:

#!/bin/sh
cd /var/www/html/my-app/
npm run-script build
cd /var/www/html/my-app/build/
git init
git add .
git commit -m 'build'
git push -f --set-upstream https://login:password@git.address.domain/my-app-build.git master

This list of commands will allow you to go to the React project directory, start compilation, and then return to the build folder and create a local repository. As a result, you will copy the build to a remote host with a forced overwriting of the repository information.

Now go to the .git/hooks directory and create a pre-push there, inserting the following content in it:

#!/bin/sh
nohup /var/www/html/my-app/build.bash &

The & symbol in the nohup command hides the terminal output. In our case, version control does not work, so when we rewrite the repository, we'll erase all the previously made and deleted comments. The created repository works as a "reaction point" necessary for the final stage of React application deployment. Let's finalize the procedure by converting both files into executable files:

chmod 775 /var/www/html/my-app/build.bash /var/www/html/my-app/.git/hooks/pre-push

When generating a WebHook for a project on GitLab, let's set a URL script, a secret token identifying the source, and mark push. Let's also write a PHP script to place in the web hosting root folder. Let's call it _deploy-client.php and include the following code:

//write information about the last request to the test file
file_put_contents(dirname(__FILE__)."/".basename(__FILE__, ".php").".txt", print_r($_SERVER, true));
//check that the request came from the right git host and that the token is correct
if($_SERVER["REMOTE_ADDR"] != "xxx.xxx.xxx.xxx.xxx" || $_SERVER["HTTP_X_GITLAB_TOKEN"] != "sdf51s65dg1sd31fs3df1w6rg")
    exit();
//if the script has reached this point, it can be deployed
//directory to copy to
$sDir = dirname(__FILE__)."/client";
//delete old build version
shell_exec("rm -rf $sDir/* $sDir/.[^.]*");
//clone repository with build to the correct directory
shell_exec("git clone https://login:password@git.address.domain/my-app-build.git $sDir/");

Deploying with an archive

Using this option, we will replace the build repository with an archive. All you have to do is fix the contents of the build.bash file:

#!/bin/sh
cd /var/www/html/tilda.local/htdocs/my-app/
npm run-script build
cd build
zip -r build.zip *
curl --data-binary @build.zip https://domain.zone/__deploy/client.php?token=token

In our example, we have specified the archive format as ZIP. We also need to modify the web-hosting deploy script slightly:

//write information about the last request into the file
file_put_contents(dirname(__FILE__)."/".basename(__FILE__, ".php").".txt", print_r($_SERVER, true).print_r($_FILES, true));
//check tokens
if($_GET["token"] != "token")
    exit();
//file to write POST data to (archive is there)
file_put_contents(dirname(__FILE__)."/build.zip", file_get_contents('php://input'));
//directory to deploy to
$sDir = $_SERVER["DOCUMENT_ROOT"]."/client";
//delete everything from the directory
shell_exec("rm -rf $sDir/* $sDir/.[^.]*");
//unpack the archive into the directory
shell_exec("unzip -d $sDir/ build.zip ");

When using the post-commit hook, you can deploy the React app without a git server.

-

Deploying React applications to a VPS

As with web hosting, we will need a React project, which we will deploy to a virtual machine. For example, let's create a new application in the local environment:

npx create-react-app react-deploy

The command runs the Node package without downloading it to the computer. The create-react-app script installs all the necessary dependencies and creates a project in the react-deploy directory. This procedure will take a few minutes to complete. The system will display the result on the screen:

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!

Once we create the project, we should convert it into a production build. 

npm run build

It will compile JavaScript and assets into the build directory, containing compiled and minimized versions of all the project files. 

Files location on an Ubuntu server

We will rent a virtual machine VPS with a pre-installed Ubuntu operating system. Next, we'll install the Nginx web server and manually specify where to store the deployed project files. 

First, let's determine the default root directory. To do this, connect to the remote host via a secure SSH channel:

ssh username@server_ip

Now let's check the configuration file's contents:

cat /etc/nginx/sites-enabled/your_domain

If there is no SSL certificate, we will see roughly the following output:

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;
        }
}

Check the line starting with root. This is the path to store the project files after deployment.

Uploading the build with SCP

The scp command is one of the safest ways to transfer project files to a virtual machine. If you have a configured SSH key, it will use it by default. Otherwise, the system will prompt you to enter a login and password. To copy all the files, use the * symbol:

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

The command displays the copied files' names, the progress percentage, and the transfer speed. 

Example: 

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

Our test project consists of static files, so installing and configuring any compiler on the server is unnecessary. Everything will work with browser functionality. Let's open a browser and enter the IP address of the server or its domain name. If everything works correctly, we should see our app. 

Conclusion

We reviewed how to auto-deploy a React application to a virtual machine and web hosting, including deploying with an archive. You can try it out on the Hostman servers, separately from your working hosts. It is important to note that we compile on the developer's computer.