Instalar Laravel en AWS usando un Load Balancer, RDS, S3, VPC.
La idea de esta guia es ayudarte a lanzar tu aplicacion Laravel de 0 en un AWS con buenas practicas de seguridad y utilizando todos los recursos que ofrece AWS para decoplar tu aplicacion.
Intro:
Generalmente, cuando desarrollamos aplicaciones corremos todo en local, mysql, php, almacenamiento, etc. Esto nos funciona para desarrollo, pero para produccion puede ser un dolor de cabeza.
Si montas todo en un server ec2, si algo llega a pasarle a ese servidor (muchas veces AWS saca el server de circulacion) entonces hay que hacer una migracion fuerte.
Cuando decoplas aplicaciones, usas varios servicios, por ejemplo RDS, lo cual es un sistema de base de datos administrado por Amazon, es decir puedes escalar tu base de datos on demand, agregar mas GB de disco duro, entra otras opciones.
Asi como RDS para base de datos, hay S3 (cloud storage), Cloudfront (CDN) ElasticCache (Redis). Amazon se encarga de la administracion y asi te dedicas a crear aplicaciones!
Tabla de contenido
Para este tutorial, vamos a explica y montar una aplicacion desde 0 con:
- VPC ( Virtual private cloud) Net, Subnets, Gateways.
- EC2 Con la aplicacion Laravel o cualquier otro framework.
- Load balancer (balanceador de cargas).
- RDS Base de datos mysql administrada por Amazon.
- S3.
- ElasticCache (Redis).
VPC (Virtual Private Cloud)
Virtual Private Cloud (VPC), es practicamente una red virtual adonde tus servers y servicios se pueden comunicar entre ellos por conexion local y por un Gateway tener conexion al internet.
AWS quiere ponerte a usar sus servicios lo antes posible, entonces ellos ya tienen con un VPC Default para que no te tengas que preocupar. la IP default de esta red es:
172.31.0.0/16
Esta configuracion default es buena, pero termina siendo muy generica y tiene muchas debilidades.
VPC – Configuracion
Paso 1:
Ir a tu consola de AWS, irte a tu region, buscar VPC y vas a ver algo asi:
Usa Oregon, N.California, N.Virgina ya que son centros de costo mas economicos.
Paso 2:
Click en Create VPC, pone nombre a tu red, en nuestro caso “Production” Selecciona el IP de la red, en nuestro caso: 10.0.0.0/16
Paso 3:
En el caso de Oregon tenemos 2 o 4 availability zones:
us-west-2a us-west-2b us-west-2c us-west-2d
Que significa esto? Que Amazon tiene 4 areas fisicas de servers en Oregon. Si uno de esos centros le pasa algo fisicamente o tecnologicamente, tenes otra zona adonde puede estar tu aplicacion.
Entre mas zonas en el mundo (por ende mas caro) tengas tus aplicacion, datos, procesamiento equivale a carga mas rapida, si se algo le pasa a un pais adonde esten tus servers, tu aplicacion puede esta up & running si problema.
Para este ejemplo solo vamos a usar estas 4 zonas.
Click en Create Subnet
- Usa el nombre “10.0.1.0_Prod_WEST_2A_PUB” que seria (Subnet IP, Production, West, zone 2A, Public access)
- Selecciona Production VPC ( La que hicimos en el paso anterior)
- Escoje tu zona de availability
- Selecciona Subnet IP (/24 = 251 IPs disponibles. porque 251 y no 256 IPs? Los primeros 4 y el ultimo estan reservados para la Subnet
Repite este paso en todas tus zonas de availability. Haz una subnet para la base de datos que luego no podra ser accesada por el internet si no, solo local
Paso 4:
Ahora necesitamos darle acceso a internet a nuestro VPC Production.
Ve a Internet Gateway
- Click Create Internet Gateway
- Una vez listo, haz click en attach y selecciona tu VPC.
Paso 5:
Ahora necesitamos asignarle internet al VPC, y seleccionar las subnets que van a tener internet.
Ve a Routes Table
- Click en el RT que tiene el VPC ( se crea automatico cuando haces el VPC)
- Routes, Edit Routes
- Agrega el ip 0.0.0.0/0 con target al gateway que hiciste “igw-xxxx”.
- Save Routes
Ahora necesitamos seleccionar cuales subnets dentro de nuestra VPC van a tener acceso a internet.
- Click en Subnet Associations
- Edit subnet associations
- Selecciona las subnets que tienen van a tener acceso a internet. Pro tip: la DB no deberia tener acceso al internet por seguridad.
Paso 6:
Ahora necesitamos asignar una capa opcional de seguridad a nuestros subnets dejado solo pasar traffico por el puerto 80 o 443 a nuestras subnets publicas y trafico de las subnets en la VPC a la subnet privada por el puerto 3306 (mysql) 6379 (redis).
En otras palabras, solo los servidores en las subnets privadas seran accesadas desde el mundo solo por los puertos 22, 443 y 80. Estos serves accederan a la base de datos solo si estan en la VPC y si los accesan solo por el puerto 3306.
Ve a Network ACL
- Selecciona la default ACL relacionada a nuestro VPC.
- Selecciona inboud rules
- Selecciona los puertos que quieres dejar abiertos
- Save
Ahora nos toca hacer lo mismo pero para la subnet privada
- Selecciona Create Network ACL, ponele nombre y asignalo al VPC.
- Selecciona inboud rules
- Selecciona los IPs (o network) y puertos que quieres dejar abiertos a la red privada mysql 3306, redis 6379
- Si quieres acceder a los servidores en esta subnet, deberás hacerlo desde la subnet pública (El término en inglés es Bastion Server). Abre el puerto 22 al Bloque de Ips de las subnets publicas que quieras permitir (10.0.1.0/24 por ej.)
- Save
Paso 7:
Ahora necesitamos configurar los Security Groups para que los puertos 80 & 443 esten abiertos al mundo y puedan entrar a nuestro VPC & Subnets Publicas.
Tambien nuestra base de datos deberia ser accesada a nivel de red privada, osea todos los servers en todas las zonas de availability.
- Crea el security group (o modifica el que ya existe asignado a nuestro VPC)
- Selecciona Nombre, VPC, Save
- Selecciona SG, Click inbound Rules
- Puerto80, 443 from anywhere
- Puerto 22 from my IP (or VPN)
- Save
Importante:
- Click Outbound Rules
- Agrega todos los puertos que deberán conectarse a tu subnet privada desde la publica.
- En el caso de la SG de tu red privada, en tu inbound, de manera similar, agregar los puertos que abrirás a tu red pública, esto permitirá hacer uso de uno o varios Bastion Server, que te permiten acceder a recursos en tu Subnet Privada.
Haremos exactamente lo mismo para nuesto SG de base de datos. Solo que seleccionaremos el puerto 3306 y el IP de la VPC osea
10.0.0.0/16
De esta manera, la base de datos tendra acceso solo por los recursos en esa VPC.
Ya con esto finalizamos nuestro VPC son subnets privadas y publicas! Felicidades 🍻!
RDS – Base de datos
Vamos a inicializar el servicio de RDS para nuestra base de datos para nuestra aplicacion.
- Ve a tu consola
- Busca RDS
- Create Database
- Nombre de la instancia – DB instance identifier
- Master username
- Master password
- Tamano de instancia – DB Instance size (t2.medium)
- Storage GB (100gb default. puede ser mas o menos pero lo puedes cambiar mas adelante)
- Availability & durability. Si lo dejas en Create a standby instance on, va a replicar esta DB en varias regiones lo cual es bueno pero puede hacer que tu DB se vuelva super cara. Yo selecciono do not create stand by instance
- Connectivity: Production VPC
- Publicly accessible: NO
- VPC security groups: Production Private VPC
- Availability zone: Cual subnet quieres usar, en nuestro caso west-2c
- Costo aprox: 162.14 USD por mes
Ahora, los credenciales deberian de verse algo asi:
url: production-db.trfvbhytf6.us-west-2.rds.amazonaws.com username: master_user password: yCNuwSnx37ngntgD puerto: 3306
Es importante recalcar que esta base de datos (configurada correctamente) no tiene acceso desde afuera. Cualquier persona con los accesos directos a la DB no podria entrar a ver o manipular datos.
La unica manera seria teniendo acceso al VPC. Aca es adonde las subnets, SG y Network ACL protejen nuestra applicacion.
Elastic Cache Redis
Si nuestra aplicacion esta usando Redis aca dejo la configuracion, si no, puedes saltarte esto.
- Ve a tu consola
- Busca ElasticCache
- Redis, Create
Ahora tenemos que configurar en que red esta esto y seleccionar el SG.
Crea un SG nuevo que se llame Production Redis Private, este servicio no deberia tener acceso, solo local. Abre el puerto 6379 con el source de tu VPC (10.0.0.0/16) asi todos las las aplicaciones en el VPC puedan accesar esta instancia de redis.
EC2 – Configuracion inicial
Aca podemos seleccionar hacer un EC2 de alguna imagen que ya tengamos (AMI) o configurar el server de 0.
Es importante las siguientes configuraciones que van a ayudar a determinar la VPC, Subnet y asingacion de IP:
EC2 – Instalar Laravel
Aca vamos a instalar Laravel, pero el concepto que llevamos hasta ahora puede ser una aplicacion en JS, Java, Python etc.
Voy a asumir que sabes hacer un EC2 y conectarte remoto al server (tienes que abrir el puerto 22 en el SG y Network a tu ip si quieres configur el server).
Tambien voy a asumir que sabes instalar Laravel, no voy a entrar mucho en detalle porque ya lo tengo instalado en una imagen.
Si no, te dejo aca los pasos:
#Update Linux sudo apt-get update sudo su
#Download Nginx nginx=stable add-apt-repository ppa:nginx/$nginx apt-get update apt-get install nginx nginx -v
#Configure PHP apt-get install python-software-properties add-apt-repository ppa:ondrej/php apt-get update apt-get install php7.2 php7.2-msql php7.2-mysql php7.2-fpm php7.2-xml php7.2-gd php7.2-opcache php7.2-mbstring apt install zip unzip php7.2-zip
#Composer,Laravel, Permission curl -sS https://getcomposer.org/installer | php mv composer.phar /usr/local/bin/composer cd /var/www #2 opciones, ## 1) proyecto nuevo: composer create-project laravel/laravel test --prefer-dist ## 2) Clonar de github git clone https://github.com/crsurfer/test.git chown -R www-data:www-data test/ chmod -R 775 test/
#Configure Nginx cd /etc/nginx/sites/available // or ../sites/default
Ahora del file NGINX deberia de verse algo asi:
server { listen 80 default_server; listen [::]:80 default_server; root /var/www/test/public; index index.php index.html index.htm index.nginx-debian.html; server_name _; location / { try_files $uri $uri/ =404; } location ~ \.php$ { include snippets/fastcgi-php.conf; # With php-fpm (or other unix sockets); fastcgi_pass unix:/var/run/php/php7.2-fpm.sock; # With php-fpm (or other unix sockets); } }
Y por ultimo:
service nginx restart
Checkpoint
Para este momento, ya deberias de tener:
- VPC configurados
- Segurity Groups en orden
- Network ACLs en orden
- Puerto 22 con tu IP en el SG para configurar el server
- Redis ya inicializado
- RDS ya inicializado
SSH
Vamos a utilizar Putty para connectarnos al server. Cuando creamos la instancia EC2, nos pidio que usaramos una llame o hicieramos una, el archivo es .pem puedes conectarte con la pem directo desde linux o mac, pero como yo tengo PC tenemos que usar una herramienta que viene con la instalacion de putty, putty gen.
Seleccionamos load key, all files y seleccionamos la llave PEM, luego salvamos private key y esta genera un PPK ( puedes usar passphrase para mas seguridad)
Luego con el Putty, pone la llave, ip, y user (ubuntu).
Una vez adentro de la consola, podemos irnos a la ruta adonde este nuestro proyecto.
En mi caso:
cd /var/www/test
Configurando la Base de Datos
Ya que la DB no tiene acceso publico, tenemos que usar la linea de comando para crear una DB, usuario y dale los permisos.
sudo apt install mysql-client-core-5.7 mysql -u master_user -p -h production-db.eefsvervrybhju8.us-west-1.rds.amazonaws.com
Si todo ha salido bien, deberia preguntarnos por el password y entrar directo a la consola
mysql> create database production; Query OK, 1 row affected (0.00 sec)
Ahora ya tenemos la DB, ahora creamos el usuario y le damos los permisos. Le damos permiso solo al usuario app_admin para que accese el servicio desde cualquiera de las 256 ips en cada subnet (10.0.1.%) etc.
GRANT ALL PRIVILEGES ON production.* TO 'app_admin'@'10.0.1.%' IDENTIFIED BY 'S3Cr3TP@$$w0rD' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON production.* TO 'app_admin'@'10.0.2.%' IDENTIFIED BY 'S3Cr3TP@$$w0rD' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON production.* TO 'app_admin'@'10.0.3.%' IDENTIFIED BY 'S3Cr3TP@$$w0rD' WITH GRANT OPTION;
Configurando Laravel
Ya que tenemos la DB configurada podemos editar el .env de nuestra aplicacion en Laravel.
sudo nano .env
y aca ponemos nuestros credenciales:
DB_CONNECTION=mysql DB_HOST=production-db.eefsvervrybhju8.us-west-1.rds.amazonaws.com DB_PORT=3306 DB_DATABASE=production DB_USERNAME=app_admin DB_PASSWORD=S3Cr3TP@$$w0rD
Y ahora corremos los comandos de Laravel
composer install php artisan key:generate php artisan migrate
Si todo ha salido bien, veremos los comandos de artisan y el estatus de las migraciones!