Saltar al contenido
KHEN / ES
Menú
Todos los posts

Publicado 23 oct. 2019

Desplegando Laravel con LEMP Stack (Parte II): configurando Laravel y Git Hooks

Segunda parte de la guía para servir una aplicación Laravel desde tu propio VPS con LEMP Stack en Ubuntu 18.04.

En esta segunda parte nos enfocaremos en la instalación de Git, la configuración de nuestro Git Hook, la configuración de Laravel y de nuestro entorno de producción para poder servir correctamente nuestra aplicación Laravel.

Los artículos de esta mini-serie son los siguientes:

Sin más que añadir, continuemos.

10. Instalando Composer

Ya has instalado Composer anteriormente (de lo contrario no tendría mucho sentido que estés leyendo esta guía 🤔), por lo que este paso te resultará conocido. Accedemos por la terminal a nuestro servidor (mediante SSH) y ya en la consola ejecutamos:

Terminal window
cd ~ && curl -sS https://getcomposer.org/installer | php

Con esto tendremos ya el composer.phar en nuestro directorio de inicio, así que es hora de moverlo hacia el bin para poder ejecutarlo de manera más sencilla simplemente haciendo composer.

Terminal window
sudo mv composer.phar /usr/local/bin/composer

Puedes comprobar si todo salió bien ejecutando composer en la consola, debería de mostrarte todos los comandos disponibles de Composer.

11. Instalando Git

Git no es un desconocido para casi nadie hoy en día y es, básicamente, un estándar. Claro que puedes utilizar otros métodos de gestión de versiones (o incluso subir tus archivos vía SFTP), pero nosotros usaremos Git.

Instalaremos Git en nuestro servidor en un directorio llamado /var/repo/. Empecemos por ahí:

Terminal window
cd /var
mkdir repo && cd repo

Con esto, notaremos que ahora estamos dentro del directorio /var/repo/. Ejecutamos lo siguiente:

Terminal window
mkdir site.git && cd site.git
git init --bare

El flag --bare puede que te resulte nuevo, y esto es porque -por lo general- se utiliza únicamente en servidores. Un repositorio bare es de un tipo especial cuyo único propósito es recibir “pushes” de desarrolladores. Puedes aprender más sobre esto en la documentación oficial.

Con esto tendremos un repositorio Git en /var/repo/site.git, 👏👏.

12. Creando nuestro Git Hook

Conociendo los Hooks

Los repositorios Git tienen una función interesante llamada “hooks” (“ganchos”) que usaremos para mover nuestros archivos luego de ejecutar git push. Lo que hacen los hooks es ejecutar cierta acción cuando estos son activados. Hay tres tipos de hooks del lado del servidor en Git: pre-receive, post-receive y update (más info aquí).

En nuestro caso, haremos uso del post-receive hook, el cual se activará cuando el repositorio haya descargado tus archivos completamente luego de recibir un push.

Configurando nuestro Hook

Para crear nuestro hook necesitamos entrar al directorio hooks que se encuentra dentro de nuestro directorio site.git. Para hacerlo haremos:

Terminal window
cd /var/repo/site.git/hooks

Una vez dentro, crearemos nuestro script post-receive, el cual se ejecutará luego de recibir nuevo código. Esto lo haremos con ayuda de Nano:

Terminal window
sudo nano post-receive

Como ya sabemos, esto nos abrirá un archivo post-receive en blanco donde podremos añadirle contenido. Escribimos (o pegamos) lo siguiente:

/var/repo/site.git/hooks/post-receive
#!/bin/sh
git --work-tree=/var/www/laravel --git-dir=/var/repo/site.git checkout -f

Para pegar en la terminal puede que no te funcione el Ctrl + V; si es así, prueba Shift + Insert.

Ahora guardamos y salimos.

Para guardar los cambios apretaremos primero Ctrl + X, luego tipeamos Y y por último apretamos Enter.

¿Pero qué hemos hecho exactamente? Veamos.

La directiva --work-tree= le indica a Git dónde debe copiar los archivos recibidos luego de haber sido descargados por completo. Es por eso que le indicamos el directorio que contendrá nuestra app de Laravel. La directiva --git-dir= le dice a Git dónde está el repositorio bare que ha recibido el código. Es así de simple.

Luego de guardar el script, necesitamos ejecutar un comando más antes de dejar todo listo para recibir y copiar el código. El archivo post-receive necesita permisos de ejecución para poder copiar los archivos de un lado a otro. Para hacer eso ejecutamos lo siguiente (asegúrate de seguir dentro de /var/repo/site.git/hooks/):

Terminal window
sudo chmod +x post-receive

Eso es todo. Ahora estamos listos para enviar nuestro código al servidor; este será copiado a nuestro directorio de Laravel, el cual a su vez será leído por Nginx para que pueda servirlo hacia nuestros usuarios 👌.

Hemos acabado por el momento con la configuración de nuestro servidor, ahora necesitamos cerrar nuestra conexión SSH para volver a nuestra máquina local para el siguiente paso. Para salir, tan solo escribe exit.

Terminal window
exit

Tu línea de comandos se debe de haber cerrado (PuTTY) o ahora notarás que en la consola figura el nombre del usuario de tu sistema en lugar de root@localhost#.

13. Subiendo nuestro proyecto al servidor remoto

Configurando nuestro entorno local para subir código

Ahora que nuestro servidor está listo para recibir código, es hora de configurar nuestra computadora local para que apunte hacia este cuando queramos subir nuestros cambios a nuestro entorno de producción (nuestro servidor).

Cuando subimos nuestros archivos a GitHub/GitLab/Bitbucket, configuramos un git remote llamado origin que representa a nuestro almacén remoto de código (en este caso, GitHub). Así que cuando queremos subir nuestros cambios hacia GitHub ejecutamos un comando de este estilo: git push origin mi-rama. Esto le dice a Git que suba la rama (en este caso la rama llamada mi-rama) hacia nuestro origin remoto.

Haremos lo mismo nosotros. Crearemos un nuevo remote, al cual llamaremos production, el cual representará a nuestro servidor remoto. Nuestra meta es que cuando ejecutemos git push production master, Git suba nuestros cambios de la rama master a nuestro servidor remoto.

Esto no interfiere en absoluto con la subida de cambios a GitHub/etc., pues seguirá estando disponible el resto de remotes que tengamos configurados en nuestro proyecto, por ejemplo el origin: git push origin master. Puedes crear tantos remotes como desees: podrías tener uno para tu servidor staging, otro para el de production, etc.

Para crear un nuevo remote vamos al directorio donde tenemos nuestro proyecto, y desde ahí ejecutamos git remote add:

Terminal window
cd mis-sitios/kennyhorna # modifícalo para tu caso
git remote add production ssh://root@MI-DOMINIO-O-IP/var/repo/site.git

Asegúrate de reemplazar MI-DOMINIO-O-IP por tu dominio (o IP). En mi caso, lo cambiaré por la IP de mi servidor, pues aún no le hemos configurado ningún dominio. Como resultado, en mi caso sería algo así:

Terminal window
git remote add production ssh://root@203.0.113.10/var/repo/site.git

Subiendo nuestro proyecto

Con este comando ejecutado hemos configurado ya nuestro remote de producción. Así que -asumiendo que nuestro código está listo para ser subido- podemos proceder a subir nuestro código.

Terminal window
git push production master

Verificando que nuestro Git Hook funcione

Tenemos que comprobar que nuestro Hook funciona, de lo contrario, todo esto habría sido en vano ;). Para esto, vamos a volver a acceder a nuestro servidor mediante SSH:

Terminal window
ssh root@203.0.113.10 # adáptalo a tus parámetros

Ahora listaremos los archivos que contiene nuestro directorio especial de Laravel:

Terminal window
ls /var/www/laravel

Lo que hace el comando ls es listar los archivos y directorios que contiene el directorio desde donde se ejecuta.

Por tanto, si todo salió bien, deberíamos ver todos nuestros archivos de Laravel 🎉🎉.

Listado de /var/www/laravel en el servidor con todos los archivos del proyecto Laravel

14. Configurando nuestra Base de Datos

En la primera parte de esta guía instalamos MySQL, pero no hicimos mayor configuración. Aún ni siquiera hemos creado la base de datos que utilizará nuestro proyecto. Resolvamos esto de una vez.

Accederemos a la consola de MySQL con el siguiente comando:

Terminal window
mysql -u root -p'tu-clave'

Asegúrate de reemplazar tu-clave por la clave que estableciste en tu base de datos. Observación: nota que no hay espacio entre la p y el primer '.

Si todo marchó bien, deberías ver que la línea de comandos ahora empieza con mysql>:

Consola de MySQL tras iniciar sesión como root, con el prompt mysql> esperando comandos

Esto nos indica que accedimos a MySQL, por lo tanto, ya podemos crear nuestra base de datos. Dado que estoy subiendo un proyecto de prueba, mi base de datos se llamará my_site. Ajusta esto a tus necesidades:

CREATE DATABASE my_site;

Para validar que nuestra DB ha sido creada, podemos ejecutar:

SHOW DATABASES;

Resultado de SHOW DATABASES con la nueva base de datos my_site en la lista

Con esto, ya podemos salir de MySQL. Ingresamos exit y le damos a Enter.

exit

15. Configurando Laravel

Instalando nuestras dependencias

Para comenzar, debemos instalar las dependencias de nuestra aplicación pues, de lo contrario, no funcionará como se debe. Para esto, haremos uso de Composer, herramienta que instalamos al inicio de este artículo.

Nos situaremos dentro de la carpeta que contiene nuestro proyecto (cd /var/www/laravel) y desde ahí ejecutaremos:

Terminal window
composer install --no-dev

El flag --no-dev le indicará a Composer que ignore las dependencias de desarrollo. Dado que nuestro entorno remoto está pensado para ser usado en producción, tiene todo el sentido del mundo hacer esto.

Estableciendo permisos

Para poder correr como se debe, Nginx necesita ciertos permisos sobre nuestro directorio Laravel. En primer lugar, necesitamos cambiar el grupo dueño de nuestro directorio de Laravel a nuestro grupo web.

Terminal window
sudo chown -R :www-data /var/www/laravel

Ahora el grupo web es dueño de los archivos, en lugar del usuario root. A continuación, necesitamos darle permisos de escritura a nuestro grupo web sobre el directorio storage de tal modo que pueda escribir sobre este folder. Es aquí donde almacenamos nuestros logs, cache, entre otras cosas. Para hacer esto hacemos:

Terminal window
sudo chmod -R 775 /var/www/laravel/storage

Del mismo modo, también debemos darle permiso de escritura sobre el directorio bootstrap/cache:

Terminal window
sudo chmod -R 775 /var/www/laravel/bootstrap/cache

Ok, ahora nuestros directorios son “writables”. Aún nos quedan cosas por hacer, pero nos estamos acercando bastante a completar una instalación exitosa ;)

16. Configurando nuestro entorno remoto de Laravel

Todo lo que nos falta hacer por ahora es configurar nuestra aplicación Laravel. Esto lo haremos de la misma manera que lo haríamos en un entorno local. Utilizaremos los archivos que están dentro de config y también configuraremos nuestro archivo .env.

Como ya sabrás, todos los archivos que están listados en nuestro .gitignore serán ignorados por Git, por tanto acá es donde incluimos archivos/carpetas que no queremos que nuestro VCS gestione, ya sea por motivos de seguridad o de facilidad.

Archivo .gitignore por defecto de Laravel abierto en el editor, con /vendor, /node_modules y .env en la lista

Un ejemplo es el directorio /vendor: este directorio tiene todas las dependencias que nuestra aplicación necesita. Sin embargo, dado que sí incluimos composer.json y composer.lock en nuestro VCS, Composer podrá saber qué dependencias y qué versión específica de cada una de ellas necesita nuestra aplicación para poder instalarlas, por tanto incluir esta carpeta se hace un poco redundante. Es por eso que la ignoramos. Lo mismo sucede con el directorio node_modules, gestionado de manera análoga por los archivos package.json y package-lock.json.

Entonces, en resumen: todo lo que consideremos vital para nuestra aplicación no debería de estar listado en nuestro .gitignore.

Entendiendo el archivo .env

El .env contiene (o debería contener) todas las llaves y detalles de la configuración de nuestra aplicación. Esto incluye: detalles de nuestra aplicación y entorno, la llave de encriptación de nuestra app, la configuración de nuestra(s) base(s) de datos, la configuración de nuestro servidor de emails y mucho más.

Ahora te preguntarás: ¿por qué aparece el .env en nuestro .gitignore, si es tan clave para Laravel? La respuesta es simple: muchas de estas configuraciones son específicas de cada entorno (de ahí su nombre: env es diminutivo de environment, que significa ambiente/entorno). Veamos un ejemplo.

En nuestro entorno local puede que utilicemos un motor de base de datos más simple como SQLite; con esta base de datos trabajamos y todo bien. Puede que nuestra aplicación, en el entorno real de producción, necesite un motor de base de datos distinto -como por ejemplo MySQL o SQL Server- entonces, para poder hacer realidad esto de manera simple, podríamos tener definido un driver y una conexión a base de datos en nuestro entorno remoto que difiera de los de nuestro entorno local. ¿Dónde haríamos estas diferencias? Estás en lo correcto: en nuestro .env.

Si no fuera de este modo, cada vez que hicieras cambios en tu aplicación, tendrías que cambiar tus llaves de SQLite por las del otro motor de base de datos para luego recién subir tus cambios al servidor (y viceversa para cuando quieras hacer pruebas locales). Por tanto, utilizando el .env podemos hacer los mismos cambios en dos entornos distintos y cada uno funcionará dependiendo de la configuración específica que tenga en su correspondiente entorno. Magnífico.

Ahora que ya sabemos el motivo del uso de los .env, vamos a proceder a crear uno.

Creando nuestro archivo .env

Si nos fijamos (ls -A /var/www/laravel) veremos que si bien no tenemos el .env, sí que tenemos uno similar: .env.example. Podemos utilizar este otro fichero como modelo para crear nuestro .env.

Tal vez hayas notado que incluimos el flag -A al listar los archivos del directorio laravel (ls -A /var/www/laravel): lo que hace este argumento es incluir en el listado los archivos ocultos.

Entonces, lo que haremos será copiar el .env.example como .env y colocar en este último los parámetros de nuestra aplicación, como por ejemplo, la conexión a la base de datos que creamos en uno de los pasos anteriores. Nos situaremos dentro de nuestra carpeta de Laravel:

Terminal window
cd /var/www/laravel
cp .env.example .env

Con esto ya tendremos nuestro .env clonado. Ahora procederemos a personalizarlo con ayuda de Nano.

Terminal window
nano .env

Al hacer esto nos mostrará algo parecido a lo siguiente:

Archivo .env recién copiado de .env.example abierto en Nano, con los valores por defecto de Laravel

Dado que estamos en un entorno de producción, podemos hacer unos cambios iniciales como:

APP_NAME="El nombre de mi App"
APP_ENV=production
APP_DEBUG=false
APP_URL=http://mi-dominio-o-mi-ip

APP_NAME y APP_URL se describen solos. APP_ENV le indica a Laravel que estamos en un entorno de producción. APP_DEBUG le indica si debe mostrar los errores extensos o si, en cambio, queremos que se manejen de una manera más humana (que es lo que queremos en un entorno de producción, dado que serán nuestros usuarios quienes vean estos mensajes).

Habrás notado que ignoramos la llave APP_KEY; descuida, esto lo generaremos con un comando más adelante.

Paso seguido, pondremos los detalles de nuestra base de datos, para que Laravel pueda acceder sin problemas.

Para esto modificaremos las siguientes llaves:

DB_HOST=localhost
DB_DATABASE=my_site
DB_USERNAME=root
DB_PASSWORD=*******

Estas llaves también son simples de deducir. DB_HOST le indica a Laravel el host donde está alojada nuestra base de datos. Si nuestra base de datos estuviera en otro servidor, podríamos indicarle ahí el dominio (o IP) al que apuntar. DB_DATABASE es el nombre de la base de datos que creamos más arriba, en mi caso my_site. Dado que estoy usando el usuario root en mi base de datos, colocaremos esto en DB_USERNAME y, por tanto, en DB_PASSWORD colocaremos la clave de este usuario.

Tal vez querrás ajustar la configuración de tus drivers de cache, queue, session, etc. Todo esto lo podrás hacer en este archivo, por ejemplo la configuración del servidor que manejará los emails.

Así que nuestro .env quedaría de la siguiente forma (grosso modo):

.env
APP_NAME="Mi nueva App"
APP_ENV=production
APP_KEY=
APP_DEBUG=false
APP_URL=http://203.0.113.10
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=my_site
DB_USERNAME=root
DB_PASSWORD=*******
BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null

Generando nuestra llave de encriptación

Tal como mencioné anteriormente, vamos a generar nuestra llave de encriptación con ayuda de un comando del propio Laravel. Para esto ejecutamos:

Terminal window
php artisan key:generate

Con esto, Laravel generará y almacenará automáticamente nuestra llave en nuestro .env bajo APP_KEY.

Hay muchos otros ajustes que podemos configurar en nuestra aplicación; no en vano tenemos un directorio específico para todos los archivos de configuración de nuestra app: config. Dado que estos archivos sí están considerados por Git, podemos modificarlos en nuestro entorno local, hacer un commit con estos cambios y subirlos a nuestro servidor remoto haciendo un push a production.

Guardando en caché nuestra configuración

Dado que hay muchos apartados de configuración, es buena idea guardar en caché estos valores. Para esto podemos hacer:

Terminal window
php artisan config:cache

Ten en cuenta que luego de cada modificación que hagamos a la configuración deberemos limpiar esta caché, de lo contrario Laravel ignorará estos cambios. Para hacer esto podemos volver a ejecutar el mismo comando, el cual limpiará cualquier caché existente y la regenerará.

Terminal window
php artisan config:cache # Regenera la caché tomando los cambios

17. Migrando nuestra base de datos

Ahora que tenemos nuestra configuración lista, podemos proceder a migrar nuestra base de datos. Para esto ejecutamos, como ya sabemos:

Terminal window
php artisan migrate

Nos preguntará si estamos seguros de correr este comando pues estamos en un entorno de producción; escribimos yes y damos Enter.

Salida de php artisan migrate en producción: se confirma con yes y se crean las tablas por defecto

Dado que estoy subiendo una instalación fresca de Laravel, en mi caso solo migrará las tablas por defecto que trae: users, password_resets y failed_jobs.

Poblando nuestra base de datos

Podemos poblar nuestra base de datos mediante Seeders. Si tuvieras configurados tus seeders para poblar tus tablas maestras, es buen momento de correrlos. Para esto haríamos:

Terminal window
php artisan db:seed

Si -tal como en mi caso- no tienes configurados Seeders, podemos hacer uso de Tinker para agregarle un usuario a nuestra app. Para acceder a Tinker hacemos:

Terminal window
php artisan tinker

Con Tinker podemos ejecutar comandos de Laravel de manera automática y simple. Entonces, ahora crearemos una nueva instancia del -en mi caso- modelo User, que es el que tengo como tabla principal. Le añadiremos datos y por último la guardaremos en la base de datos:

$u = new App\User;
$u->name = 'Mesut Özil';
$u->email = 'mesut.ozil@arsenal.com';
$u->password = Hash::make('assist-king');
$u->save();
exit

Con esto habremos creado nuestro usuario con éxito.

Sesión de Tinker creando un usuario de prueba y guardándolo en la base de datos

Podrás notar que para el campo password le apliqué un “hasheo” a la contraseña. Esto es para darle una capa adicional de seguridad a nuestro sistema. Por defecto, al hacer un intento de login, Laravel comparará la contraseña que le brindemos (luego de haberla “hasheado”) con la que tengamos en nuestra base de datos. Estas deberían de coincidir.

Para hacer Hashing, Laravel usa bcrypt por defecto, que le agrega una sal distinta a cada contraseña. La llave APP_KEY de nuestro .env no interviene aquí: Laravel la usa para encriptar datos, como las cookies y la sesión.

Cierre

🎉🎉🎉🎊 ¡Felicidades! 🎊🎉🎉🎉, con esto ya tenemos nuestro VPS configurado con todo en orden para poder utilizar nuestra aplicación Laravel y subir cambios hacia esta de manera rápida y simple. Podemos comprobarlo dirigiéndonos hacia nuestro dominio (o en mi caso, hacia nuestra IP): deberíamos ver la página de bienvenida de Laravel.

Como hemos podido ver, el proceso es un poco largo, pero he tratado de incluir el máximo detalle posible para que quede claro qué hacemos en cada paso.

Es importante saber el QUÉ, pero más importante aún, saber el POR QUÉ de lo que hacemos.

Ya tenemos nuestra aplicación funcionando. Solo nos queda configurar nuestro dominio en nuestra app y agregarle un certificado SSL. Esto lo veremos en la tercera -y última- parte:

Si tienes dudas sobre los pasos anteriores, visita la Parte I (Instalación y configuración de LEMP Stack) de la guía.

Cualquier comentario, observación, pregunta y/o aclaración es bien recibida así que… nos vemos 💪😉.