Configura tu VPS para servir aplicaciones Spring

En esta entrada vamos a explicar cómo configurar un VPS (Virtual Private Server) para poder publicar y pasar a producción nuestra aplicación desarrollada en Spring Framework (Java) y MongoDB. Posiblemente, el servicio de VPS será más barato que el uso de otros servicios, como Heroku o Amazon Web Services.

Una vez instaladas todas las herramientas, y creado un servicio de nuestra aplicación, añadiremos también a nuestro servidor un firewall y una aplicación de monitorización.

Creación de Droplet en Digital Ocean

Creación de Droplet en Digital Ocean

Elegí DigitalOcean, versión Ubuntu 14.04 de 1GB de RAM (10$ mensuales) para la configuración del mismo. Probé también con configuraciones de 512 MB de RAM, pero me dí cuenta de que la aplicación funcionaba bastante lenta en este caso.

Aquí tienes un enlace de registro con un cupón de 10$ de descuento. Interesante saber, que DigitalOcean cobra de manera fraccionada (por horas), por lo que en caso de querer realizar simplemente pruebas y no dejar el servidor siempre encendido, puedes crear un servidor, utilizarlo el tiempo que creas necesario, hacer una snapshot del mismo, y posteriormente destruirlo. De esta manera sólo te cobrarán las horas utilizadas (más una hora adicional, que te cobran por el “arranque” del servidor).

 

Configuración

Java

Primero de todo instalaremos Java 8 en el servidor mediante un repositorio apt. ¡Indispensable, claro! Nuestra aplicación lo necesitará para compilar y ejecutar nuestra aplicación. Utilizaremos los siguientes comandos:

sudo apt-get update
sudo echo 'deb http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main' >> /etc/apt/sources.list
sudo echo 'deb-src http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main' >> /etc/apt/sources.list
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys C2518248EEA14886
sudo apt-get update

sudo echo oracle-java-installer shared/accepted-oracle-license-v1-1 select true | sudo /usr/bin/debconf-set-selections
sudo apt-get install -y --force-yes oracle-java8-installer
sudo update-java-alternatives -s java-8-oracle

Maven

Una vez instalado Java, instalaremos Maven, el gestor de dependencias Java. Éste es necesario, tanto para la descarga de dependencias, como también para el uso de la tarea spring-boot:run para arrancar nuestra aplicación. Lo instalaremos mediante:

sudo curl -fsSL http://archive.apache.org/dist/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.tar.gz | sudo tar xzf - -C /usr/share && sudo mv /usr/share/apache-maven-3.3.9 /usr/share/maven && sudo ln -s /usr/share/maven/bin/mvn /usr/bin/mvn

 

MySQL

Ahora instalaremos el servidor de base de datos que necesitemos. En caso de querer instalar MySQL:

sudo apt-get update
sudo apt-get install mysql-server

Durante la instalación, nos pedirá el usuario y contraseña que queremos configurar como usuario root de MySQL. Para comprobar que MySQL se está ejecutando:

sudo netstat -tap | grep mysql

Si vemos que no se está ejecutando correctamente, podremos utilizar el comando de reinicio del servicio de MySQL:

sudo service mysql restart

 

MongoDB

En caso de querer instalar otro tipo de bases de datos, como por ejemplo MongoDB, una base de datos NoSQL, procederemos de la siguiente manera:

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10
echo "deb http://repo.mongodb.org/apt/ubuntu trusty/mongodb-org/3.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.0.list
sudo apt-get update
sudo apt-get install -y mongodb-org

echo "mongodb-org hold" | sudo dpkg --set-selections
echo "mongodb-org-server hold" | sudo dpkg --set-selections
echo "mongodb-org-shell hold" | sudo dpkg --set-selections
echo "mongodb-org-mongos hold" | sudo dpkg --set-selections
echo "mongodb-org-tools hold" | sudo dpkg --set-selections

Para iniciar o parar el servidor MongoDB podremos usar los comandos:

sudo service mongod start
sudo service mongod stop

 

Git

Ahora procederemos a instalar Git. Mediante él descargaremos nuestro código fuente para poder ejecutarlo:

sudo apt-get update
sudo apt-get install git

 

Npm, Bower y Gulp

En el caso de que necesitemos npm, bower o gulp para la gestión de dependencias y compilación de nuestro código frontend, deberemos instalarlos de la siguiente manera:

sudo apt-get update
sudo apt-get install nodejs
sudo apt-get install npm
npm install -g bower
npm install -g gulp-cli

 

Descarga de código fuente

Accederemos al path de nuestro proyecto, y mediante git descargaremos nuestro repositorio. Podemos utilizar la carpeta /home/, o la que creamos conveniente para guardar nuestros proyectos:

cd /path/
git clone https://giturl.com/gitproject.git

 

Ejecución

Podremos arrancar nuestra aplicación en primer plano situándonos en nuestro proyecto, y ejecutando la tarea Maven “run” de Spring Boot. Recomiendo, sin duda, utilizar el generador de proyectos JHipster, herramienta que nos creará y configurará automáticamente un entorno Spring seguro con sus respectivas configuraciones, perfiles y tareas Maven en unos minutos. Para ejecutar la tarea Maven:

cd /path/appname
mvn spring-boot:run

Hay que tener en cuenta, que en caso de que estemos utilizando distintos perfiles en Maven, podremos utilizarlos mediante el uso de -P. Un ejemplo de uso del profile “prod” (producción) sería:

mvn spring-boot:run -P prod

Para salir del programa, simplemente podemos utilizar el atajo de teclado Ctrl+C. Debemos tener en cuenta, que mediante este uso de comandos, nuestra ejecución se estará haciendo en primer plano, y estaremos viendo el log de la aplicación en nuestro terminal SSH. Esto significa, que en caso de cerrar nuestro terminal, la sesión de usuario se cerrará, y con ello, nuestra aplicación.

Debido esto, tendremos que crear un servicio específico para nuestra aplicación que nos permita arrancarla en segundo plano. Para poder hacer esto, podemos utilizar el siguiente comando:

nohup mvn spring-boot:run > /path/appname/logs.log 2>&1 &;

Mediante el uso de nohup, podremos mantener la ejecución de un comando pese a tener la terminal cerrada. Lo que viene a continuación (‘>’), nos permite recoger el log y guardarlo en un archivo.

Para apagar nuestra aplicación en segundo plano, no quedará más remedio que buscar sobre todos los procesos de nuestro equipo:

ps -ef | grep appname

Seleccionaremos el identificador del proceso (PID) del proceso encontrado, y mediante este, lo cerraremos. Esto es justamente lo que hace el siguiente comando:

ps -ef | grep appname | grep -v grep | awk '{print $2}' | xargs kill

 

Creación del servicio automático para una aplicación Spring Boot

Teniendo en cuenta lo anterior, utilizaremos los comandos de ejecución en segundo plano para crear un servicio de nuestra aplicación.

He utilizado esta fuente de información para crear el script que os muestro a continuación:

#! /bin/sh
APP_DIR=/path/appname

case "$1" in
 start)
   cd $APP_DIR
   nohup mvn spring-boot:run >; /path/appname/logs.log 2>&1 &
   ;;
 stop)
   ps -ef | grep appname | grep -v grep | awk '{print $2}' | xargs kill
   sleep 10
   ;;
 restart)
   ps -ef | grep appname | grep -v grep | awk '{print $2}' | xargs kill
   sleep 20
   cd $APP_DIR
   nohup mvn spring-boot:run &
   ;;
 *)
   echo "Usage: appname-spring {start|stop|restart}" >&2
   exit 3
   ;;
esac

Recordad que es muy importante modificar appname y path con los respectivos valores para vuestros casos. Crearemos el archivo, lo guardaremos, y le daremos permisos de ejecución:

nano appname-spring.sh
sudo chmod a+x appname-spring.sh

Copiaremos este archivo a nuestra carpeta /etc/init.d/, y registraremos el archivo como un servicio:

sudo update-rc.d appname-spring.sh defaults

¡Finalmente, ya tendremos nuestro servicio! Podemos arrancarlo o pararlo mediante los comandos:

sudo /etc/init.d/appname-spring.sh start
sudo /etc/init.d/appname-spring.sh stop

Y por último, podremos ver las últimas líneas del log de nuestra aplicación que permanece ejecutándose mediante el comando:

tail -f /path/appname/logs.log

 

Usar Monit para monitorizar nuestro servidor

Este paso es opcional. Monit es una sencilla herramienta creada para monitorizar los servicios de nuestro servidor, y permitir administrarlos de manera remota accediendo a una página web servida en un puerto de nuestro servidor. La instalaremos por apt:

sudo apt-get install monit

Una vez la tengamos descargada, editaremos su archivo de configuración:

sudo nano /etc/monit/monitrc

Podemos asignar los datos que mostramos a continuación:

set httpd port 2812 and
    allow localhost
    allow 0.0.0.0/0.0.0.0
    allow mockuser:mockpass

Esto permitirá acceder a nuestro servidor mediante el puerto 2812, con el usuario mockuser con el password mockpass. Deberemos cambiar esta información por la que veamos correspondiente. Ahora vamos a establecer los servicios que vamos a trackear. Todos son opcionales:

# SPRING APP
check process appname-spring matching "appname"
    start program = "/etc/init.d/appname-spring.sh start"
    stop program "/etc/init.d/appname-spring.sh stop"
    restart program = "/etc/init.d/appname-spring.sh restart"

# MYSQL
check process mysql with pidfile /var/run/mysql/mysql.pid
    start program = "/etc/init.d/mysql start"
    stop program = "/etc/init.d/mysql stop"

# MONGODB
check process mongod with pidfile /var/lib/mongodb/mongod.lock
    if failed host 127.0.0.1 port 27017 then
        restart if 5 restart within 5 cycles then timeout

# APACHE (EN CASO DE TENERLO INSTALADO)
check process apache with pidfile /var/run/apache2/apache2.pid
    start program = "/etc/init.d/apache2 start" with timeout 60 seconds
    stop program = "/etc/init.d/apache2 stop"

Como vemos, se puede establecer un timeout en el arranque de un servicio (véase el servicio de apache), así como procesos automáticos para que compruebe que el servicio se está ejecutando, y en caso de no estar ejecutándose, arrancarlo (véase el servicio de MongoDB). Una vez acabado de editar nuestro fichero, procederemos a aplicar los cambios:

monit reload

Aplicados los cambios, podremos acceder por un navegador web al puerto 2812, y administrar nuestro servidor, viendo una página parecida a la siguiente:

Monit

 

Añadiendo Firewall a nuestro VPS

Algo muy importante a tener en cuenta es que por lo general en los VPSs, es que por lo general no viene con una configuración de seguridad especial, por lo que tendremos que preocuparnos de que nuestro servidor esté correctamente protegido.

Podremos utilizar Uncomplicated Firewall (UFW), una herramienta simple de configurar para establecer un firewall en nuestro servidor:

sudo apt-get install ufw

Primeramente bloquearemos todo el tráfico, por regla general:

sudo ufw default deny incoming
sudo ufw default deny outgoing

Y añadiremos reglas para permitir SSH, DNS, HTTP, HTTP (por puerto 8080), HTTPS, Git y Monit:

sudo ufw allow 22
sudo ufw allow out 53
sudo ufw allow 80/tcp
sudo ufw allow 8080
sudo ufw allow 443
sudo ufw allow 9418/tcp
sudo ufw allow 2812

Por último, mostramos los comandos para activar, desactivar, y ver el estado de nuestro firewall:

sudo ufw enable
sudo ufw disable
sudo ufw status

Si ejecutamos ufw status, deberemos ver algo parecido a esto:

Configuración final UFW para servir nuestra aplicación Spring

Configuración final de UFW

 

Tras varios intentos, no conseguí que UFW me desbloqueara Git, pese a abrir los puertos pertinentes, por lo que se tendrá que utilizar ufw disable / enable cada vez que queramos hacer un pull de nuestro repositorio.

 

Conclusiones

Espero que este tutorial les haya sido de ayuda a todos aquellos que han querido disponer su aplicación Spring en producción de una manera fácil en su servidor privado. En caso de encontrar cualquier mejora a lo explicado, ¡me encantará escuchar vuestros comentarios!

 

Fuentes:

https://github.com/jhipster/jhipster-devbox/blob/master/scripts/setup.sh

https://docs.mongodb.org/v3.0/tutorial/install-mongodb-on-ubuntu/

https://mobiarch.wordpress.com/2014/05/16/creating-an-init-script-in-ubuntu-14-04/

https://www.digitalocean.com/community/tutorials/how-to-setup-a-firewall-with-ufw-on-an-ubuntu-and-debian-cloud-server

https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-monit

4 Comments
  1. En ubuntu 14.04 de AWS, luego de instalar npm, bower y gulp, si ejecutas bower install en la carpeta del proyecto sale el siguiente error/mensaje:

    /usr/bin/env: node: No such file or directory

    Para arreglarlo sólo necesitas ejecutar el siguiente comando y volver a ejecutar bower install:

    sudo ln -s /usr/bin/nodejs /usr/bin/node

    Saludos

    • ¡Perfecto!

      Por cierto, también me he topado con otro tipo de problemas en el arranque del perfil de producción. SI estáis ejecutando el servicio como root, añadir a .bowerrc:
      “allow_root”: true

      Saludos

    • ¡Muchas gracias Alfredo! Espero poder ayudar a todos aquellos que necesiten configurar su VPS para servir su aplicación

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *