Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save solus-hq/f70aabf19bd8abb19edaab2f44875a19 to your computer and use it in GitHub Desktop.
Save solus-hq/f70aabf19bd8abb19edaab2f44875a19 to your computer and use it in GitHub Desktop.
Steps for migrating Prosody server to Ejabberd on Debian 9

First redacted on early March 2018.

After some time with Prosody 0.10 on Debian 9, I wanted to test Ejabberd. You'll find below steps for doing such migration.

Steps

Packages installation

The most recent version can be found in Stretch's backports repository:

cat <<EOF | sudo tee /etc/apt/sources.list.d/backports.list
deb http://ftp.debian.org/debian stretch-backports main
EOF

Ensuring package is available:

$ apt update
$ apt-cache policy ejabberd
ejabberd:
  Installed: (none)
  Candidate: 16.09-4
  Version table:
     18.01-2~bpo9+1 100
        100 http://ftp.debian.org/debian stretch-backports/main amd64 Packages
     16.09-4 500
        500 http://mirrors.online.net/debian stretch/main amd64 Packages

and installation:

$ apt -t stretch-backports install ejabberd
$ apt install erlang-luerl  # for data migration

DNS entries

conference.example.com IN CNAME
echo.example.com IN CNAME
jabber.example.com IN CNAME
proxy.example.com IN CNAME
pubsub.example.com IN CNAME
share.example.com IN CNAME
status.example.com IN CNAME
example.com IN CNAME
www.example.com IN CNAME
xmpp.example.com IN A
xmpp.example.com IN AAAA
xmpps.example.com IN CNAME

_xmpp-client._tcp.example.com. 18000 IN SRV 0 5 5222 xmpp.example.com.
_xmpp-server._tcp.example.com. 18000 IN SRV 0 5 5269 xmpp.example.com.
_xmpp-server._tcp.conference.example.com. 18000 IN SRV 0 5 5269 xmpp.example.com.

Using Nginx as a reverse-proxy

Which will ends TLS connections:

server {
  listen 80;
  listen [::]:80;
  server_name example.com xmpp.example.com conference.example.com pubsub.example.com xmpps.example.com proxy.example.com status.example.com www.example.com echo.example.com;

  root /var/www/example.com/xmpp;
  index index.php index.html;

  location ^~ /.well-known/acme-challenge/ {
    alias /etc/letsencrypt/challenges/xmpp.example.com/;
    try_files $uri =404;
  }

  include snippets/security.conf;

  location / {
    return 301 https://$server_name$request_uri;
  }

  access_log /var/log/nginx/example.com/xmpp.access.log;
  error_log /var/log/nginx/example.com/xmpp.error.log;

  # DEBUG ONLY
  #rewrite_log on;
  #error_log /var/log/nginx/example.com/xmpp.error.log debug;
}

server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  server_name example.com xmpp.example.com conference.example.com pubsub.example.com xmpps.example.com proxy.example.com status.example.com www.example.com echo.example.com;

  root /var/www/example.com/xmpp/home;
  index index.php index.html;

  # ssl part
  include ssl.conf;
  ssl_certificate_key /etc/letsencrypt/private/xmpp.example.com.key;
  ssl_certificate /etc/letsencrypt/pem/xmpp.example.com.pem;

  location /admin {
    proxy_set_header Host $host;
    proxy_pass http://127.0.0.1:5280;
    proxy_set_header X-Forwarded-Port 443;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }

  access_log /var/log/nginx/example.com/xmpp.access.log;
  error_log /var/log/nginx/example.com/xmpp.error.log;
  # DEBUG ONLY
  #rewrite_log on;
  #error_log /var/log/nginx/example.com/xmpp.error.log debug;
}

Dedicated vhosts for http_upload :

server {
  listen 80;
  listen [::]:80;
  server_name share.example.com;

  root /var/www/example.com/share;
  index index.php index.html;

  location ^~ /.well-known/acme-challenge/ {
    alias /etc/letsencrypt/challenges/xmpp.example.com/;
    try_files $uri =404;
  }

  include snippets/security.conf;

  location / {
    return 301 https://share.example.com$request_uri;
  }

  access_log /var/log/nginx/example.com/share.access.log;
  error_log /var/log/nginx/example.com/share.error.log;

  # DEBUG ONLY
  #rewrite_log on;
  #error_log /var/log/nginx/example.com/share.error.log debug;
}

server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  server_name share.example.com ;

  root /var/www/example.com/share;
  index index.php index.html;

  # ssl part
  include ssl.conf;
  ssl_certificate_key /etc/letsencrypt/private/xmpp.example.com.key;
  ssl_certificate /etc/letsencrypt/pem/xmpp.example.com.pem;

  location / {
    proxy_set_header Host $host;
    proxy_pass http://localhost:5444;
    proxy_set_header X-Forwarded-Port 443;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }

  access_log /var/log/nginx/example.com/share.access.log;
  error_log /var/log/nginx/example.com/share.error.log;
}

ejabberd configuration

dhparams creation:

$ openssl dhparam -out /etc/ejabberd/dhparams.pem 2048
$ chown ejabberd: /etc/ejabberd/dhparams.pem

Let's copy the private key:

$ cp /etc/letsencrypt/private/xmpp.example.com.pem /etc/ejabberd
$ chown ejabberd: /etc/ejabberd/xmpp.example.com.pem
$ chmod 400 /etc/ejabberd/xmpp.example.com.pem
--- ejabberd.yml.bak	2018-03-12 13:14:31.444628397 +0100
+++ ejabberd.yml	2018-04-06 19:36:33.246492387 +0200
@@ -81,7 +81,8 @@
 ##   - "example.org"
 ##
 hosts:
-  - "localhost"
+  - "example.com"
+  - "example.org"

 ##
 ## route_subdomains: Delegate subdomains to other XMPP servers.
@@ -98,7 +99,10 @@
 ## automatically by ejabberd.
 ##
 certfiles:
-  - "/etc/ejabberd/ejabberd.pem"
+  - "/etc/ejabberd/xmpp.example.com.key"
+  - "/etc/ejabberd/xmpp.example.org.key"
+  - "/etc/letsencrypt/pem/xmpp.example.com.pem"
+  - "/etc/letsencrypt/pem/xmpp.example.org.pem"

 ## If your system provides only a single CA file (CentOS/FreeBSD):
 ## ca_file: "/etc/ssl/certs/ca-bundle.pem"
@@ -117,7 +121,7 @@
     - "no_tlsv1"
     - "cipher_server_preference"
     - "no_compression"
-  ## 'DH_FILE': "/path/to/dhparams.pem" # generated with: openssl dhparam -out dhparams.pem 2048
+  'DH_FILE': "/etc/ejabberd/dhparams.pem"

 ## c2s_dhfile: 'DH_FILE'
 ## s2s_dhfile: 'DH_FILE'
@@ -143,13 +147,27 @@
     max_stanza_size: 65536
     shaper: c2s_shaper
     access: c2s
+  ##
+  ## Direct-TLS for C2S (XEP-0368). A good practice is to forward
+  ## traffic from port 443 to this port, possibly multiplexing it
+  ## with HTTP using e.g. sslh [https://wiki.xmpp.org/web/Tech_pages/XEP-0368],
+  ## so modern clients can bypass restrictive firewalls (in airports, hotels, etc.).
+  ##
+  -
+    port: 5223
+    ip: "::"
+    module: ejabberd_c2s
+    tls: true
+    max_stanza_size: 65536
+    shaper: c2s_shaper
+    access: c2s
   -
     port: 5269
     ip: "::"
     module: ejabberd_s2s_in
   -
     port: 5280
-    ip: "::"
+    ip: "127.0.0.1"
     module: ejabberd_http
     request_handlers:
       "/ws": ejabberd_http_ws
@@ -157,9 +175,9 @@
       "/api": mod_http_api
     ##  "/pub/archive": mod_http_fileserver
     web_admin: true
-    ## register: true
-    ## captcha: true
-    tls: true
+    register: true
+    captcha: true
+    tls: false
     protocol_options: 'TLS_OPTIONS'

   ##
@@ -212,16 +230,16 @@
   ##
   ## To enable secure http upload
   ##
-  ## -
-  ##   port: 5444
-  ##   ip: "::"
-  ##   module: ejabberd_http
-  ##   request_handlers:
-  ##     "": mod_http_upload
-  ##   tls: true
-  ##   protocol_options: 'TLS_OPTIONS'
-  ##   dhfile: 'DH_FILE'
-  ##   ciphers: 'TLS_CIPHERS'
+  -
+    port: 5444
+    ip: "127.0.0.1"
+    module: ejabberd_http
+    request_handlers:
+      "": mod_http_upload
+    tls: false
+    protocol_options: 'TLS_OPTIONS'
+    dhfile: 'DH_FILE'
+    ciphers: 'TLS_CIPHERS'

 ## Disabling digest-md5 SASL authentication. digest-md5 requires plain-text
 ## password storage (see auth_password_format option).
@@ -436,8 +454,12 @@
   ##
   admin:
      user:
-       - ""
+       - "user1": "example.com"

+  shortname:
+    user_glob:
+      - "?"
+      - "??"
   ##
   ## Blocked users
   ##
@@ -533,7 +555,8 @@
   ## In-band registration allows registration of any possible username.
   ## To disable in-band registration, replace 'allow' with 'deny'.
   register:
-    - allow
+    - deny: shortname
+    - allow: all
   ## Only allow to register from localhost
   trusted_network:
     - allow: loopback
@@ -595,7 +618,7 @@

 ## By default the frequency of account registrations from the same IP
 ## is limited to 1 account every 10 minutes. To disable, specify: infinity
-## registration_timeout: 600
+registration_timeout: 3600

 ##
 ## Define specific Access Rules in a virtual host.
@@ -630,12 +653,13 @@
 ##
 ## Full path to a script that generates the image.
 ##
-## captcha_cmd: "/usr/share/ejabberd/captcha.sh"
+captcha_cmd: "/usr/share/ejabberd/captcha.sh"

 ##
 ## Host for the URL and port where ejabberd listens for CAPTCHA requests.
 ##
 ## captcha_host: "example.org:5280"
+captcha_host: "https://xmpp.example.com:443"

 ##
 ## Limit CAPTCHA calls per minute for JID/IP to avoid DoS.
@@ -691,22 +715,25 @@
   ## mod_delegation: {}   # for xep0356
   mod_disco: {}
   mod_echo: {}
-  mod_irc: {}
+  #mod_irc: {}
   mod_bosh: {}
   ## mod_http_fileserver:
   ##   docroot: "/var/www"
   ##   accesslog: "/var/log/ejabberd/access.log"
-  ## mod_http_upload:
-  ##   # docroot: "@HOME@/upload"
-  ##   put_url: "https://@HOST@:5444"
-  ##   thumbnail: false # otherwise needs the identify command from ImageMagick installed
+  mod_http_upload:
+    host: "share.@HOST@"
+    docroot: "@HOME@/upload"
+    put_url: "https://share.@HOST@"
+    thumbnail: false # otherwise needs the identify command from ImageMagick installed
+    max_size: 209715200 # 200 MiB
   ## mod_http_upload_quota:
   ##   max_days: 30
   mod_last: {}
   ## XEP-0313: Message Archive Management
   ## You might want to setup a SQL backend for MAM because the mnesia database is
   ## limited to 2GB which might be exceeded on large servers
-  ## mod_mam: {} # for xep0313, mnesia is limited to 2GB, better use an SQL backend
+  mod_mam: # for xep0313, mnesia is limited to 2GB, better use an SQL backend
+    default: always
   mod_muc:
     ## host: "conference.@HOST@"
     access:
@@ -715,6 +742,12 @@
       - allow: admin
     access_create: muc_create
     access_persistent: muc_create
+    max_user_conferences: 75
+    default_room_options:
+      mam: true
+      persistent: true
+      public: false
+      public_list: false
   mod_muc_admin: {}
   ## mod_muc_log: {}
   ## mod_multicast: {}
@@ -740,11 +773,11 @@
       - "pep"   # pep requires mod_caps
   mod_push: {}
   mod_push_keepalive: {}
-  ## mod_register:
+  mod_register:
   ##
   ## Protect In-Band account registrations with CAPTCHA.
   ##
-  ##   captcha_protected: true
+    captcha_protected: true
   ##
   ## Set the minimum informational entropy for passwords.
   ##
@@ -762,8 +795,8 @@
   ## When a user registers, send a notification to
   ## these XMPP accounts.
   ##
-  ##   registration_watchers:
-  ##     - "admin1@example.org"
+    registration_watchers:
+      - "user1@example.com"
   ##
   ## Only clients in the server machine can register accounts
   ##
@@ -773,6 +806,8 @@
   ##
   ##   access_from: deny
   ##   access: register
+    access: register
+    access_from: allow
   mod_roster:
     versioning: true
   mod_shared_roster: {}

Importing Prosody data

ejabberd user must be able to read Prosody data:

$ chmod 770 -R /var/lib/prosody/
$ chown root:ejabberd -R /var/lib/prosody/

$ ejabberdctl import_prosody /var/lib/prosody/

Differences

Prosody's module mod_mam, is enabling archive by default. On Ejabberd, it has to be explicitely configured:

  mod_mam:
    default: always
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment