Cómo instalar la red social Mastodon con Docker en Rocky Linux 9
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 Rocky Linux 9 utilizando Docker. Docker facilita la instalación de Mastodon al contener todos los paquetes y servicios necesarios en contenedores.
Requisitos previos
- Un servidor con Rocky Linux 9 con un mínimo de 2 núcleos de CPU y 2 GB de memoria. Tendrás que actualizar el servidor según tus necesidades.
- 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 dnf update
- Instala los paquetes de utilidades básicas. Puede que algunos ya estén instalados.
$ sudo dnf install wget curl nano unzip yum-utils -y
Paso 1 – Configurar el cortafuegos
El primer paso es configurar el cortafuegos. Rocky Linux utiliza el cortafuegos Firewalld. Comprueba el estado del cortafuegos.
$ sudo firewall-cmd --state running
El cortafuegos funciona con diferentes zonas, y la zona pública es la que utilizaremos por defecto. Enumera todos los servicios y puertos activos en el cortafuegos.
$ sudo firewall-cmd --permanent --list-services
Debería mostrar la siguiente salida.
cockpit dhcpv6-client ssh
Wiki.js necesita los puertos HTTP y HTTPS para funcionar. Ábrelos.
$ sudo firewall-cmd --permanent --add-service=http $ sudo firewall-cmd --permanent --add-service=https
Añade enmascaramiento, ya que la aplicación contactará con otras instancias.
$ sudo firewall-cmd --permanent --add-masquerade
Recarga el cortafuegos para aplicar los cambios.
$ sudo firewall-cmd --reload
Paso 2 – Instalar Docker y Docker Compose
Rocky Linux viene con una versión antigua de Docker. Para instalar la última versión, instala primero el repositorio oficial de Docker.
$ sudo yum-config-manager \ --add-repo \ https://download.docker.com/linux/centos/docker-ce.repo
Instala la última versión de Docker.
$ sudo dnf install docker-ce docker-ce-cli containerd.io
Es posible que obtengas el siguiente error al intentar instalar Docker.
ror: Problem: problem with installed package buildah-1:1.26.2-1.el9_0.x86_64 - package buildah-1:1.26.2-1.el9_0.x86_64 requires runc >= 1.0.0-26, but none of the providers can be installed - package containerd.io-1.6.9-3.1.el9.x86_64 conflicts with runc provided by runc-4:1.1.3-2.el9_0.x86_64 - package containerd.io-1.6.9-3.1.el9.x86_64 obsoletes runc provided by runc-4:1.1.3-2.el9_0.x86_64 - cannot install the best candidate for the job
Utiliza el siguiente comando si te aparece el error anterior.
$ sudo dnf install docker-ce docker-ce-cli containerd.io docker-compose-plugin --allowerasing
Habilita y ejecuta el demonio Docker.
$ sudo systemctl enable docker --now
Comprueba que se está ejecutando.
? docker.service - Docker Application Container Engine Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled) Active: active (running) since Sat 2022-11-12 00:19:44 UTC; 6s ago TriggeredBy: ? docker.socket Docs: https://docs.docker.com Main PID: 99263 (dockerd) Tasks: 8 Memory: 28.1M CPU: 210ms CGroup: /system.slice/docker.service ??99263 /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)
Tendrás 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 está añadido al grupo Docker.
$ groups navjot wheel 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.
$ 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 $ sudo sysctl --load /etc/sysctl.d/90-max_map_count.conf
Configura SELinux para permitir las conexiones de red.
$ sudo setsebool -P httpd_can_network_connect 1
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 la propiedad de 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.
version: '3' services: postgresql: image: postgres:15-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.7 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 ulimits: memlock: soft: -1 hard: -1 healthcheck: test: ["CMD-SHELL", "nc -z elasticsearch 9200"] volumes: - elasticsearch:/usr/share/elasticsearch/data networks: - internal_network website: image: tootsuite/mastodon:v4.0.2 env_file: - application.env - database.env command: bash -c "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.0.2 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.0.2 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.0.2 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.0.2. 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.x. No hay una versión principal de Elasticsearch que puedas seguir en la página de Docker Hub, así que tendrás que seguir actualizándola manualmente para las actualizaciones de seguridad relacionadas con Java.
Ese internal: true
no funciona con firewalld, por eso está comentado en el archivo anterior. Si esto se arregla alguna vez, podrás volver a añadir esa restricción adicional.
Crear secretos de aplicación
El siguiente paso es crear valores secretos de aplicación.
Genera los valores SECRET_KEY_BASE
y OTP_SECRET
ejecutando dos veces el siguiente comando. La primera vez llevará algún tiempo, ya que extraerá las imágenes.
$ docker compose run --rm shell bundle exec rake secret
También puedes utilizar la utilidad openssl
para lo mismo.
$ openssl rand -hex 64
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
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=AKIA3FIG4NVFNSC3AHXE SMTP_PASSWORD=BHM4MVOjBmnGhSJ9lH3PAXKJ/9AiLWcUghG/kEN2kkFo [email protected] # secrets SECRET_KEY_BASE=c09fa403575e0b431e54a2e228f20cd5a5fdfdbba0da80598959753b829a4e3c0266eedbac7e3cdf9f3345db36c56302c0e1bc5bfc8c5d516be59a2c41de7e37 OTP_SECRET=febb7dbb0d3308094083733fc923a430e52ccec767d48d7d2e0c577bfcb6863dbdfc920b1004b1f8c2967b9866bd7a0b4a15460f9fc7687aa4a42acf54e5a3d4 # Changing VAPID keys will break push notifications VAPID_PRIVATE_KEY=13RgrfOY2tkwuUycylDPOkoHennkJ0ZAPV_fUwDy7-g= VAPID_PUBLIC_KEY=BDAQuGwPbh1kbCV904adYXHvz9lLRaJHkiQkihRDPyBn3QmkAYbR21WHYoP8TkyG6dylG6IXpEVfLwdoW7fJVns=
Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te solicite.
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=15ff12dcb93aa60680d2aadb4032ee PGPASSWORD=15ff12dcb93aa60680d2aadb4032ee PGPORT=5432 PGHOST=postgresql PGUSER=mastodon # pgbouncer configuration #POOL_MODE=transaction #ADMIN_USERS=postgres,mastodon #DATABASE_URL="postgres://mastodon:15ff12dcb93aa60680d2aadb4032ee@postgresql:5432/mastodon" # elasticsearch ES_JAVA_OPTS=-Xms512m -Xmx512m ELASTIC_PASSWORD=13382e99f6b2d4dc7f3d66e4b9872d # mastodon database configuration #DB_HOST=pgbouncer DB_HOST=postgresql DB_USER=mastodon DB_NAME=mastodon DB_PASS=15ff12dcb93aa60680d2aadb4032ee 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=13382e99f6b2d4dc7f3d66e4b9872d
Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te solicite.
Prepara Mastodon
Prepara los archivos estáticos para que los sirva Nginx.
$ 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
Paso 5 – Instalar Nginx
Rocky Linux viene con una versión antigua de Nginx. Necesitas descargar el repositorio oficial de Nginx para instalar la última versión.
Crea y abre el archivo /etc/yum.repos.d/nginx.repo
para crear el repositorio oficial de Nginx.
$ sudo nano /etc/yum.repos.d/nginx.repo
Pega en él el siguiente código.
[nginx-stable] name=nginx stable repo baseurl=http://nginx.org/packages/centos/$releasever/$basearch/ gpgcheck=1 enabled=1 gpgkey=https://nginx.org/keys/nginx_signing.key module_hotfixes=true [nginx-mainline] name=nginx mainline repo baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/ gpgcheck=1 enabled=0 gpgkey=https://nginx.org/keys/nginx_signing.key module_hotfixes=true
Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te pida.
Instala el servidor Nginx.
$ sudo dnf install nginx
Verifica la instalación.
$ nginx -v nginx version: nginx/1.22.1
Habilita e inicia el servidor Nginx.
$ sudo systemctl enable nginx --now
Comprueba el estado del servidor.
$ sudo systemctl status nginx ? nginx.service - nginx - high performance web server Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled) Active: active (running) since Sun 2022-11-13 13:49:55 UTC; 1s ago Docs: http://nginx.org/en/docs/ Process: 230797 ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf (code=exited, status=0/SUCCESS) Main PID: 230798 (nginx) Tasks: 3 (limit: 12355) Memory: 2.8M CPU: 13ms CGroup: /system.slice/nginx.service ??230798 "nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf" ??230799 "nginx: worker process" ??230800 "nginx: worker process"
Paso 6 – Instalar SSL
La herramienta Certbot genera certificados SSL utilizando la API Let’s Encrypt. Requiere el repositorio EPEL para funcionar.
$ sudo dnf install epel-release
Utilizaremos Snapd para instalar Certbot. Instala Snapd.
$ sudo dnf install snapd
Activa e Inicia el servicio Snap.
$ sudo systemctl enable snapd --now
Instala el paquete central de Snap.
$ sudo snap install core $ sudo snap refresh core
Crea los enlaces necesarios para que Snapd funcione.
$ sudo ln -s /var/lib/snapd/snap /snap $ echo 'export PATH=$PATH:/var/lib/snapd/snap/bin' | sudo tee -a /etc/profile.d/snapd.sh
Ejecuta el siguiente comando para instalar Certbot.
$ sudo snap install --classic certbot
Habilita Certbot creando el enlace simbólico a su ejecutable.
$ sudo ln -s /snap/bin/certbot /usr/bin/certbot
Genera el 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
Para comprobar si la renovación SSL funciona correctamente, realiza una ejecución en seco del proceso.
$ 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 http2; server_name mastodon.example.com; access_log /var/log/nginx/mastodon.access.log; error_log /var/log/nginx/mastodon.error.log; http2_push_preload on; # Enable HTTP/2 Server Push 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
Si aparece el siguiente error, lo más probable es que se deba a Restricciones de SELinux.
nginx: [emerg] open() "/var/run/nginx.pid" failed (13: Permission denied)
Para solucionar el error, ejecuta los siguientes comandos.
$ sudo ausearch -c 'nginx' --raw | audit2allow -M my-nginx $ sudo semodule -X 300 -i my-nginx.pp
Inicia de nuevo el servicio Nginx.
$ sudo systemctl start 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 admin 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-web-1 /bin/bash
Ejecuta el siguiente comando.
$ sed -E 's/indices.sum.+/2000/g' -i lib/mastodon/search_cli.rb
Sal del intérprete de comandos del contenedor.
$ exit
Ejecuta de nuevo el comando de despliegue de Elasticsearch.
$ tootctl search deploy
Servicios auxiliares adicionales
Vamos a crear otro servicio para eliminar los archivos multimedia descargados.
Crea y abre el servicio de eliminación de archivos multimedia 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
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 2 usuarios y 1 de ellos (yo) está configurado como administrador. Este no suele ser el caso. 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 sitio 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 dnf 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 Rocky Linux 9. Si tienes alguna pregunta, publícala en los comentarios a continuación.