💾 Archived View for elmau.net › notes › mastodon.gmi captured on 2024-07-08 at 23:52:11. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-03-20)

-=-=-=-=-=-=-

Mastodon

Red social libre y descentralizada de microblogging.

Mastodon

Debes de tener ya apuntando un registro DNS tipo A (o AAAA) a tu dominio o subdominio que vayas a usar con Mastodon, para este ejemplo he usado: "social.elmau.net". Si no tienes dominio, puedo ayudarte con un subdominio.

Para este proceso he usado Ubuntu Server 22.04 LTS. También asumo que tienes conocimientos básicos de la terminal Linux con cualquier shell. Aquí uso el editor "vim" para editar los archivos, pero puedes usar cualquier editor de texto plano que te guste y este instalado en tu servidor.

Si activas el registro abierto en tu instancia y quieres recibir las notificaciones por correo, necesitas un servicio SMTP activo y funcionando.

El servidor es un VPS con 2 cores y 2 GB de RAM suficiente para varios usuarios.

[0] Antes de empezar

Asumo que es un servidor limpio recién instalado y actualizado. Como "root"."

apt update
apt upgrade
apt autoremove

Asegurate de tener correctamente configurado tu host.

hostnamectl set-hostname social.elmau.net

Tu zona horaria.

timedatectl set-timezone America/Mexico_City

Y tus locales

localectl set-locale LANG=en_US.UTF-8 LANGUAGE="en_US:en"

[1] Requerimiento previo

apt install apt-transport-https

[2] Agregar repositorio para "Node.js"

Version 16.x LTS

curl -sL https://deb.nodesource.com/setup_16.x | bash -

apt update

[3] Instalar requerimientos

apt install imagemagick ffmpeg libpq-dev libxml2-dev libxslt1-dev file git-core g++ libprotobuf-dev protobuf-compiler pkg-config nodejs gcc autoconf bison build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm-dev nginx redis-server redis-tools postgresql postgresql-contrib certbot libidn11-dev libicu-dev libjemalloc-dev

[4] Instalar "yarn"

corepack enable
yarn set version stable

[5] Agregar nuevo usuario

Agregamos al usuario "mastodon".

adduser --disabled-login mastodon

Y nos cambiamos a el.

su - mastodon

[6] Instalamos Ruby

Intalamos "rbenv"

git clone https://github.com/rbenv/rbenv.git ~/.rbenv
cd ~/.rbenv && src/configure && make -C src
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
exec bash

Intalamos "rbenv-build"

git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build

Instalamos y establecemos la versión global. Este paso, dependiedo de tu hardware puede ser el más tardado.

RUBY_CONFIGURE_OPTS=--with-jemalloc rbenv install 3.0.4
rbenv global 3.0.4

Intalamos

gem install bundler --no-document

Salimos del usuario "mastodon"

exit

[7] Configuramos la base de datos

Entramos al shell de "postgres"

sudo -u postgres psql

Creamos el usuarios "mastodon" con el permiso para crear la base de datos.

CREATE USER mastodon CREATEDB;

Salimos del shell.

\q

[8] Instalamos "Mastodon"

Nos cambiamos de usuario.

su - mastodon

Clonamos el repositorio.

git clone https://github.com/tootsuite/mastodon.git live

Nos movemos de directorio.

cd live

Nos cambiamos a la versión más reciente estable.

git checkout $(git tag -l | grep -v 'rc[0-9]*


 | sort -V | tail -n 1)

Configuramos.

bundle config deployment 'true'
bundle config without 'development test'

Instalamos más requerimientos.

bundle install -j$(getconf _NPROCESSORS_ONLN)
yarn install --pure-lockfile

Iniciamos el asistente de instalación:

RAILS_ENV=production bundle exec rake mastodon:setup

Es importante tener los siguientes datos, reemplaza por los tuyos y capturalos cuando los solicite el asistente.

Dominio o subdominio

Your instance is identified by its domain name. Changing it afterward will break things.
Domain name: social.elmau.net

Es posible usar Mastodon para un solo usuario, "N" para este caso.

Single user mode disables registrations and redirects the landing page to your public profile.
Do you want to enable single user mode? No

No, no estamos usando Docker

Are you using Docker to run Mastodon? no

La base de datos, en todo solo hay que dar "enter" para aceptar los valores predeterminados. Recuerda, NO se establecio contraseña al usuario de la base de datos.

PostgreSQL host: /var/run/postgresql
PostgreSQL port: 5432
Name of PostgreSQL database: mastodon_production
Name of PostgreSQL user: mastodon
Password of PostgreSQL user:
Database configuration works!

Redis, igualmente, todos los valores predeterminados.

Redis host: localhost
Redis port: 6379
Redis password:
Redis configuration works!

Si tu instancia tendrá muchos usuarios, es bueno guardar los archivos en un servicio compatible con S3, para este ejemplo es "N"

Do you want to store uploaded files on the cloud? No

Envío de notificaciones por correo, solo configura si tienes un servicio SMPT funcionando.

Do you want to send e-mails from localhost? No
SMTP server: mail.correolibre.net
SMTP port: 587
SMTP username: notificaciones@cuates.net
SMTP password:
SMTP authentication: plain
SMTP OpenSSL verify mode: none
Enable STARTTLS: always
E-mail address to send e-mails "from": (Mastodon <notifications@social.elmau.net>) notificacionesE-mail address to send e-mails "from": notificaciones@cuates.net
Send a test e-mail with this configuration right now? Yes
Send test e-mail to: test@pruebas.net

Guardamos la configuración

This configuration will be written to .env.production
Save configuration? Yes

Creación de la base de datos:

Now that configuration is saved, the database schema must be loaded.
If the database already exists, this will erase its contents.
Prepare the database now? Yes
Running `RAILS_ENV=production rails db:setup` ...

Created database 'mastodon_production'
Done!

Compilación de los assets CSS/JS

The final step is compiling CSS/JS assets.
This may take a while and consume a lot of RAM.
Compile the assets now? Yes

Compiling...
Compiled all packs in /home/mastodon/live/public/packs
Done!

All done! You can now power on the Mastodon server

Por último creamos el usuario administrador.

Do you want to create an admin user straight away? Yes
Username: admin
E-mail: admin@correo.net
You can login with the password: ba51b96a328807577793a3d7c5e716a6
You can change your password once you login.

"Importante", toma nota de la contraseña generada, cambiala por la de tu preferencia en el primer acceso a la instancia.

Salidos del usuario.

exit

[9] Solicitamos los certificados para el dominio con "Certbot"

Detenemos "nginx"

systemctl stop nginx

Registrar un correo. Utiliza un correo válido, recibirás las notificaciones para cuando estén por vencerse los certificados.

certbot register --agree-tos -m YOUR_EMAIL

(Y)es/(N)o: Y
Account registered.

Solicitamos los certificados para nuestro dominio. Reemplaza DOMAIN por el dominio o subdominio que estés usando.

certbot certonly --standalone --preferred-challenges http-01 -d DOMAIN

Si todo esta bien, debes de ver un mensaje similar a:

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/DOMAIN/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/DOMAIN/privkey.pem
This certificate expires on 2023-02-13.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.

Toma nota de las rutas completas de tus nuevos certificados.

/etc/letsencrypt/live/social.elmau.net/fullchain.pem
/etc/letsencrypt/live/social.elmau.net/privkey.pem

[10] Configuramos archivos para HTTPS.

Crear archivo "ssl-dhparams.pem"

openssl dhparam -dsaparam -out /etc/letsencrypt/ssl-dhparams.pem 4096

Crear el archivo "options-ssl-nginx.conf"

vim /etc/letsencrypt/options-ssl-nginx.conf

Con el siguiente contenido:

ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_timeout 1440m;

ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;

ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA38";

add_header Strict-Transport-Security "max-age=63072000; preload";
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Permissions-Policy interest-cohort=();

Crear el archivo "certbot.conf"

vim /etc/letsencrypt/certbot.conf

Con el siguiente contenido. Asegurate de reemplazar "social.elmau.net" por tu dominio.

ssl_certificate /etc/letsencrypt/live/social.elmau.net/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/social.elmau.net/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

[11] Configuramos "nginx"

Borramos el servidor predeterminado.

rm /etc/nginx/sites-enabled/default

Reemplazar el contenido del archivo "nginx.conf"

vim /etc/nginx/nginx.conf

Por:

user  www-data;
worker_processes  auto;
worker_rlimit_nofile 20480;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

error_log  /var/log/nginx/error.log warn;

events {
    worker_connections  5120;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    server_tokens off;
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile    on;
    tcp_nopush  on;
    types_hash_max_size 2048;
    keepalive_timeout   60;

    include /etc/nginx/sites-enabled/*.conf;

    disable_symlinks off;
}

Configurar el dominio en el archivo "social.elmau.conf", no olvides reemplazar por tu dominio o subdominio.

vim /etc/nginx/sites-available/social.elmau.conf

Con el siguiente contenido. Reemplazar "social.elmau.conf" donde corresponda:

map $http_upgrade $connection_upgrade {
  default upgrade;
  ''      close;
}

upstream backend {
    server 127.0.0.1:3000 fail_timeout=0;
}

upstream streaming {
    server 127.0.0.1:4000 fail_timeout=0;
}

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=1g;

server {
  listen 80;
  listen [::]:80;
  server_name social.elmau.net;
  root /home/mastodon/live/public;
  location /.well-known/acme-challenge/ { allow all; }
  location / { return 301 https://$host$request_uri; }
}

server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  server_name social.elmau.net;
  charset   utf-8;

  keepalive_timeout    70;
  sendfile             on;
  client_max_body_size 80m;

  include /etc/letsencrypt/certbot.conf;
  #proxy_set_header X-Forwarded-For $remote_addr;
  server_tokens off;

  access_log      /var/log/nginx/access.log;
  error_log       /var/log/nginx/error.log;

  root /home/mastodon/live/public;

  gzip on;
  gzip_disable "msie6";
  gzip_vary on;
  gzip_proxied any;
  gzip_comp_level 6;
  gzip_buffers 16 8k;
  gzip_http_version 1.1;
  gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml image/x-icon;

  location / {
    try_files $uri @proxy;
  }

  # If Docker is used for deployment and Rails serves static files,
  # then needed must replace line `try_files $uri =404;` with `try_files $uri @proxy;`.
  location = /sw.js {
    add_header Cache-Control "public, max-age=604800, must-revalidate";
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
    try_files $uri =404;
  }

  location ~ ^/assets/ {
    add_header Cache-Control "public, max-age=2419200, must-revalidate";
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
    try_files $uri =404;
  }

  location ~ ^/avatars/ {
    add_header Cache-Control "public, max-age=2419200, must-revalidate";
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
    try_files $uri =404;
  }

  location ~ ^/emoji/ {
    add_header Cache-Control "public, max-age=2419200, must-revalidate";
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
    try_files $uri =404;
  }

  location ~ ^/headers/ {
    add_header Cache-Control "public, max-age=2419200, must-revalidate";
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
    try_files $uri =404;
  }

  location ~ ^/packs/ {
    add_header Cache-Control "public, max-age=2419200, must-revalidate";
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
    try_files $uri =404;
  }

  location ~ ^/shortcuts/ {
    add_header Cache-Control "public, max-age=2419200, must-revalidate";
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
    try_files $uri =404;
  }

  location ~ ^/sounds/ {
    add_header Cache-Control "public, max-age=2419200, must-revalidate";
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
    try_files $uri =404;
  }

  location ~ ^/system/ {
    add_header Cache-Control "public, max-age=2419200, immutable";
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
    try_files $uri =404;
  }

  location ^~ /api/v1/streaming {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Proxy "";

    proxy_pass http://streaming;
    proxy_buffering off;
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    tcp_nodelay on;
  }

  location @proxy {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Proxy "";
    proxy_pass_header Server;

    proxy_pass http://backend;
    proxy_buffering on;
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    proxy_cache CACHE;
    proxy_cache_valid 200 7d;
    proxy_cache_valid 410 24h;
    proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
    add_header X-Cached $upstream_cache_status;

    tcp_nodelay on;
  }

  error_page 404 500 501 502 503 504 /500.html;
}

Creamos el vínculo simbólico.

ln -s /etc/nginx/sites-available/social.elmau.conf /etc/nginx/sites-enabled/

Probamos la configuración.

nginx -t

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Solo, si no obtienes un error, inicia el servicio.

systemctl start nginx

[12] Configuramos los servicios para Mastodon

Editamos el archivo "mastodon-web.service"

vim /etc/systemd/system/mastodon-web.service

Con el siguiente contenido.

[Unit]
Description=mastodon-web
After=network.target

[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="RAILS_ENV=production"
Environment="PORT=3000"
ExecStart=/home/mastodon/.rbenv/shims/bundle exec puma -C config/puma.rb
ExecReload=/bin/kill -SIGUSR1 $MAINPID
TimeoutSec=15
Restart=always

[Install]
WantedBy=multi-user.target

Editamos el archivo "mastodon-sidekiq.service"

vim /etc/systemd/system/mastodon-sidekiq.service

Con el siguiente contenido.

[Unit]
Description=mastodon-sidekiq
After=network.target

[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="RAILS_ENV=production"
Environment="DB_POOL=25"
Environment="MALLOC_ARENA_MAX=2"
ExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -c 25
TimeoutSec=15
Restart=always

[Install]
WantedBy=multi-user.target

Editamos el archivo "mastodon-streaming.service"

vim /etc/systemd/system/mastodon-streaming.service

Con el siguiente contenido.

[Unit]
Description=mastodon-streaming
After=network.target

[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="NODE_ENV=production"
Environment="PORT=4000"
Environment="STREAMING_CLUSTER_NUM=1"
ExecStart=/usr/bin/node ./streaming
TimeoutSec=15
Restart=always

[Install]
WantedBy=multi-user.target

Recargamos

systemctl daemon-reload

Activamos e iniciamos los servicio.

systemctl enable --now mastodon-web mastodon-sidekiq mastodon-streaming

Asegurate que cada servicio este activo sin errores.

systemctl status mastodon-web
systemctl status mastodon-sidekiq
systemctl status mastodon-streaming

[13] Permisos

Agregamos estos usuarios a estos grupos.

usermod -a -G mastodon www-data
usermod -a -G www-data mastodon

[14] Reniciamos

La mejor forma de verificar que todos los servicios arrancan bien, es reinciando el servidor.

reboot

[15] Recomendaciones finales.

Activa el firewall.

ufw allow http
ufw allow https
ufw allow ssh

ufw enable

Configura el servidor SSH para desactivar el acceso "root" y la identificación por contraseña, solo acceder con certificados que tu hayas generado.

Instala "file2ban"

Si este tutorial te ha sido útil considera hacer un aprecio al mismo:

En Junas (G1)

A5DdXxCKPw3QKWVdDVs7CzkNugNUW1sHu5zDJFWxCU2h

En Euros:

IBAN: BE60 9671 0556 5870
SWIFT / BIC: TRWIBEB1XXX

Gracias