ejabberd

Este documento ainda está em andamento!

ejabberd é um servidor XMPP de alto desempenho facilmente escalável para grandes servidores públicos, mas não tão pesado para auto-hospedagem. Ele pode ser instalado de repositórios Linux de maneira relativamente fácil e a configuração padrão é adequada para um servidor XMPP razoavelmente eficiente. Entretanto, essas configurações padrão tendem ser bem conservativas e se você quiser ter melhor suporte para funções XMPP mais modernas, você vai precisar fazer alguns ajustes. A documentação para todos as configurações dos módulos ejabberd podem ser encontradas aqui.

Pré-requisitos:

  • Um nome de domínio
  • Um servidor

Esse tutorial começa com um único virtualhost2. Para fins de exemplo, example.net é o domínio. Substitua todas as instâncias de example.net com o seu próprio domínio.

Registros A/AAAA de DNS e registros SRV são requeridos para cada serviço no servidor XMPP.

Registros A:

  • exemplo.net
  • muc.example.net (para conversas em grupo)
  • upload.example.net (para o upload de aquivos HTTP)
  • pubsub.example.net (para o nó pubsub)
  • proxy.example.net (para a proxy de transferência de arquivos)
  • turn.example.net (para STUN/TURN)

Cada um apontando ao endereço IP do servidor que vai executar ejabberd.

Crie registros SRV para cada um, apontando ao domínio que resolve ao servidor, assim:

(Todos os registros estão no formato _service._proto.name IN SRV prioridade peso porta alvo)

1_xmpp-client._tcp   IN SRV  5 0 5222 example.net.
2_xmpps-client._tcp  IN SRV  5 0 5223 example.net.
3_xmpp-server._tcp   IN SRV  5 0 5269 example.net.
4_xmpps-server._tcp  IN SRV  5 0 5270 example.net.

e

1_xmpp-client._tcp.muc   IN SRV  5 0 5222 example.net.
2_xmpps-client._tcp.muc  IN SRV  5 0 5223 example.net.
3_xmpp-server._tcp.muc   IN SRV  5 0 5269 example.net.
4_xmpps-server._tcp.muc  IN SRV  5 0 5270 example.net.

para cada um dos subdomínios (começando com muc). Exclua turn.example.net.

Finalmente, adicione um conjunto de registros SRV, para STUN/TURN.

1_stun._udp   IN SRV  5 0 3478 turn.example.net.
2_stun._tcp   IN SRV  5 0 3478 turn.example.net.
3_stuns._tcp  IN SRV  5 0 5349 turn.example.net.
4
5_turn._udp   IN SRV  5 0 3478 turn.example.net.
6_turn._tcp   IN SRV  5 0 3478 turn.example.net.
7_turns._tcp  IN SRV  5 0 5349 turn.example.net.

Informação extra: como resultado desses registros SRV de delegação, hospedar XMPP em um servidor diferente daquele em example.net é uma opção (ou seja dividindo serviços em um domínio entre servidores). Mais informações podem ser encontradas em XEP-0368.

Abra as portas:

TCP: 80 443 5222 5223 5269 5270 3478 5349 49152-65535

UDP: 3478 49152-65535

80 e 443 são para o servidor web, 5222, 5223, 5269 e 5270 são para XMPP, e o resto são para STUN/TURN.

  • obtenha (um) certificado(s) SSL para o seu domínio, assim como os vários subdomínios, em tudo:

    • exemplo.net
    • muc.exemplo.net
    • upload.exemplo.net
    • pubsub.exemplo.net
    • proxy.exemplo.net
    • turn.exemplo.net
  • proxypass http://127.0.0.1:5443 através para:

  • confirme que para /xmpp você tem o que é necessário para também fazer proxy de websockets. Se você está usando nginx, aumente client_max_body_size para uploads HTTP.

  • confirme que os arquivos de certificado são legíveis e/ou em um lugar que é legível pela conta ejabberd.

Para evitar o uso de algo como nginx + Certbot, use o módulo acme ejabberd, mas esse artigo assume que é desejado hospedar outros serviços web no mesmo sistema, no qual caso cada serviço HTTP seria encaminhado por proxy reversa a um serviço web HTTPS.

Finalmente instale o pacote de systema. Garanta que a build tem suporte PostgreSQL.

Confirme que o arquivo /etc/ejabberd/ejabberd.yml existe, e é legível pela conta que gerencia ejabberd (quase definitivamente ejabberd), copiando, se for necessário, o arquivo de exemplo ejabberd.yml ou usando o wget/curlpara obtê-lo do repositório do github. Se ele foi obtido do repositório, confirme que sua versão corresponde à versão ejabberd oferecida pelo seu SO.

Uma base de dados separada deve ser criada para cada virtualhost, pois isso esclarece as coisas, e em adição, facilita a migração de virtualhosts individuais no futuro. Entretanto, a habilidade de usar somente um, como é descrito aqui, também existe.

Siga as instruções padrão de instalação do PostgreSQL para o seu SO. Assim que isso for feito, conecte à base de dados como administrador e:

  1. crie uma conta da base de dados ejabberd com CREATE USER ejabberd WITH PASSWORD 'sua_senha';. Não esqueça de mudar a senha, e anota-la.
  2. crie uma base de dados para o virtualhost com CREATE DATABASE ejabberd_example OWNER ejabberd;. Substitua example com alguma coisa que corresponde ao virtualhost.
  3. saia da shell psql, e importe o schema da base de dados do GitHub com o comando curl -s https://raw.githubusercontent.com/processone/ejabberd/master/sql/pg.sql | sudo -u ejabberd psql ejabberd_example (novamente, substitua example).

Comece a substituir localhost embaixo de hosts com o virtualhost (ex. example.net), daí liste os arquivos de certificado previamente obtidos embaixo de certfiles.

1hosts:
2  - example.net
3
4certfiles:
5  - "/etc/ejabberd/certs/*/*"

Agora coloque default_db: sql no nível raiz do arquivo YAML. Isso deve ser seguido por host_config e a configuração da base de dados para o seu virtualhost, como é mostrado abaixo. Customize cada valor de acordo com a configuração.

 1host_config:
 2  example.net:
 3    sql_type: pgsql
 4    sql_server: "localhost"
 5    sql_port: 5432
 6    sql_username: "ejabberd"
 7    sql_password: "postgres_password"
 8    sql_database: "ejabberd_example"
 9    auth_method: sql
10    auth_password_format: scram

Embaixo de listen, certifique-se que todos os serviços corretos estão ativados em cada porta, incluindo s2s TLS na porta 5270 (não padrão):

 1listen:
 2  -
 3    port: 5222
 4    module: ejabberd_c2s
 5    max_stanza_size: 262144
 6    shaper: c2s_shaper
 7    access: c2s
 8    starttls_required: true
 9  -
10    port: 5223
11    tls: true
12    module: ejabberd_c2s
13    max_stanza_size: 262144
14    shaper: c2s_shaper
15    access: c2s
16    starttls_required: true
17  -
18    port: 5269
19    module: ejabberd_s2s_in
20    max_stanza_size: 524288
21  -
22    port: 5270
23    tls: true
24    module: ejabberd_s2s_in
25    max_stanza_size: 524288

Em seguinte, ative o servidor HTTP e os módulos de servidor STUN/TURN. Defina turn_ipv4_address e ip para o endereço IPv4 do servidor. TLS vai estar desligado para o servidor HTTP já que é feito uma proxy reversa pelo servidor web configurado anteriormente.

 1  -
 2    port: 5443
 3    module: ejabberd_http
 4    request_handlers:
 5      /xmpp/admin: ejabberd_web_admin
 6      /xmpp/bosh: mod_bosh
 7      /xmpp/upload: mod_http_upload
 8      /xmpp/ws: ejabberd_http_ws
 9      /.well-known/host-meta: mod_host_meta
10      /.well-known/host-meta.json: mod_host_meta
11  -
12    port: 3478
13    transport: udp
14    module: ejabberd_stun
15    use_turn: true
16    turn_min_port: 49152
17    turn_max_port: 65535
18    # O endereço IPv4 público do servidor:
19    turn_ipv4_address: 0.0.0.0
20  -
21    port: 5349
22    transport: tcp
23    module: ejabberd_stun
24    use_turn: true
25    tls: true
26    turn_min_port: 49152
27    turn_max_port: 65535
28    ip: 0.0.0.0
29    turn_ipv4_address: 0.0.0.0

Coloque s2s_use_starttls: required no root.

A partir daqui é possível configurar algumas ACLs. acls são apenas as listas de controle de acesso, configure access_rules de acordo com as suas necessidades, que vão ser passadas para as configurações de módulo. No mínimo uma conta de administrador é recomendada. Exemplo:

 1acl:
 2  admin:
 3    user: juliet@example.net
 4  capulet:
 5    - user: juliet@example.net
 6    - user: tybalt@example.net
 7  nurse:
 8    - user: angelica@example.net
 9
10access_rules:
11  household:
12    allow: capulet
13    allow: nurse

Adicione endereços de abuso embaixo de mod_disco. Também é possível adicionar outros endereços de contato, de acordo com XEP-0157:

1modules:
2# ...
3  mod_disco:
4    server_info:
5    -
6      modules: all
7      name: "abuse-addresses"
8      urls: ["mailto:abuse@example.net"]

Adicione mod_host_meta:

1  mod_host_meta:
2    bosh_service_url: "https://@HOST@/xmpp/bosh"
3    websocket_url: "wss://@HOST@/xmpp/ws"

Edite mod_mam, e mude assume_mam_usage para false e default para never se não é desejável arquivar mensagens por padrão:

1  mod_mam:
2    db_type: sql
3    assume_mam_usage: never
4    default: never

Adicione mod_stun_disco para anunciar o serviço STUN aos clientes, mudando 0.0.0.0 e example.net para o IP e o hostname do servidor, respectivamente:

 1  mod_stun_disco:
 2    credentials_lifetime: 12h
 3    services:
 4        -
 5          host: 0.0.0.0
 6          port: 3478
 7          type: stun
 8          transport: udp
 9          restricted: false
10        -
11          host: 0.0.0.0
12          port: 3478
13          type: turn
14          transport: udp
15          restricted: true
16        -
17          host: turn.example.net
18          port: 5349
19          type: stuns
20          transport: tcp
21          restricted: false
22        -
23          host: turn.example.net
24          port: 5349
25          type: turns
26          transport: tcp
27          restricted: true

Configure o hospedeiro para o subdomínio muc, senão ele vai tentar usar conference.example.net. Colocar mam: false em default_room_options vai desativar arquivação de mensagens no lado do servidor por padrão.

 1  mod_muc:
 2    host: muc.example.net
 3    access:
 4      - allow
 5    access_admin:
 6      - allow: admin
 7    access_create: muc_create
 8    access_persistent: muc_create
 9    access_mam:
10      - allow
11    default_room_options:
12      mam: false
1  mod_proxy65:
2    access: local
3    max_connections: 5
1  mod_http_upload:
2    put_url: https://@HOST@/xmpp/upload
3    docroot: /var/www/ejabberdupload
4    max_size: 1073741824
5    custom_headers:
6      "Access-Control-Allow-Origin": "https://@HOST@"
7      "Access-Control-Allow-Methods": "GET,HEAD,PUT,OPTIONS"
8      "Access-Control-Allow-Headers": "Content-Type"

Crie a pasta para o docroot, e garanta que ela pertence à conta ejabberd. Mude max_size (o tamanho de upload máximo) para qualquer valor seja preferido.

1  mod_pubsub:
2    access_createnode: pubsub_createnode
3    plugins:
4      - flat
5      - pep
6    force_node_config:
7      ## Evite clientes com bugs a fazerem suas bookmarks públicas
8      storage:bookmarks:
9        access_model: whitelist

Comece o servidor ejabberd!

1sudo -u ejabberd ejabberdctl start

(Dependendo do seu SO e da forma que você instalou ejabberd, isso pode precisar de mudanças.)

Registre um usuário administrador admin@example.net com a senha senha:

1sudo -u ejabberd ejabberdctl register admin example.net senha

Há um teste de conformidade em compliance.conversations.im para testar o servidor.

Após ter configurado tudo corretamente, mude, opcionalmente, o loglevel na raiz da configuração.

Haverá uma página de administrador acessível em https://example.net/xmpp/admin.

É possível configurar conversejs usando o mod_conversejs. Pode ser necessário atualizar a configuração do servidor web para encaminhar o novo endpoint (/chat abaixo).

 1listen:
 2  -
 3    port: 5443
 4    module: ejabberd_http
 5    request_handlers:
 6      /xmpp/bosh: mod_bosh
 7      /xmpp/ws: ejabberd_http_ws
 8      /chat: mod_conversejs
 9
10modules:
11  mod_conversejs:
12    websocket_url: "ws://@HOST@/xmpp/ws"
13    bosh_service_url: "https://@HOST@/xmpp/bosh"

Para cada virtualhost adicional uma nova base de dados deve ser criada, e adicionada à parte de base de dados da configuração. ex.:

 1host_config:
 2  example.net:
 3    sql_type: pgsql
 4    sql_server: "localhost"
 5    sql_port: 5432
 6    sql_username: "ejabberd"
 7    sql_password: "postgres_password"
 8    sql_database: "ejabberd_net"
 9    auth_method: sql
10    auth_password_format: scram
11  example.org:
12    sql_type: pgsql
13    sql_server: "localhost"
14    sql_port: 5432
15    sql_username: "ejabberd"
16    sql_password: "postgres_password"
17    sql_database: "ejabberd_org"
18    auth_method: sql
19    auth_password_format: scram

Não pode haver conflitos entre declarações no arquivo de configuração, então se mod_muc, mod_proxy65, mod_http_upload e mod_pubsub estiverem declarados embaixo de modules na raiz, eles (além de outras diferenças de configuração entre virtualhosts) devem ser deletadas e replicadas para cada virtualhost embaixo de append_host_config, na raiz. Exemplo a seguir:

 1append_host_config:
 2  example.org:
 3    modules:
 4      mod_muc:
 5        host: muc.example.org
 6        access_create: org_account
 7        access_persistent: org_account
 8        access:
 9          - allow
10        access_admin:
11          - allow: admin
12        default_room_options:
13          mam: false
14      mod_proxy65:
15        access: org_account
16        max_connections: 5
17      mod_http_upload:
18        access: org_account
19        put_url: https://@HOST@/xmpp/upload
20        docroot: /var/www/ejabberdupload
21        max_size: 1073741824
22        custom_headers:
23          "Access-Control-Allow-Origin": "https://@HOST@"
24          "Access-Control-Allow-Methods": "GET,HEAD,PUT,OPTIONS"
25          "Access-Control-Allow-Headers": "Content-Type"
26      mod_pubsub:
27        access_createnode: org_account
28        plugins:
29          - flat
30          - pep
31        force_node_config:
32          ## Evitar clientes com bugs a fazerem suas bookmarks públicas
33          storage:bookmarks:
34            access_model: whitelist
35  example.net:
36    modules:
37      mod_muc:
38        hosts:
39          - muc.example.net
40        access_create: net_account
41        access_persistent: net_account
42        access:
43          - allow
44        access_admin:
45          - allow: admin
46        default_room_options:
47          mam: false
48      mod_proxy65:
49        access: net_account
50        max_connections: 5
51      mod_http_upload:
52        access: net_account
53        put_url: https://@HOST@/xmpp/upload
54        docroot: /var/www/ejabberdupload
55        max_size: 1073741824
56        custom_headers:
57          "Access-Control-Allow-Origin": "https://@HOST@"
58          "Access-Control-Allow-Methods": "GET,HEAD,PUT,OPTIONS"
59          "Access-Control-Allow-Headers": "Content-Type"
60      mod_pubsub:
61        access_createnode: net_account
62        plugins:
63          - flat
64          - pep
65        force_node_config:
66          ## Evitar clientes com bugs a fazerem suas bookmarks públicas
67          storage:bookmarks:
68            access_model: whitelist

Como é mencionado acima, é possível desativar acesso a serviços específicos por virtualhost usando ACLs, em ordem para, por exemplo, prevenir contas em example.net de criar MUCs em muc.example.org.

Nesse caso, mude mod_stun_disco para isso, e não ative a opção listen para STUN/TURN. Gere um segredo de autenticação e compartilhe ele com a instância do servidor TURN.

1  mod_stun_disco:
2    secret: "auth_secret"
3    services:
4      -
5        host: turn.example.net
6        type: stun
7      -
8        host: turn.example.net
9        type: turn

Desde ejabberd 26.01 há um novo módulo mod_invites que permite você a criar tokens de convites, que você pode passar aos outros para que possam criar novas contas de maneira controlada.

Vamos analisar diferentes cenários de como configurar o seu sistema para utilizar essa nova função, da maneira que melhor lhe serve.

Apenas usuários administradores são permitidos, sem registração em banda (ibr) regular

1modules:
2  mod_invites: {}
3  mod_register:
4    allow_modules:
5      - mod_invites
Cuidado para não impor restrições adicionais em mod_register como ip_access.
1access_rules:
2  access_create_account:
3    allow: local
4#[...]
5modules:
6  mod_invites:
7    access_create_account: access_create_account
É altamente recomendado configurar uma landing page, pois ela vai melhorar, consideravelmente, a experiência do usuário. Caso contrário, você vai ter que garantir que um cliente compatível já está instalado e o sistema alvo consegue lidar com URIs XMPP.

A landing page integrada é baseada em bootstrap4 e jQuery, por causa das restrições de algumas distribuições Linux, nós não podemos enviar bibliotecas que já são incluídas pelo gerenciador de pacotes. Portanto, dependendo do seu método de instalação e a configuração do seu sistema, pode ser que precise instalar essas bibliotecas manualmente.

No Debian isso é tão fácil como

1sudo apt install libjs-jquery libjs-bootstrap4

Por conveniência, há um script incluído na distribuição fonte da ejabberd em tools/dl_invites_page_deps.sh que você usaria assim:

1./tools/dl_invites_page_deps.sh /usr/share/javascript

Confirme que você tem os direitos necessários para escrever a esse diretório.

Se você usa docker ou nossas imagens binárias, elas já podem estar incluídas.

O resto deste guia vai assumir que essas bibliotecas foram instaladas ao local acima.

Agora configure o manipulador http do ejabberd para servir a landing page e as bibliotecas.

 1listen:
 2  -
 3    port: 5281
 4    module: ejabberd_http
 5    request_handlers:
 6      /xmpp/invites: mod_invites
 7      /share: mod_http_fileserver
 8# [...]
 9modules:
10  mod_http_fileserver:
11    docroot: /usr/share/javascript
12  mod_invites:
13    landing_page: https://@HOST@/xmpp/invites/{{ invite.token }}
Você não precisa servir /share do manipulador http do ejabberd, você também pode configurar o seu servidor web preferido para fazer isso.

Se você prefere não servir a landing page incluída, você pode ainda configurar um serviço externo. Você pode ou hospedar o seu próprio serviço ou usar um existente, como o que nós oferecemos em https://invite.joinjabber.org.

Nesse caso você tem que configurar o parâmetro landing_page de acordo.

1modules:
2  mod_invites:
3    landing_page: https://invite.joinjabber.org/#{{ invite.uri|strip_protocol }}
Nenhum formulário de registração baseado na web estará disponível através de uma landing page externa. Contas terão que ser criadas usando registração em banda, a qual não é suportada por muitos clientes.
1sudo -u ejabberd ejabberdctl generate_invite example.net

Se você quiser sugerir um nome de usuário para essa conta, você pode fazer isso assim

1sudo -u ejabberd ejabberdctl generate_invite_with_username sponge_bob example.net

O resultado vai ser semelhante a isso (dependendo da sua configuração):

1xmpp:example.net?register;preauth=fvR20OkCyXyjZoOSybZh4ebx	https://example.net/xmpp/invites/fvR20OkCyXyjZoOSybZh4ebx

A primeira parte é um URI XMPP, a segunda é uma landing page (apenas presente se for configurada). Ela é a parte que você quer passar para os outros.

Primeiro você quer ter uma regra de acesso dedicada para access_create_account do mod_invite, e lá você adiciona a conta da pessoa abusiva.

1access_rules:
2  access_create_account:
3    deny:
4      - user: plankton@example.net
5    allow: local
6# [...]
7modules:
8  mod_invites:
9    access_create_account: access_create_account

Recarregue a configuração se for necessário.

1sudo -u ejabberdctl reload_config

Agora expire todos os convites enviados pela conta.

1sudo -u ejabberdctl expire_invite_tokens plankton example.net

Você pode limpar tokens usadas ou expiradas para disponibilizar espaço na sua base de dados. Mas esteja atento que esse procedimento remove todo o rastreamento ("quem convidou quem") e reseta os limites max_invites. Isso pode afetar a sua habilidade de identificar abusadores.

1sudo -u ejabberd ejabberdctl cleanup_expired_tokens example.net

Agora é a hora de espalhar a palavra! Oferecemos um guia que mostra como usar essa função para uma seleção de clientes XMPP populares.

Obviamente, essa lista não é exaustiva e se você tem perguntas ou uma ótima recomendação por gentileza nos contate aqui: servers@joinjabber.org (web chat) (xmpp)


  1. Originalmente adaptado de: blos.sm ↩︎

  2. Virtualhosts permitem que mais de um serviço XMPP seja executado em um servidor. Por exemplo, um serviço XMPP com o domínio example.net e outro serviço XMPP com o domínio example.org, ambos mais ou menos separados de um ao outro como se estivessem em servidores diferentes. ↩︎