A Step By Step Cheat Sheet on How I Usually Deploy My Full-Stack Application to a Linux Server.

Daniel Voigt
The Startup
Published in
3 min readSep 9, 2020

--

This assumes a Debian based distribution with systemd, a MySQL server, a NodeJS backend and a frontend written in any library you prefer (Vue, react, etc).

For a tl;dr see here.

Update the package list

sudo apt update

Install the mysql-server

Setup GIT deployment repository

We first need to setup a new repository on our server. This will serve as our target for certain versions we want to push and publish. Instead of copying versions manually we can instead use the power of git and push changes over ssh.

Creating a deployment hook

This will be executed on every successful push. We use this hook to automatically update our server and client with the changes pushed to this repository.

cd /var/git/<project>-[client|server].git/hooks
sudo touch post-receive
sudo chmod +x post-receive

Client:

Server:

Add systemd unit files

Unit files describe systemd services which describe when and how those services are started and under which environment. For example our server depends on a running MySQL server. We can describe this dependency with unit files.

Client:

Server:

Add the remote to our local repository

git remote add deploy-dev ssh://<user>@<hostname/var/git<project>-[client|server].git/

This is for your development environment only. On a production server you should probably use nginx or apache. For development builds I usually just set up a simple HTTP server. Either the python simple http server or in this case the http-server NPM package.

npm install --global http-server

Create a systemd unit to manage the http-server

touch /etc/systemd/system/<project>-<branch>.service

In order for our users to start and restart this service we need to add certain rights for the group to our sudoers file /etc/sudoers:

%developers  ALL= NOPASSWD: /bin/systemctl restart <project>-<branch>
%developers ALL= NOPASSWD: /bin/systemctl start <project>-<branch>

This tells sudo that everyone in the group developers is allowed to execute /bin/systemctl [start|restart] <project>-<branch> without the need to enter their password NOPASSWD. It's still important to execute those paths with sudo in order for the rule to come into effect.

Now we see why I copied the index.html to 404.html. If you develope an SPA and your preferred router works with the session history stack i.E. changes the URL instead of the URL hash you need to serve the index.html on any path. http-server serves 404.html if the path does not exist which solves our problem. On nginx, we usually use this setting:

location / {
try_files $uri $uri/ /index.html;
}

Lastly I like to set up a reverse proxy to serve my applications over TLS. This way you have a central point of managing your certificates. This certificate is valid for all subdomains so you can add applications without the hassle of setting up a new certificate. For my dev server I like to use redbird because of how easy it is to get running. It even has automated zero configuration lets encrypt capabilities. I manage a few more certificates, so I chose to generate my certificate manually and pass them to redbird.

npm install redbird

And again a systemd unit file to start up the reverse proxy.

Lastly this is how I update my certificates. You should probably use certbots auto-renewal but since my domain name isn’t pointed to this server I generate them manually for my subdomains.

./certbot-auto certonly --manual -d <domain>.<tld>

Notes

Push with Windows: Put your private key in C:\Users<user>.ssh\id_rsa. On Windows the easiest way is probably using putty-gen and exporting the private key as OpenSSH key.

Webpack: I often see developers importing static assets directly in their source. Don’t do this! Use imports/require for those files and let webpack file-loader plugin handle those files. This way you don’t need to copy any assets folders and have hashed filenames for your cache control!

Going further

Going from dev to beta which include changes from redbird and http-server to nginx and using the full power of Linux containers with docker.

--

--

Daniel Voigt
The Startup

Software developer, language enthusiast and Jazz musician.