DEV Community

Cover image for Dirt Cheap Boot
Anthony Dreessen
Anthony Dreessen

Posted on

Dirt Cheap Boot

Gather round as we embark on a journey about how you can host your very own fully fledged Spring Boot web application (API and Frontend) for as little as $5/month.

I would like for this guide to be as comprehensive as possible. So if you have questions about how to get from point A to point B, please leave a comment.
Oh, and if something here was helpful to you, remember to bookmark this guide so you can find it again.

if you would like to see the projects I'm running using this technique check them out!
https://parrit.io
https://plenti.dev

What You Need

  • A spring boot web application that can run on your localhost machine

Step 1: The Accounts

We’re going to be signing up for a variety of accounts to piece together all of the various services you’re going to be using. (Note: this simply the best, cheapest list of technologies I’ve found so far. If you have betters or alternatives, leave a comment below!)

Database: elephantsql (free)

Hosting: digitalocean ($5/month)

CI/CD: codeship (free)

Step 2: Environments

Part of what is going to be so great about the finished product is the ability to use various environments all linked to their own git branches. Codeship is will be able to read the git branch and publish using the environment you specify.

Here is my short writeup on environments. Follow this if you’re looking to set up staging versus production versus development and don’t already know how (or need a refresher)

https://anthony-orange.medium.com/development-environments-in-spring-boot-dfda98833752

Step 3: Configuring the Database

Externalized databases running on separate servers than your application is a good idea. In order to get there, you’re going to need your localhost application to be using a local database instance. Here’s my guide for how to do that: https://medium.com/@anthonyjamesdreessen/externalized-postgres-in-spring-boot-9043de80a7df

Once we’re configured to do that, we want to use a remote database instance. We can do that through our environments!

Here is a template of what a finished environment might look like

spring.datasource.url=jdbc:postgresql://dbname.db.elephantsql.com:5432/db_user_name
spring.datasource.username=db_user_name
spring.datasource.password=password
Enter fullscreen mode Exit fullscreen mode

Step 4: Launching the Application

Logging in through SSH

First, make sure you can ssh into your droplet. You’re going to need get it set up so you don’t have to enter in the password every time. Check out this article for a how-to: https://www.digitalocean.com/docs/droplets/how-to/add-ssh-keys/

(tl;dr add your computer’s public key ~/.ssh/id_rsa.pub to your server’s ~/.ssh/authorized_keys)

Installing Java

An important step. DigitalOcean droplets don’t necessarily come with Java already installed.

  1. Update your apt-get
  2. Check out if your machine does java -version if nothing is installed, you should be shown commands for how to do so. The default method is sudo apt install default-jre

Copy your application to your droplet

copy over your .jar file to the droplet scp path/to/jar username@ip_address: make sure you add the colon.

Then, after ssh-ing into your server, you can verify that your program works by running /usr/bin/java -jar -Dspring.profiles.active=profile myapp.jar (Note: don’t use this for your production deployment method. There’s something better in the next section)

you should see the familiar Spring Boot startup console. navigate to <droplet_ip>:8080 in your browser/client to see it working.

Step 5: Starting your application remotely through SSH

Modern Linux distros use systemd for deploying things like a Spring Boot application. In order to get it set up, you have to do some configuration on your droplet. I have instructions below, but if you want more information about this topic, click here

While ssh-ed into your droplet:

Create a service definition for your application

  1. sudo vi /etc/systemd/system/myapp.service
  2. The service definition file should look something like this
[Unit]
Description=My Java Application
After=syslog.target

[Service]
Environment="MY_DATABASE_PASSWORD=<database_password>"
User=<droplet_username>
ExecStart=/usr/bin/java -Xmx256m -Dspring.profiles.active=<profile> -jar /home/<droplet_username>/myapp.jar
SuccessExitStatus=143

[Install]
WantedBy=multi-user.target
Enter fullscreen mode Exit fullscreen mode
  1. Run systemctl daemon-reload

  2. Test that the service is able to run the app manually by using the command systemctl start myapp (Note: since systemctl knows to look for the extension .service you don’t need to append it to myapp, but you can)

If step #4 fails, you can see what went wrong by using systemctl status myapp

Bake in SU access

Now if you'll notice, when when we run the systemctl start myapp command, we are interactively asked for our password. This will break any attempt to do this from an automated shell script which makes it difficult to automate our deploys on Codeship.

In order to work around this, we specify exactly one command (the restart command) that our particular user is going to be able to execute without needing to enter a password. This remains a secure (enough) thing to do because we still have the SSH key for login into the droplet.

  1. sudo vi /etc/sudoers.d/myapp
  2. add this line <username> ALL = NOPASSWD: /bin/systemctl restart myapp

**IMPORTANT: The value of myapp in the above must not contain any word boundaries. This mean no periods . and no hyphens -

Step 6: Deploying automatically with Codeship

Add ssh access to your codeship account

This is very similar to what we did in step 4. In fact, you're simply going to append to the file we modified in step 4. You can find CodeShip's SSH key in Builds => Project Settings (gear icon) => General => Keys

Create deployment script on Codeship

In the deploy settings on your Codeship project. We're going to want to use a custom script. The most basic version of this looks like this:

./gradlew bootJar
scp build/libs/myapp.jar username@ip_address:
ssh -t username@ip_address 'sudo /bin/systemctl restart myapp'
Enter fullscreen mode Exit fullscreen mode

This script does the following:

  • builds the jar
  • copies it over like we did last time
  • executes the restart command for systemd to restart our service that we defined above

Success!

If I’ve successfully guided you then after your build goes green then you should be able to push code to a repository and have it trigger an automatic deploy to the cloud!

Again, if you would like more explanation about how to get from point A to point B please leave a comment and I’ll be sure to get more thorough.

Top comments (0)