Cómo instalar la red social Mastodon en Debian 12
Mastodon es una red social libre, descentralizada y de código abierto. Se creó como alternativa a Twitter. Al igual que en Twitter, la gente puede seguirse entre sí y publicar mensajes, imágenes y vídeos. Pero a diferencia de Twitter, no existe un almacén central ni una autoridad para el contenido.
En su lugar, Mastodon opera a través de miles de servidores diferentes, cada uno gestionado por varios miembros de la comunidad. Los usuarios registrados en un servidor pueden conectarse fácilmente con los usuarios de la otra red y seguirse entre instancias.
Cualquiera puede instalar su instancia de un servidor Mastodon. Este tutorial te enseñará a configurar tu instancia de Mastodon en un servidor con Debian 12 utilizando Docker. Docker facilita la instalación de Mastodon al contener todos los paquetes y servicios necesarios en contenedores.
Requisitos previos
- Un servidor con Debian 12 con un mínimo de 2 núcleos de CPU y 2 GB de memoria. Tendrás que actualizar el servidor según los requisitos.
- Un usuario no root con privilegios sudo.
- Un nombre de dominio completo (FQDN) que apunte a tu servidor. Para nuestros propósitos, utilizaremos
mastodon.example.com
como nombre de dominio. - Mastodon envía notificaciones por correo electrónico a los usuarios. Te recomendamos que utilices un servicio de correo transaccional de terceros como Mailgun, SendGrid, Amazon SES o Sparkpost. Las instrucciones de la guía utilizarán Amazon SES.
- Asegúrate de que todo está actualizado.
$ sudo apt update
- Instala los paquetes de utilidades básicas. Puede que algunos ya estén instalados.
$ sudo apt install curl wget nano software-properties-common dirmngr apt-transport-https ca-certificates lsb-release debian-archive-keyring gnupg2 ufw unzip -y
Paso 1 – Configurar el cortafuegos
El primer paso es configurar el cortafuegos. Debian viene con ufw (Uncomplicated Firewall) por defecto.
Comprueba si el cortafuegos está funcionando.
$ sudo ufw status
Deberías obtener la siguiente salida.
Status: inactive
Permite el puerto SSH para que el cortafuegos no rompa la conexión actual al activarlo.
$ sudo ufw allow OpenSSH
Permite también los puertos HTTP y HTTPS.
$ sudo ufw allow http $ sudo ufw allow https
Habilita el cortafuegos
$ sudo ufw enable Command may disrupt existing ssh connections. Proceed with operation (y|n)? y Firewall is active and enabled on system startup
Comprueba de nuevo el estado del cortafuegos.
$ sudo ufw status
Deberías ver un resultado similar.
Status: active To Action From -- ------ ---- OpenSSH ALLOW Anywhere 80/tcp ALLOW Anywhere 443 ALLOW Anywhere OpenSSH (v6) ALLOW Anywhere (v6) 80/tcp (v6) ALLOW Anywhere (v6) 443 (v6) ALLOW Anywhere (v6)
Paso 2 – Instala Docker y Docker Compose
Debian 12 incluye una versión antigua de Docker. Para instalar la última versión, importa primero la clave GPG de Docker.
$ sudo install -m 0755 -d /etc/apt/keyrings $ curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg $ sudo chmod a+r /etc/apt/keyrings/docker.gpg
Crea el archivo del repositorio de Docker.
$ echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Actualiza la lista de repositorios del sistema.
$ sudo apt update
Instala la última versión de Docker.
$ sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Comprueba que se está ejecutando.
$ sudo systemctl status docker ? docker.service - Docker Application Container Engine Loaded: loaded (/lib/systemd/system/docker.service; enabled; preset: enabled) Active: active (running) since Mon 2024-01-01 09:00:14 UTC; 17s ago TriggeredBy: ? docker.socket Docs: https://docs.docker.com Main PID: 1839 (dockerd) Tasks: 9 Memory: 27.6M CPU: 598ms CGroup: /system.slice/docker.service ??1839 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
Por defecto, Docker requiere privilegios de root. Si quieres evitar utilizar sudo
cada vez que ejecutes el comando docker
, añade tu nombre de usuario al grupo docker
.
$ sudo usermod -aG docker $(whoami)
Tienes que salir del servidor y volver a entrar como el mismo usuario para activar este cambio o utilizar el siguiente comando.
$ su - ${USER}
Confirma que tu usuario se ha añadido al grupo Docker.
$ groups navjot sudo users docker
Paso 3 – Preparación para la instalación
El límite por defecto de los recuentos mmap es muy bajo para Elasticsearch. Ejecuta el siguiente comando para comprobar el valor por defecto.
$ sudo sysctl vm.max_map_count
Obtendrás la siguiente salida.
vm.max_map_count = 65530
Aumenta el valor utilizando los siguientes comandos.
$ echo "vm.max_map_count=262144" | sudo tee /etc/sysctl.d/90-max_map_count.conf vm.max_map_count=262144 $ sudo sysctl --load /etc/sysctl.d/90-max_map_count.conf vm.max_map_count=262144
Paso 4 – Instalar Mastodon
Crea directorios y establece la propiedad
Crea directorios para Mastodon y los servicios relacionados.
$ sudo mkdir -p /opt/mastodon/database/{postgresql,pgbackups,redis,elasticsearch} $ sudo mkdir -p /opt/mastodon/web/{public,system} $ sudo mkdir -p /opt/mastodon/branding
Establece las propiedades adecuadas para los directorios Elasticsearch, web y de copia de seguridad.
$ sudo chown 991:991 /opt/mastodon/web/{public,system} $ sudo chown 1000 /opt/mastodon/database/elasticsearch $ sudo chown 70:70 /opt/mastodon/database/pgbackups
Cambia al directorio Mastodon.
$ cd /opt/mastodon
Crea archivos de entorno y docker compose
Crea archivos de entorno para la aplicación y la base de datos.
$ sudo touch application.env database.env
Crea y abre el archivo Docker compose para editarlo.
$ sudo nano docker-compose.yml
Pega en él el siguiente código.
services: postgresql: image: postgres:16-alpine env_file: database.env restart: always shm_size: 512mb healthcheck: test: ['CMD', 'pg_isready', '-U', 'postgres'] volumes: - postgresql:/var/lib/postgresql/data - pgbackups:/backups networks: - internal_network redis: image: redis:7-alpine restart: always healthcheck: test: ['CMD', 'redis-cli', 'ping'] volumes: - redis:/data networks: - internal_network redis-volatile: image: redis:7-alpine restart: always healthcheck: test: ['CMD', 'redis-cli', 'ping'] networks: - internal_network elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:7.17.16 restart: always env_file: database.env environment: - cluster.name=elasticsearch-mastodon - discovery.type=single-node - bootstrap.memory_lock=true - xpack.security.enabled=true - ingest.geoip.downloader.enabled=false - "ES_JAVA_OPTS=-Xms512m -Xmx512m -Des.enforce.bootstrap.checks=true" - xpack.license.self_generated.type=basic - xpack.watcher.enabled=false - xpack.graph.enabled=false - xpack.ml.enabled=false - thread_pool.write.queue_size=1000 ulimits: memlock: soft: -1 hard: -1 nofile: soft: 65536 hard: 65536 healthcheck: test: ["CMD-SHELL", "nc -z elasticsearch 9200"] volumes: - elasticsearch:/usr/share/elasticsearch/data networks: - internal_network ports: - '127.0.0.1:9200:9200' website: image: tootsuite/mastodon:v4.2.3 env_file: - application.env - database.env command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000" restart: always depends_on: - postgresql - redis - redis-volatile - elasticsearch ports: - '127.0.0.1:3000:3000' networks: - internal_network - external_network healthcheck: test: ['CMD-SHELL', 'wget -q --spider --proxy=off localhost:3000/health || exit 1'] volumes: - uploads:/mastodon/public/system shell: image: tootsuite/mastodon:v4.2.3 env_file: - application.env - database.env command: /bin/bash restart: "no" networks: - internal_network - external_network volumes: - uploads:/mastodon/public/system - static:/static streaming: image: tootsuite/mastodon:v4.2.3 env_file: - application.env - database.env command: node ./streaming restart: always depends_on: - postgresql - redis - redis-volatile - elasticsearch ports: - '127.0.0.1:4000:4000' networks: - internal_network - external_network healthcheck: test: ['CMD-SHELL', 'wget -q --spider --proxy=off localhost:4000/api/v1/streaming/health || exit 1'] sidekiq: image: tootsuite/mastodon:v4.2.3 env_file: - application.env - database.env command: bundle exec sidekiq restart: always depends_on: - postgresql - redis - redis-volatile - website networks: - internal_network - external_network healthcheck: test: ['CMD-SHELL', "ps aux | grep '[s]idekiq\ 6' || false"] volumes: - uploads:/mastodon/public/system networks: external_network: internal_network: internal: true volumes: postgresql: driver_opts: type: none device: /opt/mastodon/database/postgresql o: bind pgbackups: driver_opts: type: none device: /opt/mastodon/database/pgbackups o: bind redis: driver_opts: type: none device: /opt/mastodon/database/redis o: bind elasticsearch: driver_opts: type: none device: /opt/mastodon/database/elasticsearch o: bind uploads: driver_opts: type: none device: /opt/mastodon/web/system o: bind static: driver_opts: type: none device: /opt/mastodon/web/public o: bind
Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te pida.
En el momento de escribir el tutorial, la última versión disponible de Mastodon es la v4.2.3. Consulta la página de versiones de Mastodon en GitHub y ajusta la versión en el archivo de composición de Docker según corresponda. También estamos utilizando las últimas versiones de PostgreSQL y Redis. Puedes ajustarlas según tus necesidades. En este momento estamos utilizando Elasticsearch 7.17.16.
Crear Secretos de Aplicación
El siguiente paso es crear los valores secretos de la aplicación.
Genera los valores SECRET_KEY_BASE
y OTP_SECRET
ejecutando el siguiente comando dos veces. La primera vez tardará un poco, ya que extraerá las imágenes.
$ docker compose run --rm shell bundle exec rake secret 349623c049e3b856f6848638146e459857862b908ed387bbef372a30d9bd7c604fc4de5338addc86bd369a99d38ef59bacfa28e02a1750f7094ea6ede05457b8
También puedes utilizar la utilidad openssl
para lo mismo.
$ openssl rand -hex 64 ae01cf7d4dfae0182461a1345f1f2bf159658a27339ffafe7d356bef9ee8d4fa015ab2e72a608f236bd8e3f9b2af2dcb1d55ee5c8e43646959112c7da5582f4b
Genera los valores VAPID_PRIVATE_KEY
y VAPID_PUBLIC_KEY
utilizando el siguiente comando.
$ docker compose run --rm shell bundle exec rake mastodon:webpush:generate_vapid_key
Obtendrás un resultado similar.
VAPID_PRIVATE_KEY=u2qsCs5JdmdmMLnUuU0sgmFGvZedteJz-lFB_xF4_ac= VAPID_PUBLIC_KEY=BJXjE2hIXvFpo6dnHqyf1i-2PcP-cBoL95UCmhhxwlAgtFw_vnrYp4GBneR7_cmI9LZUYjHFh-TBAPSb9WTqH9A=
Utiliza la utilidad openssl
para generar las contraseñas de PostgreSQL y Elasticsearch.
$ openssl rand -hex 15 dd0bd7a95960623ed8e084a1fb7d5c $ openssl rand -hex 15 0fb52834c991b5e296c647166185bc
Archivos de entorno Mastodon
Abre el archivo application.env
para editarlo.
$ sudo nano application.env
Pega en él las siguientes líneas.
# environment RAILS_ENV=production NODE_ENV=production # domain LOCAL_DOMAIN=mastodon.example.com # redirect to the first profile SINGLE_USER_MODE=false # do not serve static files RAILS_SERVE_STATIC_FILES=false # concurrency WEB_CONCURRENCY=2 MAX_THREADS=5 # pgbouncer #PREPARED_STATEMENTS=false # locale DEFAULT_LOCALE=en # email, not used SMTP_SERVER=email-smtp.us-west-2.amazonaws.com SMTP_PORT=587 SMTP_LOGIN=AKIA3FIG4NVFB343PZEI SMTP_PASSWORD=AZX01WiA6JGbeZ2pwVXnyC9DhEa2nKcmXSu/zbLp [email protected] # secrets SECRET_KEY_BASE=349623c049e3b856f6848638146e459857862b908ed387bbef372a30d9bd7c604fc4de5338addc86bd369a99d38ef59bacfa28e02a1750f7094ea6ede05457b8 OTP_SECRET=ae01cf7d4dfae0182461a1345f1f2bf159658a27339ffafe7d356bef9ee8d4fa015ab2e72a608f236bd8e3f9b2af2dcb1d55ee5c8e43646959112c7da5582f4b # Changing VAPID keys will break push notifications VAPID_PRIVATE_KEY=oNe_4BEL7Tpc3iV8eMtLegfLwrzA7ifitGJ2YOg3dUM= VAPID_PUBLIC_KEY=BKBgmB90vIrJg6Ifq3cCHixalyPghJDkui9vm1wscxvAfNNoAQL0KinoxRTLDp0UFlGK_ahUG2n4W2n4x9AUAWM= # IP and session retention # ----------------------- # Make sure to modify the scheduling of ip_cleanup_scheduler in config/sidekiq.yml # to be less than daily if you lower IP_RETENTION_PERIOD below two days (172800). # ----------------------- IP_RETENTION_PERIOD=2592000 SESSION_RETENTION_PERIOD=2592000
Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te solicite.
Hemos habilitado el servicio de correo de Amazon SES. Si no lo necesitas, puedes eliminar la sección. Por defecto, Mastodon retiene una dirección IP durante 1 año, pero lo hemos cambiado a 30 días (2592000 segundos). Puedes cambiarlo según tus necesidades. Asegúrate de mantenerla durante más de 2 días, de lo contrario, tendrás que hacer algunos ajustes más que quedan fuera del alcance de nuestro tutorial.
Abre el archivo database.env
para editarlo.
$ sudo nano database.env
Pega en él las siguientes líneas.
# postgresql configuration POSTGRES_USER=mastodon POSTGRES_DB=mastodon POSTGRES_PASSWORD=0fb52834c991b5e296c647166185bc PGPASSWORD=0fb52834c991b5e296c647166185bc PGPORT=5432 PGHOST=postgresql PGUSER=mastodon # pgbouncer configuration #POOL_MODE=transaction #ADMIN_USERS=postgres,mastodon #DATABASE_URL="postgres://mastodon:0fb52834c991b5e296c647166185bc@postgresql:5432/mastodon" # elasticsearch ELASTIC_PASSWORD=dd0bd7a95960623ed8e084a1fb7d5c # mastodon database configuration #DB_HOST=pgbouncer DB_HOST=postgresql DB_USER=mastodon DB_NAME=mastodon DB_PASS=0fb52834c991b5e296c647166185bc DB_PORT=5432 REDIS_HOST=redis REDIS_PORT=6379 CACHE_REDIS_HOST=redis-volatile CACHE_REDIS_PORT=6379 ES_ENABLED=true ES_HOST=elasticsearch ES_PORT=9200 ES_USER=elastic ES_PASS=dd0bd7a95960623ed8e084a1fb7d5c
Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando te lo pida.
Prepara Mastodon
Prepara los archivos estáticos para que los sirva Nginx. Este paso va a llevar algo de tiempo porque Docker sacará todas las imágenes por primera vez.
$ docker compose run --rm shell bash -c "cp -r /opt/mastodon/public/* /static/"
Activa la capa de datos.
$ docker compose up -d postgresql redis redis-volatile
Comprueba el estado de los contenedores.
$ watch docker compose ps
Espera a running (healthy)
, luego pulsa Ctrl + C
e inicializa la base de datos utilizando el siguiente comando.
$ docker compose run --rm shell bundle exec rake db:setup
Si aparece el error de que la base de datos mastodon
ya existe, ejecuta el siguiente comando.
$ docker compose run --rm shell bundle exec rake db:migrate
Paso 5 – Instalar Nginx
Debian 12 incluye una versión antigua de Nginx. Para instalar la última versión, necesitas descargar el repositorio oficial de Nginx.
Importa la clave de firma de Nginx.
$ curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \ | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
Añade el repositorio de la versión principal de Nginx.
$ echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ http://nginx.org/packages/mainline/debian `lsb_release -cs` nginx" \ | sudo tee /etc/apt/sources.list.d/nginx.list
Actualiza los repositorios del sistema.
$ sudo apt update
Instala Nginx.
$ sudo apt install nginx
Verifica la instalación. En los sistemas Debian, necesitas sudo
para ejecutar el siguiente comando.
$ sudo nginx -v nginx version: nginx/1.25.3
Inicia el servidor Nginx.
$ sudo systemctl start nginx
Comprueba el estado del servidor.
$ sudo systemctl status nginx ? nginx.service - nginx - high performance web server Loaded: loaded (/lib/systemd/system/nginx.service; enabled; preset: enabled) Active: active (running) since Mon 2024-01-01 10:17:38 UTC; 4s ago Docs: https://nginx.org/en/docs/ Process: 8972 ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf (code=exited, status=0/SUCCESS) Main PID: 8973 (nginx) Tasks: 3 (limit: 4637) Memory: 2.9M CPU: 17ms CGroup: /system.slice/nginx.service ??8973 "nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf" ??8974 "nginx: worker process" ??8975 "nginx: worker process" Jan 01 10:17:38 mastodon systemd[1]: Starting nginx.service - nginx - high performance web server... Jan 01 10:17:38 mastodon systemd[1]: Started nginx.service - nginx - high performance web server.
Paso 6 – Instalar SSL
Necesitamos instalar Certbot para generar el certificado SSL. Puedes instalar Certbot utilizando el repositorio de Debian u obtener la última versión utilizando la herramienta Snapd. Nosotros utilizaremos la versión Snapd.
Debian 12 no viene con Snapd instalado. Instala el paquete Snapd.
$ sudo apt install snapd
Ejecuta los siguientes comandos para asegurarte de que tu versión de Snapd está actualizada. Asegúrate de que tu versión de Snapd está actualizada.
$ sudo snap install core $ sudo snap refresh core
Instala Certbot.
$ sudo snap install --classic certbot
Utiliza el siguiente comando para asegurarte de que se ejecuta el comando Certbot creando un enlace simbólico al directorio /usr/bin
.
$ sudo ln -s /snap/bin/certbot /usr/bin/certbot
Verifica la instalación.
$ certbot --version certbot 2.8.0
Ejecuta el siguiente comando para generar un certificado SSL.
$ sudo certbot certonly --nginx --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m [email protected] -d mastodon.example.com
El comando anterior descargará un certificado en el directorio /etc/letsencrypt/live/mastodon.example.com
de tu servidor.
Genera un certificado de grupo Diffie-Hellman.
$ sudo openssl dhparam -dsaparam -out /etc/ssl/certs/dhparam.pem 4096
Comprueba el servicio programador de renovaciones de Certbot.
$ systemctl list-timers
Encontrarás snap.certbot.renew.service
como uno de los servicios programados para ejecutarse.
NEXT LEFT LAST PASSED UNIT ACTIVATES ----------------------------------------------------------------------------------------------------------------------------------------- Mon 2024-01-01 20:03:52 UTC 9h left Mon 2023-12-11 21:56:24 UTC 2 weeks 6 days ago apt-daily.timer apt-daily.service Mon 2024-01-01 21:06:00 UTC 10h left - - snap.certbot.renew.timersnap.certbot.renew.service Tue 2024-01-02 00:00:00 UTC 13h left - - dpkg-db-backup.timer dpkg-db-backup.service
Realiza una ejecución en seco del proceso para comprobar si la renovación SSL funciona correctamente.
$ sudo certbot renew --dry-run
Si no ves ningún error, ya está todo listo. Tu certificado se renovará automáticamente.
Paso 7 – Configurar Nginx
Abre el archivo /etc/nginx/nginx.conf
para editarlo.
$ sudo nano /etc/nginx/nginx.conf
Añade la siguiente línea antes de la línea include /etc/nginx/conf.d/*.conf;
.
server_names_hash_bucket_size 64;
Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te solicite.
Crea y abre el archivo /etc/nginx/conf.d/mastodon.conf
para editarlo.
$ sudo nano /etc/nginx/conf.d/mastodon.conf
Pega en él el siguiente código.
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 default_server; server_name mastodon.example.com; location / { return 301 https://$host$request_uri; } } server { listen 443 ssl; server_name mastodon.example.com; access_log /var/log/nginx/mastodon.access.log; error_log /var/log/nginx/mastodon.error.log; http2 on; # Enable HTTP/2 - works only on Nginx 1.25.1+ ssl_certificate /etc/letsencrypt/live/mastodon.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/mastodon.example.com/privkey.pem; ssl_trusted_certificate /etc/letsencrypt/live/mastodon.example.com/chain.pem; ssl_session_timeout 1d; # Enable TLS versions (TLSv1.3 is required upcoming HTTP/3 QUIC). ssl_protocols TLSv1.2 TLSv1.3; # Enable TLSv1.3's 0-RTT. Use $ssl_early_data when reverse proxying to # prevent replay attacks. # # @see: https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_early_data ssl_early_data on; ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384'; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_tickets off; keepalive_timeout 70; sendfile on; client_max_body_size 80m; # OCSP Stapling --- # fetch OCSP records from URL in ssl_certificate and cache them ssl_stapling on; ssl_stapling_verify on; ssl_dhparam /etc/ssl/certs/dhparam.pem; add_header X-Early-Data $tls1_3_early_data; root /opt/mastodon/web/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; add_header Strict-Transport-Security "max-age=31536000" always; location / { try_files $uri @proxy; } location ~ ^/(system/accounts/avatars|system/media_attachments/files) { add_header Cache-Control "public, max-age=31536000, immutable"; add_header Strict-Transport-Security "max-age=31536000" always; root /opt/mastodon/; try_files $uri @proxy; } location ~ ^/(emoji|packs) { add_header Cache-Control "public, max-age=31536000, immutable"; add_header Strict-Transport-Security "max-age=31536000" always; try_files $uri @proxy; } location /sw.js { add_header Cache-Control "public, max-age=0"; add_header Strict-Transport-Security "max-age=31536000" always; try_files $uri @proxy; } 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; add_header Strict-Transport-Security "max-age=31536000" always; tcp_nodelay on; } 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; } error_page 500 501 502 503 504 /500.html; } # This block is useful for debugging TLS v1.3. Please feel free to remove this # and use the `$ssl_early_data` variable exposed by NGINX directly should you # wish to do so. map $ssl_early_data $tls1_3_early_data { "~." $ssl_early_data; default ""; }
Cuando hayas terminado, guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te solicite.
Verifica la sintaxis del archivo de configuración de Nginx.
$ sudo nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
Reinicia el servidor Nginx.
$ sudo systemctl restart nginx
Paso 8 – Iniciar Mastodon
Herramienta Tootctl CLI
La herramienta Tootctl CLI se utiliza para realizar tareas administrativas en Mastodon. Necesitamos hacerla accesible en el shell del host.
Crea el archivo /usr/local/bin/tootctl
y ábrelo para editarlo.
$ sudo nano /usr/local/bin/tootctl
Pega en él el siguiente código.
#!/bin/bash docker compose -f /opt/mastodon/docker-compose.yml run --rm shell tootctl "$@"
Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te pida.
Da permiso de ejecución al archivo.
$ sudo chmod +x /usr/local/bin/tootctl
Fichero de servicio Mastodon
Puedes iniciar los contenedores Mastodon utilizando el comando Docker compose, pero es más fácil hacerlo mediante un archivo de unidad systemd.
Crea y abre el archivo de servicio Mastodon para editarlo.
$ sudo nano /etc/systemd/system/mastodon.service
Pega en él el siguiente código.
[Unit] Description=Mastodon service After=docker.service [Service] Type=oneshot RemainAfterExit=yes WorkingDirectory=/opt/mastodon ExecStart=/usr/bin/docker compose -f /opt/mastodon/docker-compose.yml up -d ExecStop=/usr/bin/docker compose -f /opt/mastodon/docker-compose.yml down [Install] WantedBy=multi-user.target
Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te solicite.
Recarga el demonio del sistema para iniciar el archivo de servicio.
$ sudo systemctl daemon-reload
Habilita e inicia el servicio Mastodon.
$ sudo systemctl enable --now mastodon.service
Comprueba el estado de los contenedores Docker.
$ watch docker compose -f /opt/mastodon/docker-compose.yml ps
Una vez que el estado de los contenedores cambie a running (healthy)
, sal de la pantalla pulsando Ctrl + C.
Crea el usuario admin para Mastodon y anota la contraseña proporcionada.
$ tootctl accounts create navjot --email [email protected] --confirmed --role Owner OK New password: 1338afbe1b4e06e823b6625da80cb537
Si quieres cerrar los registros de usuarios, utiliza el siguiente comando.
$ tootctl settings registrations close
Para abrir de nuevo los registros, emite el siguiente comando.
$ tootctl settings registrations open
Inicializar la búsqueda
Necesitarás hacer un toot antes de poder crear y poblar los índices de Elasticsearch. Una vez que hayas hecho un toot, emite el siguiente comando.
$ tootctl search deploy
Es posible que obtengas el siguiente error.
/opt/mastodon/vendor/bundle/ruby/3.0.0/gems/ruby-progressbar-1.11.0/lib/ruby-progressbar/progress.rb:76:in `total=': You can't set the item's total value to less than the current progress. (ProgressBar::InvalidProgressError) from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/ruby-progressbar-1.11.0/lib/ruby-progressbar/base.rb:178:in `block in update_progress' from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/ruby-progressbar-1.11.0/lib/ruby-progressbar/output.rb:43:in `with_refresh' from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/ruby-progressbar-1.11.0/lib/ruby-progressbar/base.rb:177:in `update_progress' from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/ruby-progressbar-1.11.0/lib/ruby-progressbar/base.rb:101:in `total=' from /opt/mastodon/lib/mastodon/search_cli.rb:67:in `deploy' from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/thor-1.2.1/lib/thor/command.rb:27:in `run' from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/thor-1.2.1/lib/thor/invocation.rb:127:in `invoke_command' from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/thor-1.2.1/lib/thor.rb:392:in `dispatch' from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/thor-1.2.1/lib/thor/invocation.rb:116:in `invoke' from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/thor-1.2.1/lib/thor.rb:243:in `block in subcommand' from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/thor-1.2.1/lib/thor/command.rb:27:in `run' from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/thor-1.2.1/lib/thor/invocation.rb:127:in `invoke_command' from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/thor-1.2.1/lib/thor.rb:392:in `dispatch' from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/thor-1.2.1/lib/thor/base.rb:485:in `start' from /opt/mastodon/bin/tootctl:8:in `<main>'
En este caso, entra en el shell del contenedor del sitio web.
$ docker exec -it mastodon-website-1 /bin/bash
Ejecuta el siguiente comando.
$ sed -E '/progress.total = /d' -i lib/mastodon/search_cli.rb
Sal del intérprete de comandos del contenedor.
$ exit
Ejecuta de nuevo el comando de despliegue de Elasticsearch. A veces el comando puede funcionar más tarde. Se trata de un problema en curso en Mastodon, por lo que no existe una solución definitiva por el momento.
$ tootctl search deploy Done! 1/?? |-=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=---=| ETA: ??:??:?? (0 docs/s) Indexed 1 records, de-indexed 0
Servicios de ayuda adicionales
Vamos a crear otro servicio para eliminar los archivos multimedia descargados.
Crea y abre el servicio de eliminación de archivos multimedia de Mastodon para editarlo.
$ sudo nano /etc/systemd/system/mastodon-media-remove.service
Pega en él el siguiente código.
[Unit] Description=Mastodon - media remove service Wants=mastodon-media-remove.timer [Service] Type=oneshot StandardError=null StandardOutput=null WorkingDirectory=/opt/mastodon ExecStart=/usr/bin/docker compose -f /opt/mastodon/docker-compose.yml run --rm shell tootctl media remove [Install] WantedBy=multi-user.target
Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te pida.
Si quieres programar la eliminación de archivos multimedia, puedes configurar un servicio temporizador para ello.
$ sudo nano /etc/systemd/system/mastodon-media-remove.timer
Pega el siguiente código.
[Unit] Description=Schedule a media remove every week [Timer] Persistent=true OnCalendar=Sat *-*-* 00:00:00 Unit=mastodon-media-remove.service [Install] WantedBy=timers.target
Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te solicite.
Puedes configurar otro servicio para eliminar las tarjetas de previsualización enriquecidas generadas mediante etiquetas OpenGraph.
$ sudo nano /etc/systemd/system/mastodon-preview_cards-remove.service
Pega el siguiente código.
[Unit] Description=Mastodon - preview cards remove service Wants=mastodon-preview_cards-remove.timer [Service] Type=oneshot StandardError=null StandardOutput=null WorkingDirectory=/opt/mastodon ExecStart=/usr/bin/docker compose -f /opt/mastodon/docker-compose.yml run --rm shell tootctl preview_cards remove [Install] WantedBy=multi-user.target
Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te solicite.
Configura el servicio de temporizador correspondiente.
$ sudo nano /etc/systemd/system/mastodon-preview_cards-remove.timer
Pega el siguiente código.
[Unit] Description=Schedule a preview cards remove every week [Timer] Persistent=true OnCalendar=Sat *-*-* 00:00:00 Unit=mastodon-preview_cards-remove.service [Install] WantedBy=timers.target
Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te solicite.
Recarga el demonio del sistema.
$ sudo systemctl daemon-reload
Habilita e inicia los temporizadores.
$ sudo systemctl enable --now mastodon-preview_cards-remove.timer $ sudo systemctl enable --now mastodon-media-remove.timer
Lista todos los temporizadores para comprobar la programación de los servicios Mastodon.
$ systemctl list-timers ..... Sat 2024-01-06 00:00:00 UTC 4 days left - - mastodon-media-remove.timer mastodon-media-remove.service Sat 2024-01-06 00:00:00 UTC 4 days left - - mastodon-preview_cards-remove.timer mastodon-preview_cards-remove.service
Acceder a Mastodon
Visita la URL https://mastodon.example.com
para acceder a tu instancia y verás una página similar.
En la captura de pantalla anterior, puedes ver que hay 0 usuarios. Esto se debe a que aún no hemos iniciado sesión. Aunque crees una cuenta de administrador, no aparece en la página principal en la primera ejecución. Para ello, inicia sesión en tu instancia y accederás a la siguiente página.
Haz clic en la opción Preferencias de la barra lateral derecha para acceder a la configuración. Desde ahí, haz clic en la opción Administración del menú de la izquierda para acceder al panel de administración de Mastodon.
Haz clic en la opción Configuración del servidor de la barra lateral izquierda.
Aquí, introduce tu nombre de usuario de contacto y tu correo electrónico profesional, que se reflejarán en la página de inicio de tu servidor. Rellena también otra información como la descripción del servidor, el logotipo y las reglas del servidor para personalizar tu instancia de Mastodon.
Paso 9 – Mantenimiento de Mastodon
Para ver el rendimiento y los registros de tu instancia de Mastodon, dirígete a https://mastodon.example.com/sidekiq/
.
Aquí puedes ver una lista de varios procesos y tareas programadas relacionadas con tu instancia de Mastodon. También puedes comprobar si hay tareas fallidas en la sección Muertos o Reintentos. También te indicará el uso de memoria de tu instancia.
Puedes comprobar el estado de la base de datos de tu instancia desde https://mastodon.example.com/pghero/
.
Puedes realizar el mantenimiento de tu base de datos, ejecutar consultas SQL y eliminar índices no utilizados. Para activar las estadísticas de consulta, haz clic en el botón Activar de la página anterior y obtendrás la siguiente información.
Cambia al usuario root.
$ sudo -i su
Cambia al directorio /opt/mastodon/database/postgresql
.
$ cd /opt/mastodon/database/postgresql
Abre el archivo postgresql.conf
.
$ nano postgresql.conf
Busca la línea #shared_preload_libraries = '' # (change requires restart)
y sustitúyela por lo siguiente.
shared_preload_libraries = 'pg_stat_statements'
Añade la siguiente línea al final del archivo.
pg_stat_statements.track = all
Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te solicite.
Reinicia los contenedores Mastodon.
$ systemctl restart mastodon.service
Sal del shell raíz.
$ exit
Si compruebas la página de salud de la base de datos, podrás ver si ahora hay alguna consulta lenta.
Nota: También puedes iniciar las URL de PgHero y Sidekiq desde el menú Preferencias.
Si tu sitio no se carga por alguna razón, puedes comprobar los registros generados por Docker.
$ docker logs <container-name>
Paso 10 – Copia de seguridad de Mastodon
Utilizaremos una herramienta de terceros llamada Restic para hacer una copia de seguridad de Mastodon. El primer paso para hacer una copia de seguridad utilizando Restic es añadir todos los archivos y directorios a la lista de repositorios.
Crea y abre el archivo de la lista de repositorios para editarlo.
$ sudo nano /opt/mastodon/backup-files
Pega en él las siguientes líneas.
/etc/nginx /etc/letsencrypt /etc/systemd/system /root /opt/mastodon/database/pgbackups /opt/mastodon/*.env /opt/mastodon/docker-compose.yml /opt/mastodon/branding /opt/mastodon/database/redis /opt/mastodon/web/system /opt/mastodon/backup-files /opt/mastodon/mastodon-backup
Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te pida.
Instala Restic.
$ sudo apt install restic
Crea un repositorio de copia de seguridad y crea la copia de seguridad inicial. Vamos a hacer una copia de seguridad de nuestros datos en el servicio S3.
$ restic -r s3:https://$SERVER:$PORT/mybucket init $ restic -r s3:https://$SERVER:$PORT/mybucket backup $(cat /opt/mastodon/backup-files) --exclude /opt/mastodon/database/postgresql
Crea un temporizador de servicio de copia de seguridad Mastodon y ábrelo para editarlo.
$ sudo nano /etc/systemd/system/mastodon-backup.timer
Pega en él el siguiente código.
[Unit] Description=Schedule a mastodon backup every hour [Timer] Persistent=true OnCalendar=*:00:00 Unit=mastodon-backup.service [Install] WantedBy=timers.target
Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te pida.
Crea un archivo de servicio de copia de seguridad de Mastodon y ábrelo para editarlo.
$ sudo nano /etc/systemd/system/mastodon-backup.service
Pega en él el siguiente código.
[Unit] Description=Mastodon - backup service # Without this, they can run at the same time and race to docker compose, # double-creating networks and failing due to ambiguous network definition # requiring `docker network prune` and restarting After=mastodon.service [Service] Type=oneshot StandardError=file:/var/log/mastodon-backup.err StandardOutput=file:/var/log/mastodon-backup.log WorkingDirectory=/opt/mastodon ExecStart=/bin/bash /opt/mastodon/mastodon-backup [Install] WantedBy=multi-user.target
Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te solicite.
A continuación, crea y abre el archivo /opt/mastodon/mastodon-backup
para editarlo. Contiene los comandos de copia de seguridad propiamente dichos.
$ sudo nano /opt/mastodon/mastodon-backup
Pega en él el siguiente código.
#!/bin/bash set -e AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= SERVER= PORT= RESTIC_PASSWORD_FILE=/root/restic-pasword docker compose -f /opt/mastodon/docker-compose.yml run --rm postgresql sh -c "pg_dump -Fp mastodon | gzip > /backups/dump.sql.gz" restic -r s3:https://$SERVER:$PORT/mybucket --cache-dir=/root backup $(cat /opt/mastodon/backup-files) --exclude /opt/mastodon/database/postgresql restic -r s3:https://$SERVER:$PORT/mybucket --cache-dir=/root forget --prune --keep-hourly 24 --keep-daily 7 --keep-monthly 3
Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te solicite.
Da permisos de ejecución al script de copia de seguridad.
$ sudo chmod +x /opt/mastodon/mastodon-backup
Recarga el demonio de servicio e inicia el servicio de copia de seguridad y el temporizador.
$ sudo systemctl daemon-reload $ sudo systemctl enable --now mastodon-backup.service $ sudo systemctl enable --now mastodon-backup.timer
Confirma que se están realizando copias de seguridad cada hora y que se puede acceder a ellas mediante los siguientes comandos.
$ restic -r s3:https://$SERVER:$PORT/mybucket snapshots $ restic -r s3:https://$SERVER:$PORT/mybucket mount /mnt
Paso 11 – Actualizar Mastodon
Actualizar Mastodon requiere varios pasos. Primero, cambia al directorio
$ cd /opt/mastodon
Extrae las últimas imágenes de contenedor para Mastodon.
$ docker compose pull
Realiza los cambios que quieras en docker-compose.yml
.
Realiza todas las migraciones de bases de datos.
$ docker compose run --rm shell bundle exec rake db:migrate
Actualiza tus copias de archivos estáticos.
$ docker compose run --rm shell bash -c "cp -r /opt/mastodon/public/* /static/"
Reinicia los contenedores Mastodon.
$ sudo systemctl restart mastodon.service
Las instrucciones anteriores son instrucciones genéricas de actualización. Consulta siempre la página de versiones de GitHub de Mas todon para buscar tareas y comandos de actualización específicos entre versiones para asegurarte de que todo va bien.
Conclusión
Con esto concluye nuestro tutorial sobre la instalación de la Red Social Mastodon utilizando Docker en un servidor Debian 12. Si tienes alguna pregunta, publícala en los comentarios a continuación.