Webapp serving guide

My goal is to streamline the deployment and serving of webapps. Why should I upgrade linux every once in a while, remember to update packages, etc?


You could go for a hosted solution like Ghost's. But it's ridiculously expensive. $30/mo for the smallest set up. https://ghost.org/pricing/. Instead, I run it in Docker on a $5/mo DigitalOcean VM.

See http://blog.wafrat.com/setting-up-the-blog/ for more info.

Webapp with no server

Currently: Using my own VM

I have a $5/mo DigitalOcean VM that runs nginx or Apache. One such VM can serve multiple websites, but the configuration is a bit messy. Handling my own SSL certificates adds to the complexity.

With Apache, I've had a nagging issue where even if I set up caching invalidation, when I update a file, the browsers won't notice unless I clear the browser cache. I don't remember if I've had the same issue with nginx. But even spending 2 hours trying to debug such a trivial issue is a huge waste of time. That's one more reason I'd like to stay away from administering my own machines.

I'll detail the whole process in another article.

Ideally: Firebase Hosting

I have not use it yet. It looks like this is what I want to use eventually. To use it, you would write a config file that determines which files to serve. Then you deploy by running firebase deploy.

You can also customize serving behavior. This is good to redirect any request to your index.html. This is good for your web app to handle routing itself.

Finally Firebase Hosting handles SSL certificates for you, and lets you use your own domain easily.

Webapp with a server

In this set up, the server does not store data, or stores data in a remote database like Firestore.

Currently: VM with nginx

By server I mean your own server application. My web apps have been mostly running in node.js. They were using one of two setups:

  • The node.js application serves the backend routes as well as the frontend. If I want to run multiple such apps on the same VM, I make them serve the app on a different port (eg 3000 and 4000). Then I use nginx to listen to port 443 and redirects to the right port depending on the domain.
  • The node.js application exposes an API, and nginx serves the webapp separately.

One drawback in both is that I have to handle SSL certificates in node.js.

Running the server

I use forever (https://www.npmjs.com/package/forever) to run the node.js application.

I also have an init.d bash script that runs the command. However it's been flaky, so I sometimes have to run the app manually every time the VM reboots. I haven't looked into why.

Deploying updates

To update the backend, I just update the code with a git pull. To update the frontend, I scp the latest build to the nginx's serving folder. Then rerun the application with forever restartall.

Next step: Docker on a VM

First I wouldn't write the server in node.js. I'd want to try writing in in Dart. Then it would run on docker. The docker image would run Nginx to serve the web app, as well as the Dart server.

Would it be able to run multiple such containers on the same VM? In that case the host itself would need an Nginx config, which I'd have to figure out.

According to this guide (https://techsparx.com/nodejs/docker/express-https.html), setting up https in the node.js app itself is far easier than setting up nginx to handle it. Seems like for a Dart server, you can set up SSL easily.

Running it

I don't know if or how to make Docker automatically run an image on boot.

Deploying updates

I'd rebuild a new docker image, publish to my private Docker repository. On the VM, I'd pull the new image and run it.

Long term solution: Kubernetes?

This requires a load balancer. How much does it cost? On DigitalOcean, it seems like it's free, but the smallest node costs $10/mo.

The benefit would be that I won't have to administer the nodes' Linux updates?... If I use a Kubernetes service like DigitalOcean's Kubernetes clusters, Amazon's or Google's.

Deploying updates

I'd build the docker image, then run some kubectl command? Not sure.

Webapp with a server and a database

This time, the server talks to a MongoDB or MySQL database.

Currently: all in one VM

Like the previous set up, it's a node.js app serving both the API and the webapp.


The drawback of this approach is that every time I get a new laptop, I need to install MongoDB and Node.js. On MacOS, installing MongoDB is weird. There's no installer. It's a simple .tar.gz file that I uncompress somewhere, then I have to modify my  ~/.zshrc file. And MongoDB requires I pass in a folder for the data files.

Next step: docker on a VM

The Docker image has to be set up so that the MongoDB's data folder is mapped to the VM's folder.

Long term: Kubernetes?

In that case, the data folder needs to be a remote volume. On DigitalOcean it is really cheap

Volumes cost $0.10 per GiB.

Other points to consider

Going serverless

One thing I haven't looked into is whether it is possible to go serverless even for my more complicated webapps. Could I use Firestore in the app I wrote with MongoDB? Could I use Cloud Functions instead of a server application?

Implement continuous delivery

Right now, I have presubmit hooks that run unit tests on each commit. Either that or they run in my deploy.sh script.

Would it be possible to use a CI tool like Travis, Jenkins or CircleCI? How much easier would administration be? I'd be nice to see graphs of unit tests failing or not, code coverage and compile size.

Develop without installing additional software on my laptop

I have to install Node.js, MongoDB, and an IDE (Visual Studio Code). Since I do Flutter development, I also need to install Flutter, which comes with Dart.

Would it be possible to code remotely from even a Chromebook? The IDE would be a hosted VSC. Everything would be built remotely.

The intermediate step would be to use Docker. Then I'd only need to install Docker and VSC.

Ultimately, to not even run or compile anything on the laptop, I'd need a build server. Should it be my own machine, an on-demand VM or a build service?