Deploying and configuring a DigitalOcean Droplet to host server side rendered web applications.

Reid JS
9 min readFeb 4, 2020

Avoid getting locked in to expensive cloud application platforms like Heroku, Now, and Netlify.

The Problem

I run a low margin service online that requires serving multiple web applications. I’ve surpassed the free tiers of Heroku, Now, and Netlify, but I don’t have enough time or customers to warrant setting up Docker Swarm or Kubernetes. What deployment strategy sits in between cloud based web application providers for novices and enterprise scale container orchestration?

The Solution

Deploy a cloud hosted server like a DigitalOcean droplet, configure a Nginx or Apache webserver, and render your web application(s) from the remote server.

Benefits

  • This approach scales. Nginx and Apache are enterprise grade battle-tested webserver software. They readily serve as a reverse proxy for load balancing and caching if needed.
  • Your web applications load fast. Websites that are server side rendered (SSR) tend to load significantly faster than those rendered client side as explained in this article.
  • Hosting is cheap and low maintenance. All software used in this project is free and open source. The only costs are cloud hosting and registering a domain name.

This is a great solution if…

  • You are building a service that has already or will extend past the free version of cloud based web application providers like Heroku, Now, or Netlify.
  • You want or need more control over your hosting and build environment.
  • You want to build and deploy updates to your web application(s) faster than cloud providers can provide for free.
  • You want an extensible web application stack entirely composed of free and open source software.

This is not a great solution if…

  • You need a really quick one-click deployment solution for a hackathon project or proof of concept.
  • You don’t need your web application to serve many users concurrently.
  • You can’t live without the github integrations provided by Heroku, Now, or Netlify.
  • You are running an enterprise grade application and need to support more than tens of thousands of requests per second.

Price

The only costs are cloud hosting your server and registering a domain name. I deployed a DigitalOcean droplet ($5/month) because I love their documentation and web interface. If this price is a concern consider deploying with AWS, GCP, or your own local server. If you aren’t satisfied with this solution, delete your droplet within 24 hours to avoid paying a fee.

Time Cost

Set up takes approximately 1–2 hours for an experienced engineer. The longest part is deploying the droplet and setting up the webserver. Fortunately, once you configure the webserver you can deploy as many websites and subdomains as you want very quickly.

Prerequisites

Many steps require configuring a remote webserver, which involves working from your terminal. Therefore, it helps to be comfortable using text editors like nano or vim and know common unix commands like cd, ls, cp, and rsync. If this scares you, consider this a good opportunity to learn some new skills!

Let’s do it!

Don’t feel compelled to do all of this at once, but after starting a step I recommend completing it entirely to avoid partial configuration issues.

  1. Deploy cloud hosted server (30m, $5/month)
  2. Configure your cloud hosted server (10m)
  3. Install and configure your webserver (30m)
  4. Get domain name and configure nameservers (5m, $1–10/year)
  5. Set up A records (5m)
  6. Create a web application and deploy script (20m)
  7. Add SSL/TLS (https) for free (optional, 15m)

These time estimates are for an experienced engineer. Don’t get discouraged if they take longer, especially if you are new to navigating a remote server from your terminal.

Step 1. Deploy cloud hosted server (20m)

I chose to deploy a DigitalOcean droplet because of their excellent documentation and browser interface. An AWS EC2 or the GCP equivalent are also valid choices.

  1. Go to https://www.digitalocean.com/
  2. Sign up in the Deploy in Secondsbox, or sign in if you already have an account.
  3. Confirm your email.
  4. Sign in and set up your payment type. You will need a valid credit or debit card, or PayPal account.
  5. You should see a Welcome form to Create Your Project.
  6. Enter a name and select a purpose from the dropdown. In the tools section you can select Nginx and React, but I believe you can get away with leaving this blank if you prefer.
  7. Click the Start button to enter your DigitalOcean dashboard.
  8. Click the New Droplet button and select the default Ubuntu 18.04.3 (LTS) x64 distribution.
  9. Select the default Standard Starter Plan and click the left arrow on the selection area to find the $5/month droplet all the way to the left.
  10. Choose the datacenter region nearest to where you live.
  11. For authentication, select SSH Keys (a more secure authentication method).
  12. Click New SSH Key and follow the steps to the right to copy your public key into the droplet. If your computer already has a key, in a terminal run: cat ~/.ssh/id_rsa.pub
  13. Copy the terminal output (it should start with “ssh-rsa”) and paste it into the text area.
  14. Leave everything else default and click the green Create Dropletbutton.

Take a breather. You successfully launched your cloud hosted server! Now we’re going to take a few more steps to configure it properly.

Step 2. Configure your cloud hosted server

  1. Copy the IP address and in your local terminal ssh into the box to make sure everything was setup properly (replace the x’s with the IP): ssh root@xx.xxx.xxx.xxx
  2. It’s not a good idea to use root, so lets add a sudo user to the remote server (replace username with whatever name you’d like): adduser username
  3. Set a strong password when prompted.

In order to log in with this new account we will need to allow password login, use the text editor of your choice to edit sshd_config file

  1. In your remote server: sudo nano /etc/ssh/sshd_config
  2. Change PermitRootLogin prohibit-password to PermitRootLogin yes
  3. Then change PasswordAuthentication no to PasswordAuthentication yes
  4. Save and exit the text editor then restart the ssh service by running: sudo service ssh restart
  5. In a local terminal, try logging in with ssh username@xx.xxx.xxx.xxx
  6. And enter the password you set earlier.

Now we need to set up the SSH key with this account. You might already have ssh-copy-id on your local machine, which makes this next step easy.

  1. From your local terminal: ssh-copy-id username@xx.xxx.xxx.xxx

If that worked, you should be able to ssh into the droplet without typing a password. Otherwise, follow this tutorial to configure your SSH keys.

We’ve now set up our cloud hosted Linux server, great work! This is a good time to take a break and get used to navigating around and getting used to working with the server remotely. The next step is to set up our webserver to expose part of our droplet to the world wide web.

Step 3. Install and configure your webserver (30m)

I recommend following DigitalOcean’s documentation, including the optional Server Blocks section. If you’re already comfortable with setting up webservers the steps are:

  1. Install Nginx
  2. Open up your firewall to allow Nginx http
  3. Create server blocks to allow more than one web server on the droplet

By the end of this step make sure that when you visit http://your_server_ip you see the Nginx welcome page:

Step 4. Get a domain name and configure nameservers (5m)

Any domain name registrar will do, I like namecheap because of their advanced search option, Beastmode. After you purchase a domain name, we need to configure the domain registrar to point requests towards DigitalOcean’s nameservers.

If you used namecheap this is the process:

  1. Sign in to your account and navigate to the dashboard.
  2. Click the Manage button on the domain you’d like to use.
  3. Scroll down to the Nameserverssection and select Custom DNS from the dropdown.
  4. Add ns1.digitalocean.com, ns2.digitalocean.com, and ns3.digitalocean.com

Your changes should save automatically.

If you went with a different domain name provider, refer to DigitalOcean’s documentation for many common registrars.

Step 5. Set up A records (5m)

Go back to DigitalOcean and make sure you are signed in and have the correct project selected.

  1. Select the Networking tab on the left and select your domain name from the list
  2. In the Create New Record form, select the A tab (it should already be selected by default).
  3. In the hostname input, type @ and select your droplet from the dropdown
  4. Click the blue Create Record button
  5. Repeat step 2, except in the hostname input type www

Go to http://your_domain_name and you should see the same Nginx welcome page from earlier. Be aware these changes take some time to propagate over the internet. If you don’t see the welcome page immediately, try waiting a few minutes, then retry in an incognito window.

Step 6. Create a web application and deploy script (20m)

This step will show you how to set up a simple React app rendered server side using Gatsby. Anything you put into the html folder will be served to the internet, so it is not strictly necessary to use any framework at all for this next step. If you intend to serve a client side rendered app (for example a Single Page React App) or express endpoints, you will need to set up pm2. Refer to this tutorial to run a node server from within your remote server.

6.1 Setting up your application

This section follows Gatsby’s quick start tutorial.

  1. In your local terminal, run: npm install -g gatsby-cli
  2. Create a new site: gatsby new gatsby-site
  3. Navigate into your project folder: cd gatsby-site
  4. Run the development server: gatsby develop
  5. Open a browser to localhost:8000and you should see the Gatsby Welcome page.
gatsby welcome page

Now we just need to get this page to show up at our domain name.

6.2 Deploying your application

We are going to use rsync to copy our local build files to our remote server. In the scripts object of package.json, add the following line, replacing username@xxx.xx.xx.xxx with your username and droplet ip:

In your local terminal, type npm run deploy and you should see the Gatsby CLI build your project and then rsync copy the build files to your remote server.

If you are getting permission issues from the deploy step, run this command in your remote server: sudo chown -R $USER:$USER /var/www/example.com/html

Step 7. Add SSL/TLS (HTTPS) for free (optional, 15m)

While this is optional, I tend to trust websites considerably more if they use HTTPS. Your customers may feel the same way. I recommend following DigitalOcean’s tutorial.

All these steps take place on your remote server

  1. Add the repository sudo add-apt-repository ppa:certbot/certbot
  2. Instal certbot for Nginx sudo apt install python-certbot-nginx
  3. Open the server block file for your domain sudo nano /etc/nginx/sites-available/example.com
  4. Find the server_name line in that file,

If it looks like that already, continue, otherwise edit it to match and save and exit.

  1. Verify you didn’t make any mistakes by running sudo nginx -t
  2. Now reload Nginx sudo systemctl reload nginx
  3. Allow HTTPS traffic through our firewall sudo ufw allow 'Nginx Full'
  4. Our HTTP record is now redundant, so remove it with sudo ufw delete allow 'Nginx HTTP'
  5. Type sudo ufw status and you should see the following output
  1. To obtain an SSL Certificate run sudo certbot --nginx -d example.com -d www.example.com

If that works, you should see the following output

I chose to redirect (2), but either choice is fine. You should get a success message from certbot afterwards and you can test it here.

  1. It’s a good idea to verify that certbot will auto renew your certificate after 90 days. Test that this works by running sudo certbot renew --dry-run

Now try visting https://your_domain.com and you should see the Gatsby starter page from before.

Future Steps

Business requirements might warrant:

  • Running a database to authenticate users and query data.
  • Storing environment secrets like API keys.
  • Creating RESTful API endpoints to serve data.

One of the most common patterns to handle these extra requirements is the LAMP or LEMP stack. We already have Linux and Nginx (Engine-X) configured, so we need MySQL and PHP to complete the stack. Skip to Step 2 of this tutorial to add MySQL and PHP.

PHP is beginning to deprecate as a server side programming language, so unless you’re already comfortable with it consider running a NodeJS with Express server instead.

Tradeoffs

Now that our web application is up and running I want to remind you of this strategy’s tradeoffs compared to web application providers like Heroku, Now, and Netlify.

About the author

I’m a software engineer in the Bay Area currently working on reroute.ai, a service to automate many tasks in freight broker’s claims departments. Questions, suggestions, feedback, or general comments about this article are encouraged and appreciated.

Thank you for reading,
Reid Sherman
reid@reroute.ai
github.com/reidjs

--

--