Do not directly edit on medium. Instead:
- update here
- open the mkdown viewer (cmd k + v)
- copy-paste viewer text into medium
Avoid getting locked in to expensive cloud application platforms like Heroku, Now, and Netlify
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?
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.
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.
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.
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!
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.
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.
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.
cat ~/.ssh/id_rsa.pub
Take a breather. You successfully launched your cloud hosted server! Now we're going to take a few more steps to configure it properly.
ssh root@xx.xxx.xxx.xxx
adduser username
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
sudo nano /etc/ssh/sshd_config
PermitRootLogin prohibit-password
to PermitRootLogin yes
PasswordAuthentication no
to PasswordAuthentication yes
sudo service ssh restart
ssh username@xx.xxx.xxx.xxx
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.
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.
I recommend following DigitalOcean's documentation, including the optional Server Blocks section. If you're already comfortable with setting up webservers the steps are:
By the end of this step make sure that when you visit http://your_server_ip you see the Nginx welcome page:
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:
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.
Go back to DigitalOcean and make sure you are signed in and have the correct project selected.
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 test page immediately, try waiting a few minutes then retry in an incognito window.
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.
This section follows Gatsby's quick start tutorial.
npm install -g gatsby-cli
gatsby new gatsby-site
cd gatsby-site
gatsby develop
localhost:8000
and you should see the Gatsby Welcome page.Now we just need to get this page to show up at our domain name.
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:
https://gist.github.com/df66eb143f94098d30d402b5052a3d3d
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
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
sudo add-apt-repository ppa:certbot/certbot
sudo apt install python-certbot-nginx
sudo nano /etc/nginx/sites-available/example.com
...
server_name example.com www.example.com;
...
If it looks like that already, continue, otherwise edit it to match and save and exit.
sudo nginx -t
sudo systemctl reload nginx
sudo ufw allow 'Nginx Full'
sudo ufw delete allow 'Nginx HTTP'
sudo ufw status
and you should see the following outputhttps://gist.github.com/bccddbe9b807429b92a12afef754f98c
sudo certbot --nginx -d example.com -d www.example.com
If that works, you should see the following output
https://gist.github.com/10d7d6cb108a84222c1fe8027a757e24
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.
sudo certbot renew --dry-run
Now try visting https://your_domain.com and you should see the Gatsby starter page from before.
Business requirements might warrant:
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.
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.
https://gist.github.com/reidjs/bff6a636a26a2d8eb38bae68382526d9
I'm a software engineer in the Bay Area currently working on partnr.org, a service to help underrepresented communities start their careers in tech. Questions, suggestions, feedback, or general comments about this article are encouraged and appreciated.
Thank you for reading,
Reid Sherman
reid@partnr.org
github.com/reidjs
...
server_name example.com www.example.com;
...