A continuación os vamos a explicar como configurar Object Storage con soporte en S3 en tu instancia de Mastodon que ya está desplegada para meter todo el contenido multimedia y cache en un agujero sin fondo (bueno, en realidad tiene fondo y es el fondo de tu bolsillo xD).

¿Qué es Object Storage?

En resumidas cuentas, el almacenamiento de objeto es una arquitectura de almacenamiento de datos que maneja los datos como objectos. Si esta característica no la tenemos activada en Mastodon, significa que estamos usando una arquitectura de almacenamiento de tipo sistema de archivos, que en este caso se manejan los datos con una jerarquía de archivos.

En el caso del almacenamiento de objeto, cada objecto incluye el propio dato, una cantidad variable de metadatos y un identificador global único.

En un lenguaje coloquial, se podría decir que el almacenamiento de objectos es como si tuvieras un cubo donde ir metiendo cosas sin fondo.

En este caso, utilizaremos un Object Storage basado en S3, que es una tecnología que en su día inventó AWS para gestionar este tipo de servicios.

¿Porqué activar Object Storage / S3?

En mi caso, básicamente porque tenía 90GB de espacio de caché en el servidor y en las últimas semanas estaba recibiendo muchos avisos de Zabbix indicando que estaba ocupando más del 80% del disco del servidor. Y era algo constante.

En la versión de Mastodon que tenía, aún no habían aplicado los comandos para eliminar de forma segura los ficheros de cache por lo tanto una opción fue meterlo todo en un cubo y resolver el problema de espacio.

Además, tengo pendiente migrar el servidor, y esto resultará bastante más sencillo ya que los datos se encontrarán separado de toda migración.

Que Object Storage usar

Existen muchos servicios interesantes para el Object Storage. Durante un tiempo estuve utilizando el servicio de Linode para mis backups. También utilicé Vultr para unas pruebas que estuve haciendo. Actualmente estoy utilizando Wasabi para guardar todos mis backups.

Pero finalmente he escogido Storj.io para montar el Object Storage con mi nodo de Mastodon.

He escogido este servicio básicamente porque ofrece un plan gratuito que puede ser interesante. Son 150GB mensuales gratuitos. Pero hay "trampa", ya que únicamente puedes importar 10K segmentos mensuales. Por lo que si tienes que subir 90GB no te va a valer. Pero si que te puede ser útil si justo acabas de desplegar Mastodon.

En mi caso estoy usando el plan PRO con un límite de 25TB de espacio -que no voy ha usar en la vida-. Pero también los 150GB iniciales no se facturan.

Apartado de facturación de Storj

Chismes varios

[OFFTOPIC] Como curiosidad hace cosa de un mes, por allá finales de enero... Muchos administradores de Mastodon recibimos un e-mail de Storj indicando que podíamos utilizar su servicio para nuestros nodos. SPAM del bueno.

Básicamente utilizaron los e-mails de los administradores, que son públicos, y nos enviaron este e-mail de arriba. Con documentación oficial de Storj sobre como montarlo en Mastodon desde cero.

Bueno, vamos al lío.

Crear bucket en Storj.io

Una de las primeras cosas que tenemos que hacer, es crear un Bucket. Para ello en el panel de Storj iremos a Buckets > New Bucket y configuraremos un nombre para nuestro bucket.

Una vez tengamos el bucket creado, tenemos que crear unas credenciales para S3. Para eso vamos a Access > Create S3 credencials.

Configuramos una contraseña y nos descargamos el fichero con las credenciales.

🚨
Guardad este fichero en un sitio seguro, es muy importante no perderlo.

Copiar los ficheros del servidor al bucket

Para poder copiar los ficheros, usaremos una herramienta llamada aws-cli, que permite sincronizar un directorio con el bucket entre muchas otras cosas.

apt install awscli

Y lo configuramos de la siguiente forma:

$ aws configure 

AWS Access Key ID [****************e53q]: [ACCESS_KEY_ID]
AWS Secret Access Key [****************bbxq]: [SECRET_KEY]
Default region name [us-east-1]: 
Default output format [None]: 
📢
Aquí tendremos que añadir el Access Key ID y el Secret Key que hemos generado anteriormente.

Tras configurar la herramienta, iremos a nuestro directorio donde tenemos instalado Mastodon y empezaremos a copiar los ficheros a nuestro bucket.

cd /home/mastodon/live
aws s3 sync --acl public-read public/system/ s3://[BUCKET] --endpoint-url=https://gateway.storjshare.io

Esto dependiendo lo que tengamos en el servidor, tardará más o menos. Así que paciencia en este punto.

Por ejemplo, en mi caso tenía 90GB de ficheros dentro de public/system/, por lo que recomiendo antes ejecutar estos dos comandos para liberar espacio:

RAILS_ENV=production ./bin/tootctl media remove --remove-headers
RAILS_ENV=production ./bin/tootctl media remove --prune-profiles

Estos dos comandos liberaron muuuuuucho espacio. Al final solo tuve que sincronizar 10Gb y fue mucho más liviano.

Generar las credenciales Linksharing

Storj funciona un poco diferente a otros servicios de S3 que he utilizado. Además del bucket y de las credenciales de acceso, necesitamos otras credenciales llamadas linksharing.

Para esto necesitamos descargarnos un programa llamado UpLink CLI para instalarlo:

curl -L https://github.com/storj/storj/releases/latest/download/uplink_linux_amd64.zip -o uplink_linux_amd64.zip
unzip -o uplink_linux_amd64.zip
sudo install uplink /usr/local/bin/uplink

Y luego ejecutamos el siguiente comando para generar las credenciales linksharing:

uplink share --readonly=false --register sj://[NombreDelBucket]
📢
Recuerda de cambiar el nombre del bucket por el que hayas creado tu.

Este comando nos dará una salida parecida a esta:

Sharing access to satellite [CENSURADO]@eu1.storj.io:7777
== ACCESS RESTRICTIONS ==
Download  : Allowed
Upload    : Allowed
Lists     : Allowed
Deletes   : Allowed
NotBefore : No restriction
NotAfter  : No restriction
Paths     : sj://[NombreDelBucket]/ (entire bucket)
== SERIALIZED ACCESS WITH THE ABOVE RESTRICTIONS TO SHARE WITH OTHERS ==
Access    : [ACCESS_KEY]
== GATEWAY CREDENTIALS ==
Access Key ID: [ACCESS_KEY_ID]
Secret Key   : [SECRET_KEY]
Endpoint     : https://gateway.storjshare.io
Public Access: false

Guardaremos estos datos en un sitio seguro. Principalmente Acces Key ID y Secret Key. Luego ejecutaremos este otro comando:

uplink share --url --readonly --disallow-lists --not-after=none sj://[NombreDelBucket]

Este otro comando nos dará una salida parecida a esta:

Sharing access to satellite [CENSURADO]@eu1.storj.io:7777
== ACCESS RESTRICTIONS ==
Download  : Allowed
Upload    : Disallowed
Lists     : Disallowed
Deletes   : Disallowed
NotBefore : No restriction
NotAfter  : No restriction
Paths     : sj://[NombreDelBucket]/ (entire bucket)
== SERIALIZED ACCESS WITH THE ABOVE RESTRICTIONS TO SHARE WITH OTHERS ==
Access    : [ACCESS]
== GATEWAY CREDENTIALS ==
Access Key ID: [ACCESS_KEY_ID]
Secret Key   : [SECRET_KEY]
Endpoint     : https://gateway.storjshare.io
Public Access: true
== BROWSER URL ==
URL       : https://link.storjshare.io/s/[LINKSHARING]/[NombreDelBucket]

De este comando, guardaremos el último parámetro URL.

Crear Nginx Proxy para el bucket

Este paso realmente no sería necesario, pero queda mucho más profesional utilizar una URL propia para todos los medios del nodo.

Vamos a crear un subdominio para que carguen los ficheros, así los tenemos en media.nodo.com o data.nodo.com o s3.nodo.com.

En este tutorial, vamos a utilizar el subdominio media, pero podéis poner lo que queráis.

Esta es la configuración de Nginx que debéis de crear:

proxy_cache_path /cache levels=1:2 keys_zone=MEDIA_CACHE:10m max_size=10g inactive=36h use_temp_path=off;

server {
    listen 443 ssl;
    server_name media.[DOMINIO];
    root /home/mastodont/live/public/system;

    access_log /var/log/nginx/mstdn-media-access.log;
    error_log /var/log/nginx/mstdn-media-error.log;

    # Add your certificate and HTTPS stuff here
    ssl_certificate /etc/letsencrypt/live/media.[DOMINIO]/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/media.[DOMINIO]/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    
    keepalive_timeout 30;

    location = / {
        index index.html;
    }

    location ~ /.well-known {
        allow all;
    }

    location / {
        try_files $uri @s3;
    }

    set $s3_hostname "link.storjshare.io/raw/[LINKSHARING]";
    set $s3_backend 'https://$s3_hostname';
    set $s3_bucket "[NOMBRE_BUCKET]";
  
    location @s3 {
        limit_except GET {
           deny all;
        }

        resolver 8.8.8.8 ipv6=off;
    
        proxy_set_header Connection '';
        proxy_set_header Authorization '';

        proxy_hide_header Set-Cookie;
        proxy_hide_header 'Access-Control-Allow-Origin';
        proxy_hide_header 'Access-Control-Allow-Methods';
        proxy_hide_header 'Access-Control-Allow-Headers';
        proxy_hide_header x-amz-id-2;
        proxy_hide_header x-amz-request-id;
        proxy_hide_header x-amz-meta-server-side-encryption;
        proxy_hide_header x-amz-server-side-encryption;
        proxy_hide_header x-amz-bucket-region;
        proxy_hide_header x-amzn-requestid;
        proxy_ignore_headers Set-Cookie;
        proxy_ssl_server_name on;
        proxy_pass $s3_backend/$s3_bucket$uri;
        proxy_intercept_errors off;

        proxy_cache MEDIA_CACHE;
        proxy_cache_valid 200 5d;
        proxy_cache_valid 403 15m;
        proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
        proxy_cache_lock on;

        expires 1y;
        add_header Cache-Control public;
        add_header 'Access-Control-Allow-Origin'  '*';
        add_header 'Access-Control-Allow-Methods' 'GET';
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
        add_header X-Cache-Status $upstream_cache_status;
    }
}


server {
    if ($host = media.[DOMINIO]) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    listen 80;
    server_name media.[DOMINIO];
    return 404; # managed by Certbot
}

Debéis de tener en cuenta de cambiar [DOMINIO] por vuestro dominio y modificar estos valores:

set $s3_hostname "link.storjshare.io/raw/[LINKSHARING]";
set $s3_backend 'https://$s3_hostname';
set $s3_bucket "[NOMBRE_BUCKET]";

Con el nombre del bucket y nuestro linksharing (que lo encontrarás en el parámetro URL de antes).

También tenemos que tener un certificado creado, para ello os dejo este tutorial:

Cómo utilizar Certbot para configurar un SSL de Let’s Encrypt en GNU/Linux
Certbot es una maravillosa herramienta que puedes utilizar para generar un certificado SSL con Let’s Encrypt e instalarlo y configurar automáticamente en tu servidor web.

Configurar Mastodon con S3

Por último tendremos que configurar el fichero .env.production de nuestro Mastodon. Tenemos que añadir lo siguiente:

S3_ENABLED=true
S3_PROTOCOL=https
S3_REGION=global
S3_ENDPOINT=https://gateway.storjshare.io
S3_HOSTNAME=gateway.storjshare.io
S3_ALIAS_HOST=media.[DOMINIO]
S3_BUCKET=[BUCKET]
AWS_ACCESS_KEY_ID=[ACCESS_KEY_ID]
AWS_SECRET_ACCESS_KEY=[SECRET_KEY]

Guardamos y reiniciamos los servicios de Mastodon:

systemctl restart mastodon-web.service
systemctl restart mastodon-sidekiq.service
systemctl restart mastodon-streaming.service

Y si todo ha funcionando, deberían de cargar las imágenes desde nuestro dominio. Cualquier problema, revisar el log de Nginx que se ha configurado porque allí veremos todos los errores.

Notas revisadas para este artículo:

Haz que cada palabra cuente: tu donación nos inspira a seguir creando contenido. Accede al apartado de Donación para hacer tu aportación