Introducción
Drive es una biblioteca de abstracción de almacenamiento en AdonisJS. Proporciona una API coherente que funciona en todos los proveedores de almacenamiento.
Drive tiene un controlador S3 para admitir el almacenamiento en la nube compatible con S3, como Vultr Object Storage. Esta guía explica cómo configurar AdonisJS Drive para Vultr Object Storage y usarlo para almacenar y leer archivos.
requisitos previos
Antes de comenzar, debe:
-
Cree un usuario no root con sudo privilegios
Instalar Node.js
AdonisJS requiere al menos la versión 14 de Node.js. Puede instalar la última versión de Node.js mediante Node Version Manager (NVM).
-
Instalar NVM:
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
-
Desconecte y vuelva a conectar su sesión ssh.
-
Instale Node.js:
$ nvm install node
-
Compruebe la versión de Node.js:
$ node -v v19.3.0
Crear almacenamiento de objetos
-
Iniciar sesión en Portal de clientes Vultr .
-
Navegar a Productos -> Objetos .
-
Agregar almacenamiento de objetos . Elija la región y asígnele una etiqueta.
-
Haga clic en su almacenamiento de objetos y vaya a la pestaña Cubo.
-
Cree un depósito y asígnele un nombre.
-
Toma nota de la
Hostname
laSecret Key
laAccess Key
y elBucket Name
.
Crear nueva aplicación AdonisJS
Vaya al directorio de inicio.
$ cd ~
Cree un nuevo directorio para su aplicación.
$ mkdir app
Ve a la app
directorio y generar una nueva aplicación AdonisJS usando el npm init
dominio.
$ cd app
$ npm init [email protected] website
-
Seleccione la estructura del proyecto web.
-
Elija ‘y’ cuando le solicite que configure el Webpack Encore.
Genera tu app en el website
directorio. Para las tareas restantes, debe ejecutarlas en el website
directorio.
$ cd website
Instalar Redis
La aplicación de muestra de esta guía utiliza Redis para almacenar los nombres de archivo de las imágenes.
Instalar Redis:
$ sudo apt install redis-server
Configure el modo persistente de Redis:
-
Abra el archivo de configuración de Redis:
$ sudo nano /etc/redis/redis.conf
-
Cambiar el
appendonly no
aappendonly yes
. -
Guardar archivo y salir.
-
Reinicie Redis.
$ sudo systemctl restart redis-server
Instale y configure el paquete AdonisJS Redis:
$ npm i @adonisjs/redis
$ node ace configure @adonisjs/redis
Abre el env.ts
expediente:
$ nano env.ts
Agregue las siguientes reglas:
REDIS_CONNECTION: Env.schema.enum(['local'] as const),
REDIS_HOST: Env.schema.string({ format: 'host' }),
REDIS_PORT: Env.schema.number(),
REDIS_PASSWORD: Env.schema.string.optional(),
Configurar la unidad AdonisJS
AdonisJS Drive tiene un controlador S3 para interactuar con almacenamiento en la nube compatible con S3 como Vultr Object Storage.
Instale y configure el controlador S3:
$ npm i @adonisjs/drive-s3
$ node ace configure @adonisjs/drive-s3
Abre el env.ts
expediente:
$ nano env.ts
Actualizar el DRIVE_DISK
normas:
DRIVE_DISK: Env.schema.enum(['local','s3'] as const),
Agregue las siguientes reglas:
S3_KEY: Env.schema.string(),
S3_SECRET: Env.schema.string(),
S3_BUCKET: Env.schema.string(),
S3_REGION: Env.schema.string(),
S3_ENDPOINT: Env.schema.string.optional(),
Abre el config/drive.ts
expediente:
$ nano config/drive.ts
Agregue las configuraciones de S3 dentro del disks
objeto:
s3: {
driver: 's3',
visibility: 'public',
key: Env.get('S3_KEY'),
secret: Env.get('S3_SECRET'),
region: Env.get('S3_REGION'),
bucket: Env.get('S3_BUCKET'),
endpoint: Env.get('S3_ENDPOINT'),
}
Abre el .env
expediente:
$ nano .env
Actualizar el DRIVE_DISK
valor a s3
:
DRIVE_DISK=s3
Agregue las credenciales de Vultr Object Storage:
S3_KEY=
S3_SECRET=
S3_BUCKET=adonis-drive
S3_REGION=sgp1
S3_ENDPOINT=https://sgp1.vultrobjects.com
-
S3_KEY
es su clave de acceso al almacenamiento de objetos Vultr. -
S3_SECRET
es su clave secreta de almacenamiento de objetos Vultr. -
S3_BUCKET` es el nombre de su depósito de almacenamiento de objetos Vultr.
-
S3_ENDPOINT
es su nombre de host de almacenamiento de objetos Vultr. -
S3_REGION
es su región de almacenamiento de objetos Vultr.
Añadir Tailwind CSS
Esta guía utiliza Tailwind CSS para el marco CSS. Instale Tailwind CSS y sus dependencias a través de NPM:
$ npm install -D tailwindcss postcss autoprefixer postcss-loader
Abre el webpack.config.js
expediente:
$ nano webpack.config.js
Habilite el cargador PostCSS:
Encore.enablePostCssLoader()
Cree y abra el archivo de configuración Tailwind CSS:
$ npx tailwindcss init -p
$ nano tailwind.config.js
Cambia el contenido a:
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./resources/**/*.edge",
"./resources/**/*.js",
],
theme: {
extend: {},
},
plugins: [],
}
Abre el resources/css/app.css
y reemplace el contenido por las directivas CSS de Tailwind:
@tailwind base;
@tailwind components;
@tailwind utilities;
Agregar JavaScript
Abre el resources/js/app.js
y agregue los siguientes scripts:
import '../css/app.css'
document.getElementById('fileImage').addEventListener('change',function(){
if( this.files.length > 0 ){
document.getElementById('uploadBtn').removeAttribute('disabled');
}
});
Los scripts habilitan el botón de carga después de que el usuario seleccione el archivo de imagen.
Crear vista
Crear un resources/views/gallery.edge
expediente:
$ nano resources/views/gallery.edge
Agrega el siguiente código:
<html>
<head>
<title>Gallery</title>
@entryPointStyles('app')
</head>
<body>
<div class="max-w-7xl m-auto">
<h1 class="text-3xl font-bold text-gray-900 text-center py-8 uppercase">Gallery</h1>
<form action="" method="post" enctype="multipart/form-data" class="flex flex-wrap text-center justify-center items-start p-4 rounded-lg">
<label class="block py-1">
<input id="fileImage" type="file" name="fileImage" class="block w-full text-sm text-slate-500 pr-6
file:cursor-pointer
file:mr-4 file:py-2 file:px-4
file:rounded-full file:border-0
file:text-sm file:font-semibold
file:bg-indigo-50 file:text-indigo-700
hover:file:bg-indigo-100
"/>
@if (flashMessages.has('errors.fileImage'))
<span class="block text-red-700 py-4 text-left">{{ flashMessages.get('errors.fileImage') }}</span>
@endif
</label>
<button id="uploadBtn" disabled class="rounded border border-transparent bg-indigo-600 px-6 py-2 text-base font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 disabled:opacity-50" type="submit">
Upload Image
</button>
</form>
<div class="grid grid-cols-2 gap-x-4 gap-y-8 sm:grid-cols-3 sm:gap-x-6 lg:grid-cols-4 xl:gap-x-8 ">
@each(image in images)
<div>
<img class="rounded" src="">
</div>
@end
</div>
</div>
@entryPointScripts('app')
</body>
</html>
Crear controlador
Crea y abre el GalleryController.ts
expediente:
$ node ace make:controller GalleryController -e
$ nano app/Controllers/Http/GalleryController.ts
Importe bibliotecas y ayudantes en la parte superior del archivo:
import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import Drive from '@ioc:Adonis/Core/Drive'
import Redis from '@ioc:Adonis/Addons/Redis'
import { string } from '@ioc:Adonis/Core/Helpers'
import { schema } from '@ioc:Adonis/Core/Validator'
Crear el index
acción. Muestra el formulario de carga y enumera todas las imágenes de su almacenamiento de objetos Vultr. Obtiene los nombres de archivo de imagen de Redis y llama al getUrl
de la biblioteca de Drive para obtener la URL de cada imagen.
public async index({ view }: HttpContextContract) {
const galleryString = await Redis.get('gallery')
const gallery = (galleryString) ? JSON.parse(galleryString) : []
let images:string[] = []
for (const filename of gallery) {
const url = await Drive.getUrl(`gallery/${filename}`)
images.push(url)
}
return view.render('gallery', { images })
}
Crear el upload
acción. Maneja cuando un usuario sube sus imágenes. Valida el archivo, guarda el nombre del archivo en Redis y luego almacena el archivo en Vultr Object Storage usando el moveToDisk
método.
public async upload({ request, response }: HttpContextContract) {
const imageSchema = schema.create({
fileImage: schema.file({
extnames: ['jpg', 'png', 'gif']
}),
})
const payload = await request.validate({ schema: imageSchema })
const filename = `${string.generateRandom(32)}.${payload.fileImage.extname}`
if (payload.fileImage) {
await payload.fileImage.moveToDisk(", {
name: `gallery/${filename}`
}, 's3')
const galleryString = await Redis.get('gallery')
let gallery:string[] = []
if (galleryString) {
gallery = JSON.parse(galleryString)
}
gallery.push(filename)
await Redis.set('gallery', JSON.stringify(gallery))
}
return response.redirect().toPath("https://www.vultr.com/")
}
Debe guardar y obtener los nombres de archivo de imagen de Redis porque el controlador AdonisJS S3 no puede obtener una lista de archivos en un depósito o carpeta. Solo puede obtener un archivo a la vez.
El siguiente es el contenido completo del GalleryController.ts
expediente:
import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import Drive from '@ioc:Adonis/Core/Drive'
import Redis from '@ioc:Adonis/Addons/Redis'
import { string } from '@ioc:Adonis/Core/Helpers'
import { schema } from '@ioc:Adonis/Core/Validator'
export default class GalleryController {
public async index({ view }: HttpContextContract) {
const galleryString = await Redis.get('gallery')
const gallery = (galleryString) ? JSON.parse(galleryString) : []
let images:string[] = []
for (const filename of gallery) {
const url = await Drive.getUrl(`gallery/${filename}`)
images.push(url)
}
return view.render('gallery', { images })
}
public async upload({ request, response }: HttpContextContract) {
const imageSchema = schema.create({
fileImage: schema.file({
extnames: ['jpg', 'png', 'gif']
}),
})
const payload = await request.validate({ schema: imageSchema })
const filename = `${string.generateRandom(32)}.${payload.fileImage.extname}`
if (payload.fileImage) {
await payload.fileImage.moveToDisk(", {
name: `gallery/${filename}`
}, 's3')
const galleryString = await Redis.get('gallery')
let gallery:string[] = []
if (galleryString) {
gallery = JSON.parse(galleryString)
}
gallery.push(filename)
await Redis.set('gallery', JSON.stringify(gallery))
}
return response.redirect().toPath("https://www.vultr.com/")
}
}
Añadir rutas
Abre el start/routes.ts
expediente:
$ nano start/routes.ts
Agrega el siguiente código:
Route.get("https://www.vultr.com/", 'GalleryController.index')
Route.post("https://www.vultr.com/", 'GalleryController.upload')
Probar la aplicación
-
Para probar su aplicación, debe deshabilitar el firewall de Ubuntu .
$ sudo ufw disable
Puede volver a habilitarlo cuando cree su aplicación para producción.
-
Inicie un servidor de desarrollo:
$ node ace serve --encore-args="--host [VULTR_VPS_IP_ADDRESS]"
-
Abre el
https://[VULTR_VPS_IP_ADDRESS]:3333
en un navegador. -
Debería ver el formulario de carga.
-
Subir una imagen.
-
Compruebe si la imagen aparece en su almacenamiento de objetos Vultr y en la galería debajo del formulario de carga.
-
Presione CTRL+C para detener el servidor de desarrollo.
Utilice varias ubicaciones de almacenamiento de objetos
Vultr Object Storage está disponible en varias ubicaciones. Las siguientes son las ubicaciones que admite Vultr:
-
Ámsterdam:
ams1.vultrobjects.com
-
New Jersey:
ewr1.vultrobjects.com
-
Silicon Valley:
sjc1.vultrobjects.com
-
Singapur:
sgp1.vultrobjects.com
Puede usar varias ubicaciones de almacenamiento de objetos en la aplicación AdonisJS para agregar redundancia a sus archivos. Para hacer eso, agrega una configuración de disco para cada ubicación en el config/drive.ts
expediente. El disco en AdonisJS Drive representa una ubicación y un controlador de almacenamiento en particular.
Crear nuevo almacenamiento de objetos
-
Ir a Portal de clientes Vultr .
-
Navegar a Productos -> Objetos .
-
Agregar almacenamiento de objetos . Elija una región diferente, para exampleÁmsterdam.
-
Cree un depósito en el nuevo almacenamiento de objetos.
-
Toma nota de la
Hostname
laSecret Key
laAccess Key
y elBucket Name
.
Configurar nuevo disco
Abre el config/drive.ts
expediente:
$ nano config/drive.ts
Agregue una nueva configuración de disco en la sección S3. Puede establecer el nombre del disco en cualquier cosa, por example, s3ams
. Agregue un sufijo a los nombres de las variables de entorno para diferenciarlos del primer disco.
s3ams: {
driver: 's3',
visibility: 'public',
key: Env.get('S3_KEY_AMS'),
secret: Env.get('S3_SECRET_AMS'),
region: Env.get('S3_REGION_AMS'),
bucket: Env.get('S3_BUCKET_AMS'),
endpoint: Env.get('S3_ENDPOINT_AMS'),
},
Abre el .env
expediente:
$ nano .env
Agregue las credenciales de su almacenamiento de objetos:
S3_KEY_AMS=
S3_SECRET_AMS=
S3_BUCKET_AMS=adonis-drive
S3_REGION_AMS=ams1
S3_ENDPOINT_AMS=https://ams1.vultrobjects.com
-
S3_KEY_AMS
es su clave de acceso al almacenamiento de objetos Vultr. -
S3_SECRET_AMS
es su clave secreta de almacenamiento de objetos Vultr. -
S3_BUCKET_AMS
es su nombre de depósito de almacenamiento de objetos Vultr. -
S3_ENDPOINT_AMS
es su nombre de host de almacenamiento de objetos Vultr. -
S3_REGION_AMS
es su región de almacenamiento de objetos Vultr.
Abre el env.ts
expediente:
$ nano env.ts
Añade el s3ams
nombre del disco al DRIVE_DISK
valor de enumeración:
DRIVE_DISK: Env.schema.enum(['local','s3','s3ams'] as const),
Agregar reglas de validación para s3ams
variables de entorno del disco:
S3_KEY_AMS: Env.schema.string(),
S3_SECRET_AMS: Env.schema.string(),
S3_BUCKET_AMS: Env.schema.string(),
S3_REGION_AMS: Env.schema.string(),
S3_ENDPOINT_AMS: Env.schema.string.optional(),
Guarda el archivo y cierra.
Actualizar controlador
Abre el GalleryController.ts
expediente:
$ nano app/Controllers/Http/GalleryController.ts
En el upload
acción, busque el código responsable de cargar el archivo en el almacenamiento de objetos.
await payload.fileImage.moveToDisk(", {
name: `gallery/${filename}`
}, 's3')
Duplique el código y cambie el nombre del disco a s3ams
.
await payload.fileImage.moveToDisk(", {
name: `gallery/${filename}`
}, 's3')
await payload.fileImage.moveToDisk(", {
name: `gallery/${filename}`
}, 's3ams')
Carga el archivo en ambas ubicaciones de almacenamiento de objetos.
Establecer el disco predeterminado
El index
acción en el GalleryController.ts
utiliza el disco predeterminado para obtener la URL de la imagen. Para cambiar el disco predeterminado, abra el .env
expediente:
$ nano .env
Actualizar el DRIVE_DISK
valor al disco que desea:
DRIVE_DISK=s3ams
Guarda el archivo y cierra.
Prueba la aplicación
-
Inicie un servidor de desarrollo:
$ node ace serve --encore-args="--host [VULTR_VPS_IP_ADDRESS]"
-
Abre el
https://[VULTR_VPS_IP_ADDRESS]:3333
en un navegador. -
Subir una imagen.
-
Compruebe si la imagen aparece tanto en las ubicaciones de Vultr Object Storage como en la galería debajo del formulario de carga.
-
Presione CTRL+C para detener el servidor de desarrollo.
Construir para producción
La aplicación AdonisJS usa TypeScript. Debe compilarlo en JavaScript antes de ejecutarlo en producción.
Ve a la website
carpeta:
$ cd ~/app/website
Compílalo usando el build
dominio. El resultado está en el build
carpeta.
$ node ace build --production --ignore-ts-errors
Copia el .env
archivo a la build
carpeta y abrirlo:
$ cp .env build/.env
$ nano build/.env
Selecciona el NODE_ENV
variables en el .env
archivo a production
:
NODE_ENV=production
Instale dependencias solo de producción en el build
carpeta:
$ cd build
$ npm ci --production
Ejecute la aplicación en producción usando PM2
PM2 es un administrador de procesos demonio. Le ayuda a ejecutar y administrar su aplicación AdonisJS en producción.
Instale el paquete PM2 más reciente:
$ npm install [email protected] -g
Cree el archivo del ecosistema PM2 para administrar su aplicación:
$ cd ~/app
$ nano ecosystem.config.js
Agregue estas configuraciones a la ecosystem.config.js
expediente:
module.exports = {
apps : [
{
name : "website",
script : "./website/build/server.js"
}
]
}
-
Pon el nombre de tu aplicación en el
name
parámetro. -
Ponga la ruta de producción de
script.js
en elscript
parámetro.
Ejecute su aplicación:
$ pm2 start ecosystem.config.js
$ pm2 list
En este punto, su aplicación se está ejecutando. Pero, el proceso no es persistente todavía. Significa que debe ejecutar su aplicación manualmente nuevamente después de reiniciar su servidor.
Para ejecutar una aplicación persistente, debe generar un script de inicio para PM2.
$ pm2 startup
Copie y pegue el comando que se muestra en la terminal:
$ sudo env PATH=$PATH:/home/ubuntu/.nvm/versions/node/v19.3.0/bin /home/ubuntu/.nvm/versions/node/v19.3.0/lib/node_modules/pm2/bin/pm2 startup systemd -u ubuntu --hp /home/ubuntu
Guarde su lista de aplicaciones PM2 usando este comando:
$ pm2 save
Proxy de reserva de Nginx
Debe configurar un proxy de reserva de Nginx para conectar su dominio a su aplicación. Pones tus aplicaciones detrás del servidor web Nginx. Acepta todas las solicitudes entrantes y las reenvía a sus aplicaciones.
Agregue los repositorios ondrej para obtener la última versión de Nginx.
$ sudo add-apt-repository -y ppa:ondrej/nginx-mainline
$ sudo apt update
Instalar Nginx:
$ sudo apt install nginx
Deshabilite la configuración predeterminada de Nginx:
$ sudo unlink /etc/nginx/sites-enabled/default
Cree un nuevo archivo de configuración de Nginx:
$ sudo nano /etc/nginx/sites-available/website
Agregue las siguientes configuraciones. Asegúrate de cambiar el nombre de dominio googlesyndication.com
a tu dominio. Guarda el archivo y cierra.
server {
listen 80;
server_name googlesyndication.com;
location / {
proxy_pass https://localhost:3333;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_cache_bypass $http_upgrade;
}
}
Habilitar la configuración de Nginx:
$ sudo ln -s /etc/nginx/sites-available/website /etc/nginx/sites-enabled/
Pruebe sus configuraciones a partir de errores de sintaxis:
$ sudo nginx -t
Si no hay errores, puede volver a cargar el proceso Nginx:
$ sudo systemctl reload nginx
Apunte sus dominios a su dirección IP Vultr VPS.
Configurar cortafuegos
Configure el firewall para permitir el puerto ssh:
$ sudo ufw allow 'OpenSSH'
Permitir puertos HTTP y HTTPS:
$ sudo ufw allow 'Nginx Full'
Habilite el cortafuegos:
$ sudo ufw enable
Comprobar el estado del cortafuegos:
$ sudo ufw status
Aplicaciones seguras con el certificado SSL de Let’s Encrypt
Let’s Encrypt proporciona un certificado SSL gratuito para su sitio web. Para generar el certificado, debe utilizar la herramienta de software Certbot.
Instalar Certbot:
$ sudo snap install core; sudo snap refresh core
$ sudo snap install --classic certbot
$ sudo ln -s /snap/bin/certbot /usr/bin/certbot
Genere el certificado SSL:
$ sudo certbot --nginx
Visite su dominio en el navegador y confirme que tiene una conexión HTTPS.
El certificado de Let’s Encrypt caduca después de 90 días. Certbot agrega el comando de renovación al temporizador systemd o Cron Job para renovar el certificado automáticamente antes de que caduque. Puedes verificarlo con el siguiente comando:
$ systemctl list-timers | grep 'certbot|ACTIVATES'
Conclusión
Esta guía muestra ejemplos del uso de Vultr Object Storage en AdonisJS con una o varias ubicaciones de almacenamiento de objetos, incluidos los pasos para que la aplicación esté lista para la producción.
Otras lecturas
Almacenamiento de objetos Vultr.
Documentación de AdonisJS Drive.
Implemente múltiples aplicaciones de Adonis.js con PM2 y Nginx.
Título del artículo Nombre (opcional) Correo electrónico (opcional) Descripción
Enviar sugerencia