0%

Hoy vamos a aprender cómo tener nuestro propio servidor de mastodon con docker usando ubuntu 22.04.

Como ya intenté una vez por mastodon (pero no era el lugar la verdad), vamos a aprender a desplegar y construir el contenedor de mastodon en Docker.
Lo harémos siguiendo los siguientes pasos:

  1. Preparar el equipo
  2. Bajar repositorio de mastodon
  3. Cambiar permisos a carpetas
  4. Configurar el entorno
  5. Configurar nginx
  6. Elasticsearch (opcional)
  7. Fin

1. Preparar el equipo

El paso mas importante de todos para preparar el servidor necesitamos primero es hacer todo el proceso con este video de fondo. Si no no funciona.

Asumimos que tenemos un correo para el SMTP y un dominio (si no es así mal empezamos, cierra esta web y empieza por ahí)
Ahora necesitaríamos:

  • Instalar docker
  • Configurar las reglas de salida del cortafuegos
  • Instalar certbot

Al lio.

Instalar Docker

No os dejeis engañar por los cantos de sirena de instalar el servicio cuando instales ubuntu server. A la minima te dará problemas.
Seguimos los pasos que aparecen en la página oficial

Que son, añadir el repositorio

1
2
3
4
5
6
7
8
9
10
11
12
13
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

# Add the repository to Apt sources:
echo \
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update

E instalarlo

1
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Configurar las reglas de salida del cortafuegos

Usaremos ufw, aka Uncomplicated Firewall (siempre me hago un lio con iptables)

1
2
3
4
5
6
# Activar cortafuegos
sudo ufw enable

# Añadir reglas http y https (puertos 80 y 443)
sudo ufw allow http
sudo ufw allow https
Instalar certbot

Si queremos que funcione nuestro servidor de mastodon tenemos que tener un certificado para que funcione el https. Así que primero, actualizamos el sistema e instalamos

1
2
3
4
# Actualizamos el sistema (aunque puede que lo hicieramos en el paso anterior, si es asi saltatelo)
sudo apt-get update
# E instalamos
sudo apt-get install certbot python3-certbot-apache

Por ultimo instalamos el certificado.
Nota: Si has sido muy rápido y has instalado nginx primero, lanza sudo “systemctl stop nginx” para pararlo, ya que imagino que estará tocando las narices en el puerto 80

1
sudo certbot certonly --standalone -d tu.dominio

(cambia “tu.dominio” por tu puto dominio, no me seas cabestro)

Y con eso ya tendriamos el certbot funcionando así como los puertos abiertos. Ya estamos listos para la acción.

2. Bajar el repositorio de mastodon

Este es el paso mas corto (mira que bien), en primer lugar necesitamos elegir el directorio donde vamos a instalar mastodon.

No ese no, ojo cuidao que por defecto todos los archivos de tus usuarios y los federados se van a almacenar ahí, busca una partición con espacio de sobra al menos 100GB para ir moviendote.

¿Ese? ¿seguro? bueeno, pues ahora, clonas el repositorio
¿que como? a ver que te lo tengo que dar todo hecho…

1
2
cd /tu/directorio/elegido
git clone https://github.com/mastodon/mastodon.git

¿Cómo? ¿que no tienes git? Bueno, si es el caso vete aqui que tampoco te lo tengo que dar todo todo hecho

Si tienes que modificar el limite de caracteres te recomiendo un post anterior, concretamente este

Y con eso ya estaríamos. No es estrictamente necesario construir la imagen de docker, ya que si no la construimos la bajará cuando lancemos el server, pero si modificamos algo que no sea .env.production o docker-compose.yml no nos olvidemos de lanzar

1
docker build . -t "ghcr.io/mastodon/mastodon:v4.2.0"

3. Cambiar permisos a carpetas

Algunas carpetas necesitan algunos permisos especiales para la imagen de docker, si da problemas podemos cambiar los permisos de la carpeta /public

1
sudo chown -R 991:991 public/*

Y si usamos elasticsearch

1
sudo chown -R 1000:1000 elasticsearch/*

4. Configurar el entorno

Aqui tenemos dos opciones, o crear nuestro .env.production desde 0, para lo cual copiaremos .env.production.sample a .env.production

Desde la carpeta donde tenemos el repositorio

1
cp .env.production.sample .env.production

y rellenamos la configuración que queramos, o bien lanzamos

1
docker-compose run --rm web bundle exec rake mastodon:setup

Lo cual lanzara el asistente de configuración de mastodon.

Teneis más información en (la web oficial de mastodon)[https://docs.joinmastodon.org/admin/config/]

NOTA: Muy importante cuando relleneis la configuración, la dirección del host de postgresql es “db”, la de redis es “redis” y la de elasticsearch es “es” sin mas.
Hay que tener en cuenta que los contenedores se reconocen entre si con esos aliases y es la dirección que necesitan para comunicarse

5. Configurar nginx

Ya va quedando menos, configuremos nginx.
Primero copiamos el archivo nginx que tenemos en el repositorio de mastodon a nuestro directorio de configuración de nginx.

1
sudo cp /tu/directorio/elegido/mastodon/dist/nginx.conf /etc/nginx/sites-available/mastodon

Y ahora editamos:

Si buscamos hay dos secciones donde pone “server_name”

1
2
3
4
5
6
7
8
9
10
11
12
13
server {
listen 80;
listen [::]:80;
server_name example.com;
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 example.com;

hay que sustituir donde pone example.com por “tu.dominio” (de nuevo, tu puto dominio, no me seas merluzo)

Luego, hay una parte comentada con los certificados

1
2
3
# Uncomment these lines once you acquire a certificate:
# ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
# ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

Descomentandola y añadiendo tu dominio en el path quedaría en nuestro ejemplo algo así

1
2
3
# Uncomment these lines once you acquire a certificate:
ssl_certificate /etc/letsencrypt/live/tu.dominio/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/tu.dominio/privkey.pem;

(no me hagas repetirte lo mismo)
Ojo cuidao que si no hemos instalado el certificado digital nos fallará nginx cuando lo lancemos

Ahora tenemos una serie de “locations” que son algo asi:

1
2
3
4
5
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;
}

En todos ellos, al usar docker tenemos que sustituir el try_files $uri =404 por try_files $uri @proxy;
Quedando así

1
2
3
4
5
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 @proxy;
}

Y ya para terminar al final del todo, hay dos “location” que tienen proxy_pass estas reglas son las rutas hacia el servicio de streaming de mastodon y el de la web hay que sustituir donde pone “https://backend“ por nuestro backend quedando mas o menos así

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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://127.0.0.1:4000;
proxy_buffering off;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";

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://127.0.0.1:3000;
proxy_force_ranges on;
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;
}

Ya casi estamos

6. Elasticsearch (opcional)

Para añadir elasticsearch a la mezcla, en nuestro repositorio de mastodon tenemos un docker-compose.yml

En ese archivo veremos una seccion “es:” comentada, tiene que quedar así:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
es:
restart: always
image: docker.elastic.co/elasticsearch/elasticsearch:7.17.4
environment:
- "ES_JAVA_OPTS=-Xms512m -Xmx512m -Des.enforce.bootstrap.checks=true"
- "xpack.license.self_generated.type=basic"
- "xpack.security.enabled=false"
- "xpack.watcher.enabled=false"
- "xpack.graph.enabled=false"
- "xpack.ml.enabled=false"
- "bootstrap.memory_lock=true"
- "cluster.name=es-mastodon"
- "discovery.type=single-node"
- "thread_pool.write.queue_size=1000"
networks:
- external_network
- internal_network
healthcheck:
test: ["CMD-SHELL", "curl --silent --fail localhost:9200/_cluster/health || exit 1"]
volumes:
- ./elasticsearch:/usr/share/elasticsearch/data
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536
hard: 65536
ports:
- '127.0.0.1:9200:9200'

Es muy posible que elasticsearch os falle porque necesita una configuración de memoria virtual extra, en ese caso podemos lanzar

1
sysctl -w vm.max_map_count=262144

Pero en el siguiente reinicio la configuración se irá. Para ello editamos el fichero /etc/sysctl.conf y añadimos al final

1
vm.max_map_count=262144

7. Fin

Bueno, ha sido un largo y extraño viaje. Una vez aquí ya podemos lanzar el servidor de mastodon “sin miedo”*

Desde la carpeta del repositorio:
Empezaremos migrando la base de datos (para construir las estructuras)

1
docker-compose run --rm web rake db:migrate

Y si queremos podemos construir los indices de elasticsearch (aunque van a estar vacíos la verdad) y solo si usamos elasticsearch

1
docker-compose run --rm web bin/tootctl search deploy

Y por último lanzamos los contenedores.

1
docker-compose up -d

Con esto ya deberias poder acceder “sin miedo”* a tu.dominio (ejem… que no me entere yo que sigues usandolo literal) y empezar a disfrutar de un nodo descentralizado.

En fin, ¡hasta luego! y gracias por el pescado.

*El miedo existe y existirá porque ni siquiera he validado la guía apropiadamente

En esta entrada vamos a contar de forma breve como cambiar el número de caracteres en mastodon.
Para hacerlo, seguiremos 3 sencillos siguientes pasos:
(nota: este tutorial se ha hecho usando mastodon 4.2.0 aunque es válido para 4.1 en adelante)

  1. Separar la rama de git del repositorio de mastodon
  2. Editar archivos de mastodon
  3. Reconstruir y/o reiniciar

Paso 1: Separar la rama de git del repositorio de mastodon

Para ello tenemos que ir a nuestro repositorio de mastodon, en una instalación local suele estar alojada /home/mastodon/live asi que usaremos de ejemplo esa ruta, aunque puede estar donde esté.

1
cd /home/mastodon/live

Una vez dentro de la carpeta del repositorio, creamos una rama nueva, que vamos a llamar “mod”, para ello llamamos al comando checkout con el flag -b que lo que hace es crear una rama nueva y hacer el checkout desde donde estamos.

1
git checkout -b mod

Y con esto ya tenemos nuestra rama separada

Paso 2: Editar archivos de mastodon

Una vez hecho esto, editamos los archivos de mastodon que implican el número limite de caracteres, empezaremos con app/javascript/mastodon/features/compose/components/comopose_form.jsx donde nos encontraremos en la linea 103:

1
2
3
4
5
6
7
canSubmit = () => {
const { isSubmitting, isChangingUpload, isUploading, anyMedia } = this.props;
const fulltext = this.getFulltextForCharacterCounting();
const isOnlyWhitespace = fulltext.length !== 0 && fulltext.trim().length === 0;

return !(isSubmitting || isUploading || isChangingUpload || length(fulltext) > 500 || (isOnlyWhitespace && !anyMedia)); //esta es la linea 103
};

Y en la linea 300

1
<CharacterCounter max={500} text={this.getFulltextForCharacterCounting()} />

Esos dos numeros hay que cambiarlos por el límite deseado

Luego, en el archivo app/validators/status_length_validator.rb en la linea 4 nos encontramos una variable de MAX_CHARS que la cambiaremos al número que queramos

1
2
3
4
# frozen_string_literal: true

class StatusLengthValidator < ActiveModel::Validator
MAX_CHARS = 500 # numero a cambiar por el que quieras

Una vez hecho esto, aplicamos los cambios a la rama

1
2
git add --all # aplicando cambios a la rama
git commit -m "Cambiando el numero de caracteres a XXX" # guardando cambios en la rama con el mensaje

Paso 3: Reconstruir y/o reiniciar

Una vez hecho esto, tenemos dos casos, si tienes mastodon en local, se recompila:

1
RAILS_ENV=production bundle exec rails assets:precompile

y se reinicia:

1
2
3
systemctl restart mastodon-sidekiq
systemctl reload mastodon-web
systemctl restart mastodon-streaming

En caso de tener mastodon en docker, reconstruimos la imagen

1
docker build . -t "ghcr.io/mastodon/mastodon:v4.2.0" # esta etiqueta puede ser personalizada, dependiendo de como esté reflejado en el archivo docker-compose.yml

y cuando esté lista, levantamos los contenedores

1
docker-compose up -d

Final

Y con eso ya tendríamos el limite de caracteres actualizado ^_^U

Espero que sea util a alguien, en el futuro a ver si subo un tutorial para instalar mastodon usando docker.

¡A tocarlo todo!

Lo malo de esta plataforma de blogging, no es solo el tema de ser “techie” (que realmente es una ventaja, me gusta bastante poder postear desde el terminal), sino que muchos temas (para personalizar el blog) están directamente en chino.

No sabia cuando me meti a usar esta plataforma de blogging que me iba a encontrar tanta comunidad china. Igualmente, aunque es un follón personalizar el blog (creo que se va a quedar con el tema next), me gusta el tema de seguir practicando el markdown para formateo.

Además está muy bien para poder escribir código sin problema, por ejemplo, este el script para crear los templates de posts en local:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#!/usr/bin/env python3

import os
import sys
import datetime
import re
import unicodedata
folder = 'posts'

def normalize(sentence):
normalized= re.sub(r'(\.$|[¡!¿?])','',sentence)
normalized = ''.join(c for c in unicodedata.normalize('NFD', normalized)
if unicodedata.category(c) != 'Mn')
return normalized

def main(postname):
if not os.path.exists(folder):
os.makedirs(folder)
slug = normalize(postname.replace(' ', '-'))
post = os.path.join(folder, f'{slug}.md')
now = datetime.datetime.now()
if os.path.exists(post):
print('Post already exists')
sys.exit(1)
with open(post, 'w') as f:
f.write('---\n')
f.write('title: {}\n'.format(postname))
f.write('date: {}\n'.format(now.strftime('%Y-%m-%d %H:%M:%S')))
f.write('tags: \n')
f.write('---\n')
print('Created {}'.format(post))

if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('postname', help='Post name')
args = parser.parse_args()

main(args.postname)

Al final hay algunas cosas que se me hacen mas comodas escribiendolas en texto plano que con editores WYSIWYG sofisticados (otras cosas no, tendria que buscar como dividir un texto en columnas por ejemplo) así que ni tan mal, quizá escriba una entrada un poco mas completa sobre cómo montar mastodon en docker modificandolo como ya me pidieron y no hice apropiadamente.
Ahora si que podría.

En fin, ¡seguimos por el fediverso!

EDITO: Aquí estoy probando a meter un “toot” embebido en el post :)

¡Hola Gambitas!

Hola, este es el resultado de una prueba de unos pequeños scripts para publicación remota.

Basicamente es un pequeño script de python que emula el

1
hexo new {post}

junto a un script conecta por ssh a la maquina para copiar el contenido de los posts y publicarlos.

Luego a ver si veo como se enganchan las imagenes y con esto ya estaría. Supongo que un añadido bueno será meter comentarios, ya veré como se hace.

See you later shrimpinator

Añado una imagen para ver si pirulan

¡Buenas!

Si has llegado aqui significa que estas viendo el blog de shrimply.social

Seguramente leas cuando leas esto está manga por hombro, asi que bueno… perdoname “de antebraso”

Aqui iremos poniendo algunas cosillas, no sé si opinión, no sé si técnicas, o no se si nada en absoluto. Ya lo iremos viendo :P