Spring Boot deployment with nginx
This post will show how to configure a CentOS server for deploying a Spring Boot application build with Gradle. The networking is passed trough nginx which can be used to run multiple servers on the same host or serve static traffic faster.
Configure nginx
To configure nginx add the following server declaration to your
/etc/nginx/conf.d/nginx.conf
file.
server {
listen 80;
listen [::]:80;
server_name <your-domain>;
location / {
proxy_pass http://localhost:8080/;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
}
}
This will pass the traffic through to the locally running app server.
Then test the configuration and restart nginx.
sudo nginx -t # test the new configuration for valid syntax
sudo systemctl restart nginx
Configure deployment in Gradle
First off, we need to define the server information and credentials. Log into
the server and create a user deployment
. Assign the sudo
privilege to the
newly created user. Then generate a SSH key deployment
locally and add it to
the allowed keys on the server.
Edit the user gradle.properties
file at ~/.gradle/gradle.properties
(or
create it if it doesn’t exist) and add the following:
server_key_deployment_passphrase=<deployment-ssh-key-passphrase>
server_user_deployment_passphrase=<deployment-user-passphrase>
Now we need to set up Gradle to deploy the application. To do so we add the
org.hidetake.ssh
plugin which allows us to perform SSH operations:
plugins {
id 'org.hidetake.ssh' version '2.9.0'
}
Then we configure our server access properties:
remotes {
webServer {
host = '<your-ip>'
user = 'deployment'
port = <your-ssh-port>
identity = file("${System.properties['user.home']}/.ssh/deployment")
passphrase = server_key_deployment_passphrase
sudoPassword = server_user_deployment_passphrase
errorStream = System.err
outputStream = System.out
}
}
Note how the passphrases are loaded from the properties file, such that they do not end up in version control by accident.
Next we define the build and deployment directories:
def remote_dir = '/var/www/<yourapp>' // server deployment location
def local_dir = 'build/libs' // local artefact output directory
def deploy_file = "<yourapp>-${version}.jar" // artefact name
Now we add a new task to perform the deployment. The task requires that the
artefact is build and checked (i.e. test cases are ran). Then it connects to the
server and pushes the newly built file. The deployed application versions exist
all side by side. The currently active one is linked to <yourapp>.jar
. Then
the app server is restarted.
task('deploy') {
dependsOn build, test, check
doLast {
ssh.run {
session(remotes.webServer) {
put from: "${projectDir}/${local_dir}/${deploy_file}", into: remote_dir
execute "ln -sf ${remote_dir}/${deploy_file} ${remote_dir}/<yourapp>.jar"
executeSudo('systemctl restart <yourapp>.service', pty: true)
}
}
}
}
Register the application with systemd
The new application needs to be registered with systemd such that it can be
controlled easily. To do so, create a unit file at
/etc/systemd/system/<yourapp>.service
and write the following content inside.
[Unit]
Description=Spring Boot Application
After=syslog.target
After=network.target[Service]
User=<serveruser>
Type=simple
[Service]
ExecStart=/usr/bin/java -jar /var/www/<yourapp>/<yourapp>.jar
Restart=always
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=<yourapp>
[Install]
WantedBy=multi-user.target
Then start the app server:
sudo systemctl start <yourapp>
sudo systemctl status <yourapp>
Perform a local test
Build the uber-jar containing all of the necessary jars, including the app server (e.g. Tomcat) by invoking
./gradlew build
Now run it with java -jar <yourapp>.jar
and test it.
Perform the deployment
To perform a deployment to the server you need to invoke the new Gradle task deploy
:
./gradlew deploy