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
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.
- Update your apt-get
- 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 issudo 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
sudo vi /etc/systemd/system/myapp.service
- 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
Run
systemctl daemon-reload
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.
sudo vi /etc/sudoers.d/myapp
- 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'
This script does the following:
- builds the jar
- copies it over like we did last time
- executes the
restart
command forsystemd
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)