How to deploy a Spring Boot - Angular application on Ubuntu server

When I first tried to deploy an application, I had no clue how it works. I had to do it on my own and read lots of blog posts, tutorials and Stack Overflow answers to get it. I collected information all the way to be able to create my own step-by-step tutorial. Because guess what, none of the ones I found on the Internet worked as is and I had to mix a lot of resources all together to make it work.

Since then, I reused my own tutorial to deploy a Spring Boot + Angular and Ionic application and it worked like a charm. So maybe if you have the same config as I have, this might work for you too!

This tutorial aims at deploying a web application with a Java / Spring Boot REST API, an Angular and/or Ionic front-end user interface (I’m not going into Ionic details here), on an Ubuntu server version 16.04 (Xenial Xerus) or 18.04 (Bionic Beaver). I’m using a PostgreSQL database and also explain how I installed it.

I did not use containerization as I have very little knowledge, even though I’d like to give Docker (and maybe Jenkins) a try for my next deployment. I also chose the “old school”, server way, to deploy, first to understand it well, second because it seemed the easiest, somehow… and finally because I don’t get to “do” much Linux while I enjoy it, so it was an opportunity. I’ll also try new ways to deploy apps shortly (Cloud solutions namely). But this tutorial is not about it.

Also, I didn’t go into all details about Linux commands (for writing in files or checking folders contents for example) because if you know nothing about Linux it would be good to take a little course on the basics (file systems, basic commands…) before trying this, or anything else on a Linux machine. Linux is more permissive and lends more power and responsibilities (thank you!) than Windows, but that’s also more “dangerous” so better know the beast before doing anything with it.

I cross my fingers for this tutorial to work for you without having to compile a ton of other information!

Deploy a Spring Boot – Angular application on Ubuntu server

I’m not going through the creation of Spring Boot, Java, Angular… projects or PostgreSQL database, if you’re here I guess you have it all ready to deploy. I developed a full, independent (REST API model) back-end API with latest LTS Spring Boot version and Java14, and front-end interface consuming that API with the latest Angular version. I developed on a Windows machine but I’ll deploy on Ubuntu server. There was a little issue a had to solve to deploy on Ubuntu 16.04, which hadn’t appeared on version 18.04 (always use latest LTS when possible!), I included that step in the tutorial.

If you’re working on a Windows machine, make sure you have a SSH client installed (PuTTy is quite a reference…). Also, gather the access information to connect to the remote Ubuntu server (if you’ve rented a remote server like I did).

To remote connect through SSH, you’ll use the Windows command line

putty.exe user@IP

where “user” is the user name and IP is the host IP address.

You might use PuTTy’s graphical interface, but using command line allows you to create a little script (.bat) so you just click on the script and it opens the connection window where you just have to input the password. I find it very handy. I guess if there’s no security issues you might even create a script that inputs the pwd as well…

When connected to the remote Ubuntu machine, you want to ensure the user that will deploy has the sudo privileges. To be honest, when I deploy a private project and I’m working alone, I do everything with the root account, but that’s not recommended.

From admin (root) account (type su):

visudo

It opens a file, just add following line at bottom:

username ALL=(ALL) NOPASSWD:ALL

where username is the name of the user that needs sudo access.

Now, when you connect as “username”, you can type sudo -i or su to act with full privilege (beware of security issues!) or prefix commands with “sudo “.

Install Java (Oracle Java JDK Installer) on the Ubuntu server

Here started trouble, because I wasn’t able to install one of the licensed Java versions (8 or 11), neither from Oracle or OpenJDK sources (which also prevented me from working with Jenkins, therefore the old school deployment tactic…). So this method works to install any unlicensed Java version from the web. I chose Java 14 but you might just change the version number.

sudo apt update && sudo apt upgrade
sudo add-apt-repository ppa:linuxuprising/java
sudo apt update
sudo apt install oracle-java14-installer

Check that it worked with:

java --version
javac -version

Install PostgreSQL on Ubuntu server

This might need adjustments depending on your Postgres version!

Get dependency for PostgreSQL:

sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt/ bionic-pgdg main" >> /etc/apt/sources.list.d/pgdg.list'

where “bionic” is the Ubuntu version. Check yours with lsb_release -c if needed and adapt above line.

Import the repository signing key:

wget --verbose -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add – 

Install (here installing PostgreSQL version 11, which you can of course change):

apt-get update
apt-get install postgresql-11

Alternately, this shell script will automate the repository setup. The script is included in the postgresql-common package in Debian and Ubuntu, so you can also run it straight from there:

sudo apt install postgresql-common
sudo sh /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh

Now, try to connect to PostgresSQL. Default user’s name is “postgres”:

su - postgres

Exit Postgres and set the environment variables (change version if necessary):

export PATH=$PATH:/usr/lib/postgresql/11/bin
export PATH=$PATH:/usr/lib/postgresql/11/main
export PATH=$PATH:/var/lib/postgresql/11/main
export PATH=$PATH:/var/run/postgresql

Check your installation and variables:

postgres --version

You might want to make PostgreSQL start at server boot:

update-rc.d postgresql enable
systemctl enable postgresql

I’m not going into details on how to allow remote connections (for a Power BI or tier application connection or to manage your database remotely e.g.) here because I installed everything on the same server and didn’t intend to give remote accesses. You will find plenty of answers about this on the Internet and that’s quite simple to do.

You can always check the status of your database with those commands, first giving you pg server status (connections, ports…), the second giving you information on the service (if you made a service, as shown few lines above).

pg_isready                 
/etc/init.d/postgresql status

You probably want to make an automatic back-up of your database!

su – postgres
(postgres@server:~$)
mkdir -p ~/postgres/backups
find -name “backups”
crontab -e

The structure of the instructions is explained in the file that opens. Here’s an example of how to make a back-up of your database every Sunday at midnight. Beware, the server has to be up and running at that time, otherwise the back-up will be skipped!

0 0 * * 0 pg_dump -U postgres my_db_name > ~/postgres/backups/my_db_name.bak

Deploy Spring Boot back-end on Ubuntu

You can get your repository from a public GitHub repo like so:

wget --no-check-certificate https://github.com/User/Repository/archive/master(branchname).tar.gz

Or download the tar from your GitLab repo and copy it to the remote Ubuntu server. I tend to like GitLab a lot more because it gives you that choice to download a .tar or .tar.gz directly! Beware that destination file must have write permission from “other” group (chmod o+w remoteFolder).

scp full/path/myLocalFile remoteuser@remoteserver:/remoteFolder/

where “myLocalFile” is the tar.gz downloaded from GitLab and “remoteFolder” is the destination folder on the server.

Extract source code from the archive:

tar -xf myRepo.tar.gz

Installing and configuring maven for deployment

I work with maven as a dependency manager, so you might do a little research is you use gradle. Also, I use a very simple configuration because this is about personal projects, you might want to configure production settings more cleanly for a professional project or if heavy maintenance is foreseen. This is probably the minimum acceptable config.

Install maven:

apt-get install maven

You’ll need to make some changes in your pom.xml file, the one that you unzipped on your server (you might have done it before, but what’s more fun than using vim or nano honestly?). This allows to make an executable jar.

<groupId> ... </groupId>
<artifactId> ... </artifactId>
<version>0.0.1</version>
<name> ... </name>
<packaging>jar</packaging>
 
<plugins>
    <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <executions>
            <execution>
                <goals>
                    <goal>repackage</goal>
                </goals>
                <configuration>
                    <executable>true</executable>
                    <classifier>spring-boot</classifier>
                    <mainClass>
                       
[groupId.artifactId].Application
                    </mainClass>
                </configuration>
            </execution>
        </executions>

    </plugin>
</plugins>

Place yourself in the file where the pom.xml is and build the jar:

mvn clean package

Then try running the application:

mvn spring-boot:run

Make a service from the jar

Now that you have an executable jar, you want to make a service (in the Linux way) so it can run, start at boot, stopped and restarted…

Check that you file is executable, else change it with chmod 755 yourApp.jar

I created a script myapp.service in file /etc/systemd/system with following content:

[Unit]
Description=My Spring Boot application
After=syslog.target
 
[Service]
ExecStart=/path/to/your-app.jar 
SuccessExitStatus=143 
 
[Install] 
WantedBy=multi-user.target

When saved, try:

service myapp start 
service myapp status

If everything ok, you’d see the Spring Boot start logs (the ones you’d see in the console of your IDE), or an error log.

If you want the app to start at server boot, type:

systemctl enable myapp

You can now check your endpoints with the curl command, you’ll see an html/JSON representation or a JSON message saying that you have to be connected if you put some secured access on your application.

Deploy Angular front-end project on Ubuntu

You’ll have to get your repository just as you did for Spring Boot. Be sure you changed your URIs from http://localhost:8080/blabla to /blabla, because your Angular front-end won’t be communicating directly with your Spring Boot back-end, we will use a web server with a proxy. When I first tried to deploy, I was convinced I just had to install everything as on my dev machine and it would do the trick, but spoiler alert, that won’t. You need a web server to render the front end, so your Angular front-end itself won’t be working on the “localhost” itself. I chose Apache2 to serve my application which seems a pretty common choice (common = well documented, well tested… don’t make it too exotic at first!).

Installations to be able to run Angular:

apt install nodejs
apt install npm
curl -sL https://deb.nodesource.com/setup_12.x | bash -
apt-get install -y nodejs
node --version
npm install -g @angular/cli

Place yourself in the file you previously transferred and unzipped, where [src] file is, and build:

ng build --prod

If it works, a [dist] file is created. If you’re working with Ionic, please note the file will be called [www] instead of [dist].

You might encounter problem “@angular-devkit/build-angular”, which I solved with following lines:

npm install --save-dev @angular-devkit/build-angular
npm update

Install and use Apache2 as web server for your Angular application

Install Apache2 and allow access from anywhere (if your application is meant to be public, otherwise you’ll have to make some config). Here we will configure the Ubuntu firewall (ufw). If the app list doesn’t show Apache as allowed application (from outside), type line 3. Type line 4 to check that firewall is up and running. Type line 5 if it wasn’t, and check again.

sudo apt install apache2
sudo ufw app list
(sudo ufw allow 'Apache')
(sudo ufw status)
(sudo ufw enable)

Check that Apache server is “active running”:

sudo systemctl status apache2

If everything seems ok, check from another computer that you see the default Apache2 page by just typing the IP address in a browser.

Set up a virtual host:

sudo chmod -R 755 /var/www/domain_name

And configure the proxy from front to back:

sudo nano /etc/apache2/sites-available/domain_name.conf

Use 80 for http or 443 for https:

<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    ServerName your_domain
    ServerAlias your_domain
    Alias /mypath /var/www/your_domain
    DocumentRoot /var/www/your_domain
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
	ProxyPass /api/	http://localhost:8080/api/
	ProxyPassReverse /api/ http://localhost:8080/api/
	ProxyRequests	Off
</VirtualHost>

Enable your new domain and disable the default one:

a2ensite your_domain.conf
a2dissite 000-default.conf

Check config:

sudo apache2ctl configtest

You might encounter error “Invalid command ProxyPass”, enable proxy with:

a2enmod proxy_http
systemctl restart apache2

Now, copy the Angular [dist] file CONTENT to the newly created domain file. The index file must be in /domain_name.

cp -a ./angular/dist/[folder]/. /var/www/domain_name

When I build, I get a folder with my app name in the dist folder, that’s the content of that folder I need to copy into my new “domain_name” folder. Don’t folder the /. that copies all the content, because copying the folder itself doesn’t work.

Finally, configure routing:

sudo nano /var/www/domain_name/.htaccess

Just copy/paste:

RewriteEngine on
#Don’t rewrite files or directories
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d
RewriteRule ^- [L]
#Rewrite everything else to index.html to allow html5 state links
RewriteRule ^ /index.html [L]

Well, at this point, you should be able to access your application from any computer by typing its IP in a browser, and your front-end should be able to communicate with your back-end which works with your PostgreSQL database.

2 thoughts on “How to deploy a Spring Boot – Angular application on Ubuntu server

  1. I tried this – it didn’t work, I also don’t understand how it is even supposed to work since Angular index.html is download on my browser on my local machine, following which it sends a request to backend with a url /blabla but without prepending the ip of EC2 instance such call can never work. I don’t undestand how setting up proxies can help if the call is made from my machine that has no idea about Apache2 installed on ec2

    1. You access to the website served via Apache server from your machine, so it’s aware of the server address. You’re not making a direct call from your browser, your browser contacts the web server, then the web server calls to back-end service. This, of course, if both are on the same server machine. I’ve used this deployment template many times. Only thing I can think of if it doesn’t work is with the URIs on Angular or Java side.

Leave a Reply

Your email address will not be published. Required fields are marked *

Don’t miss out!

Receive every new article in your mailbox automatically.


Skip to content