Configuring Ejabberd + TLS + Let’s Encrypt

Intro

Hi everyone, in this tutorial i’m going to explain you how to setup a TLS secured Ejabberd server on your raspberry pi.

What is Ejabberd?

Ejabberd is a powerful open-source instant messaging server based on the XMPP (Extensible Messaging and Presence Protocol) standard.

Ejabberd is designed to handle a large number of concurrent users and is highly scalable, reliable, and secure. It supports a wide range of features, including group chats, message archiving, push notifications, and user authentication.

One of the key strengths of ejabberd is its modular architecture, which allows developers to add new features and extend its functionality easily. Additionally, ejabberd provides a web-based administration console that allows administrators to manage users, chat rooms, and other aspects of the server configuration.

Overall, ejabberd is an ideal choice for building real-time messaging and collaboration applications that require a robust and scalable backend infrastructure.

What is TLS Encryption?

Transport Layer Security (TLS) is a cryptographic protocol used to establish a secure and encrypted communication channel between two networked devices. In the case of ejabberd, TLS encryption can be used to secure the communication channel between the client devices (such as mobile devices, desktops, or other servers) and the ejabberd server.

When a client connects to an ejabberd server over an unencrypted connection, all the data exchanged between them can potentially be intercepted and read by a third party. This can be a major security risk, especially when the exchanged data includes sensitive information such as login credentials, private messages, or personal information.

By using TLS encryption, ejabberd can ensure that all the data exchanged between the client and the server is encrypted and can only be decrypted by the intended recipient. This helps to prevent eavesdropping, data tampering, and other security threats.

In addition to security, using TLS encryption can also help to improve the reliability and performance of the ejabberd service. Encrypted connections can help to prevent data loss or corruption due to network errors or malicious attacks, and can also help to reduce the risk of performance degradation caused by network congestion.

What is Let’s Encrypt?

When it comes to TLS encryption and ejabberd, Let’s Encrypt is a popular choice for obtaining digital certificates to enable secure communication over the XMPP protocol. Let’s Encrypt provides free digital certificates that are trusted by major web browsers, and can be used to secure the communication channel between the ejabberd server and client devices.

To enable HTTPS (HTTP Secure) on a website or service, including ejabberd, a digital certificate is required. Traditionally, obtaining and managing digital certificates has been a complex and expensive process, but Let’s Encrypt has made it easier and more accessible by providing free, automated certificate issuance and renewal.

In the case of ejabberd, Let’s Encrypt can be used to obtain a digital certificate that can be used to enable TLS encryption on the XMPP communication channel.

My scenario

to fully understand what i’m doing, you should understand before my setup scenario:
I did setup a raspberry in my LAN with the static IP 192.168.1.80, yet i didn’t want it to work only on my LAN, i wanted it to operate on the internet, thus allowing people to join my XMPP server freely.
How did i achieve that?

simple, with port forwarding

Port forwarding is a technique used to allow external devices to access services on a local network. It involves configuring a router or firewall to forward incoming network traffic from a specific port on the public IP address to a specific port on a device within the private network. This allows the device to receive and respond to incoming network requests from the internet. Port forwarding is commonly used to allow remote access to services such as web servers, email servers, and gaming servers hosted on a local network.

Last things i had to deal with were:

  1. Ejabberd doesn’t like IPs as hostnames. they require a Domain
  2. i Wanted people to easily access my raspbery without having to memorize an IP address that could change over time due to the lease time of the ISP.
  3. Certificates are associated to domains, not IP addresses

To deal with these “troubles” i decided to create a type A DNS record (xmpp.risingpirates.com) in my website (this) linking it to my public ip address.

This whole process is also called Self Hosting.

You will need

  • Raspberry Pi
  • Internet Connection
  • Domain
  • Access to your router configuration
  • Access to your Domain’s DNS settings

Setup Tutorial

1) Installing Ejabberd

to install ejabberd simply input these commands on the Raspberry pi’s Terminal

        # Update the package manager cache
        sudo apt-get update
        
        # Install ejabberd using the package manager
        sudo apt-get install ejabberd
        
        # Follow the prompts to complete the installation

        now that you’ve installed it, let’s move on to the next step.

        2) Generating certificates for our domain (or sub-domain)

        To to this we will need help of a good Friend, called certbot

        Certbot

        Certbot is a free and open-source client that automates the process of generating and renewing SSL/TLS certificates, offered by Let’s Encrypt. The software is designed to simplify the configuration of a secure website and provide secure encrypted connections via HTTPS.

        To install Certbot on a Raspberry Pi, you can follow these steps:

        sudo apt-get update
        sudo apt-get install certbot

        now that certbot is installed, let’s go on and setup our challenge.
        but first…

        What is a Certbot Challenge?

        A Certbot challenge is a process that Let’s Encrypt uses to verify that the person requesting the SSL certificate is the owner or has control over the domain name. Let’s Encrypt requires domain validation before issuing a certificate, and Certbot automates this process.

        There are several types of challenges that Certbot can use to verify domain ownership:

        1. HTTP-01 Challenge: This challenge involves placing a temporary file with a specific token in a specific location on the domain’s web server. The Let’s Encrypt server then checks that file to ensure the domain owner has control of the server.
        2. DNS-01 Challenge: This challenge involves adding a specific TXT record to the domain’s DNS zone file. Let’s Encrypt checks the DNS zone file to ensure the domain owner has control over the domain.
        3. TLS-ALPN-01 Challenge: This challenge uses the Application-Layer Protocol Negotiation (ALPN) extension in the TLS handshake to validate domain ownership. The Certbot client adds a specific extension to the TLS handshake, and the Let’s Encrypt server checks for it.

        since i had troubles with the HTTP-01, i tried the DNS-01 challenge, which by the way is the more popular and less “faulty”

        Challenge Setup

        To start the challenge we need to input the following command:

        sudo certbot certonly --manual --preferred-challenge=dns --email youremail@provider.com -d yourdomain

        Here’s a breakdown of the different parts of the command:

        • sudo: This command runs the Certbot command with administrator privileges.
        • certonly: This tells Certbot to obtain a certificate but not install it. This is useful if you want to manually configure your web server to use the certificate.
        • --manual: This option tells Certbot to use a manual verification process for domain ownership.
        • --preferred-challenge=dns: This option specifies that Certbot should use the DNS-01 challenge to verify domain ownership.
        • --email youremail@provider.com: This option specifies the email address to use for renewal reminders and security notices.
        • -d yourdomain: This specifies the domain name for which to request the SSL certificate. You can replace yourdomain with your own domain name.

        When you run this command, Certbot will ask you to add a specific TXT record to your domain’s DNS zone file. Once you’ve added the TXT record, Certbot will check your DNS zone file to ensure that you have control over the domain. Once domain ownership has been verified, Certbot will generate the SSL certificate and save it to a location on your server that you can specify.

        Certbot Keys

        When you use Certbot to request an SSL certificate, it generates two types of cryptographic keys: a private key and a public key.

        The private key is generated on your server and stored in a location specified during the Certbot request process. By default, Certbot stores private keys in the directory /etc/letsencrypt/live/yourdomain/privkey.pem (replacing yourdomain with your actual domain name).

        The public key is generated by Let’s Encrypt and is part of the SSL certificate that Certbot requests. The SSL certificate, which includes the public key, is also stored in a location specified during the Certbot request process. By default, Certbot stores SSL certificates in the directory /etc/letsencrypt/live/yourdomain/fullchain.pem (replacing yourdomain with your actual domain name).

        It’s important to keep the private key secure and protected, as it is used to decrypt SSL traffic sent to your server. The public key, on the other hand, can be freely shared with anyone who needs to communicate securely with your server.

        Generating a “Mashed up key”

        So, now you have private and public key. Ejabberd need only one file with both. To achieve this simply do this command:

        cat  /etc/letsencrypt/live/yourdomain/privkey.pem /etc/letsencrypt/live/yourdomain/fullchain.pem >> /etc/ejabberd/yourdomain.pem

        3) Configuring Ejabberd

        First thing first, let’s configure the package with the following command

        sudo dpkg-reconfigure ejabberd
        # Running this command will launch a configuration wizard that allows you to modify the # ejabberd configuration.

        After you’ve configured the basic settings, you should now configure the ejabberd.yml file located at /etc/ejabberd/ejabberd.yml

        run the following command:

        sudo nano /etc/ejabberd/ejabberd.yml

        once you’re into the ejabberd.yml file, this is the file you should be looking at:

        ###
        ###              ejabberd configuration file
        ###
        ### The parameters used in this configuration file are explained at
        ###
        ###       https://docs.ejabberd.im/admin/configuration
        ###
        ### The configuration file is written in YAML.
        ### *******************************************************
        ### *******           !!! WARNING !!!               *******
        ### *******     YAML IS INDENTATION SENSITIVE       *******
        ### ******* MAKE SURE YOU INDENT SECTIONS CORRECTLY *******
        ### *******************************************************
        ### Refer to http://en.wikipedia.org/wiki/YAML for the brief description.
        ###
        
        hosts:
          - localhost
        
        loglevel: info
        
        ## If you already have certificates, list them here
        # certfiles:
           - "/etc/ejabberd/ejabberd.pem"
        #  - /etc/letsencrypt/live/domain.tld/fullchain.pem
        #  - /etc/letsencrypt/live/domain.tld/privkey.pem
        
        listen:
          -
            port: 5222
            ip: "::"
            module: ejabberd_c2s
            max_stanza_size: 262144
            shaper: c2s_shaper
            access: c2s
            starttls_required: true
          -
            port: 5223
            ip: "::"
            tls: true
            module: ejabberd_c2s
            max_stanza_size: 262144
            shaper: c2s_shaper
            access: c2s
            starttls_required: true
          -
            port: 5269
            ip: "::"
            module: ejabberd_s2s_in
            max_stanza_size: 524288
          -
            port: 5443
            ip: "::"
            module: ejabberd_http
            tls: true
            request_handlers:
              /admin: ejabberd_web_admin
              /api: mod_http_api
              /bosh: mod_bosh
              /captcha: ejabberd_captcha
              /upload: mod_http_upload
              /ws: ejabberd_http_ws
          -
            port: 5280
            ip: "::"
            module: ejabberd_http
            request_handlers:
              /admin: ejabberd_web_admin
              /.well-known/acme-challenge: ejabberd_acme
          -
            port: 3478
            ip: "::"
            transport: udp
            module: ejabberd_stun
            use_turn: true
            ## The server's public IPv4 address:
            # turn_ipv4_address: "203.0.113.3"
            ## The server's public IPv6 address:
            # turn_ipv6_address: "2001:db8::3"
          -
            port: 1883
            ip: "::"
            module: mod_mqtt
            backlog: 1000
        
        s2s_use_starttls: optional
        
        acl:
          local:
            user_regexp: ""
          loopback:
            ip:
              - 127.0.0.0/8
              - ::1/128
        
        access_rules:
          local:
            allow: local
          c2s:
            deny: blocked
            allow: all
          announce:
            allow: admin
          configure:
            allow: admin
          muc_create:
            allow: local
          pubsub_createnode:
            allow: local
          trusted_network:
            allow: loopback
        
        api_permissions:
          "console commands":
            from:
              - ejabberd_ctl
            who: all
            what: "*"
          "admin access":
            who:
              access:
                allow:
                  - acl: loopback
                  - acl: admin
              oauth:
                scope: "ejabberd:admin"
                access:
                  allow:
                    - acl: loopback
                    - acl: admin
            what:
              - "*"
              - "!stop"
              - "!start"
          "public commands":
            who:
              ip: 127.0.0.1/8
            what:
              - status
              - connected_users_number
        
        shaper:
          normal:
            rate: 3000
            burst_size: 20000
          fast: 100000
        
        shaper_rules:
          max_user_sessions: 10
          max_user_offline_messages:
            5000: admin
            100: all
          c2s_shaper:
            none: admin
            normal: all
          s2s_shaper: fast
        
        modules:
          mod_adhoc: {}
          mod_admin_extra: {}
          mod_announce:
            access: announce
          mod_avatar: {}
          mod_blocking: {}
          mod_bosh: {}
          mod_caps: {}
          mod_carboncopy: {}
          mod_client_state: {}
          mod_configure: {}
          mod_disco: {}
          mod_fail2ban: {}
          mod_http_api: {}
          mod_http_upload:
            put_url: https://@HOST@:5443/upload
            custom_headers:
              "Access-Control-Allow-Origin": "https://@HOST@"
              "Access-Control-Allow-Methods": "GET,HEAD,PUT,OPTIONS"
              "Access-Control-Allow-Headers": "Content-Type"
          mod_last: {}
          mod_mam:
            ## Mnesia is limited to 2GB, better to use an SQL backend
            ## For small servers SQLite is a good fit and is very easy
            ## to configure. Uncomment this when you have SQL configured:
            ## db_type: sql
            assume_mam_usage: true
            default: always
          mod_mqtt: {}
          mod_muc:
            access:
              - allow
            access_admin:
              - allow: admin
            access_create: muc_create
            access_persistent: muc_create
            access_mam:
              - allow
            default_room_options:
              mam: true
          mod_muc_admin: {}
          mod_offline:
            access_max_user_messages: max_user_offline_messages
          mod_ping: {}
          mod_privacy: {}
          mod_private: {}
          mod_proxy65:
            access: local
            max_connections: 5
          mod_pubsub:
            access_createnode: pubsub_createnode
            plugins:
              - flat
              - pep
            force_node_config:
              ## Avoid buggy clients to make their bookmarks public
              storage:bookmarks:
                access_model: whitelist
          mod_push: {}
          mod_push_keepalive: {}
          mod_register:
            ## Only accept registration requests from the "trusted"
            ## network (see access_rules section above).
            ## Think twice before enabling registration from any
            ## address. See the Jabber SPAM Manifesto for details:
            ## https://github.com/ge0rg/jabber-spam-fighting-manifesto
            ip_access: trusted_network
          mod_roster:
            versioning: true
          mod_s2s_dialback: {}
          mod_shared_roster: {}
          mod_stream_mgmt:
            resend_on_timeout: if_offline
          mod_stun_disco: {}
          mod_vcard: {}
          mod_vcard_xupdate: {}
          mod_version:
            show_os: false
        
        ### Local Variables:
        ### mode: yaml
        ### End:
        ### vim: set filetype=yaml tabstop=8

        i know it does seem a complete mess, but here are the main sections of the file and what they’re used for

        • hosts: This section defines the virtual hosts that ejabberd will serve. You can define multiple virtual hosts in this section, each with its own configuration options.
        • loglevel: This section sets the verbosity level of the log files generated by ejabberd. There are six levels of verbosity: debug, info, warn, error, critical, and alert. The default level is info.
        • listen: This section defines the network interfaces and ports that ejabberd will listen on. You can define multiple listeners in this section, each with its own configuration options.
        • acl: This section defines the access control rules for the ejabberd server. You can define ACL rules based on IP addresses, domain names, or regular expressions.
        • auth_method: This section defines the authentication method that ejabberd will use to authenticate users. You can choose from a variety of authentication methods, such as internal authentication, LDAP, SQL, or OAuth.
        • modules: This section defines the ejabberd modules that will be loaded by the server. You can enable or disable modules by commenting or uncommenting the appropriate lines in this section.
        • shaper: This section defines the rate limiting rules for the ejabberd server. You can set limits on the number of connections, the number of messages, or the bandwidth usage.
        • s2s: This section defines the settings for server-to-server communication between ejabberd servers. You can define trusted domains, encryption options, and connection timeouts.
        • certfiles: This section defines the SSL/TLS certificates and keys that ejabberd will use for secure communication. You can specify the location of the certificate and key files, as well as the password for the key file.
        • c2s: This section defines the settings for client-to-server communication between ejabberd servers and XMPP clients. You can define encryption options, authentication methods, and connection timeouts.

        The ejabberd file is properly working as raw as it is, but if we try to connect to it at the 5222 port, mos of the clients will not consider our connection safe since he is still using his self-signed certificate

        What is a self-signed certificate

        A self-signed certificate is an SSL/TLS certificate that is signed by its own creator instead of a trusted third-party certificate authority (CA). Unlike a certificate issued by a trusted CA, a self-signed certificate is not automatically trusted by browsers or other client software.

        Self-signed certificates are often used for testing or internal purposes where the security requirements are not as strict. They can also be used in situations where it is not feasible or cost-effective to obtain a certificate from a trusted CA.

        However, because self-signed certificates are not signed by a trusted CA, users visiting a website secured with a self-signed certificate will typically receive a warning message from their browser indicating that the website’s identity cannot be verified. This warning can discourage users from accessing the website and may cause them to question its security. For this reason, self-signed certificates should be used with caution and only in appropriate situations.

        Giving ejabebrd our signed certificate

        Now, we do have our signed certificated at /etc/ejabberd/yourdomain.pem

        let’s modify the certificates section of the ejabberd.yml file this way

        certfiles:
          - /etc/ejabberd/yourdomain.pem

        File permissions

        now, the file is owned by root, we need to make it accessible to the ejabberd user

        sudo chown ejabberd yourdomain.pem

        finally, we need to allow only the owner to read and write the file, and all other users to read the file.

        sudo chmod 604 yourdomain.pem

        Restart

        now that everything is set up, you only need to restart the service

        sudo systemctl restart ejabberd.service

        4) Web management

        To access the web admin interface of ejabberd, you will need to access it through a web browser using the URL for your ejabberd server, followed by the port number and the /admin path. For example, if your ejabberd server is running on yourdomain.com and the web admin port is set to 5280, you would access the admin interface by navigating to https://yourdomain.com:5280/admin in your web browser.
        You will be prompted with a login popup, here you shall input the credentials you’ve set up at step 1.

        5) Conclusion

        In conclusion, setting up ejabberd with TLS encryption and Let’s Encrypt is an important step in ensuring secure and encrypted communication between users on your Jabber/XMPP server. With TLS encryption, all communication between clients and the server is encrypted, preventing unauthorized access and eavesdropping. Let’s Encrypt provides free SSL/TLS certificates that can be used to secure the server and enable HTTPS connections, which are essential for modern web browsers and applications.

        To set up ejabberd with TLS encryption and Let’s Encrypt, you first need to install ejabberd on your server and configure it to use the appropriate certificates and settings. You also need to obtain a Let’s Encrypt SSL/TLS certificate for your domain and configure it for use with ejabberd.

        While the process may seem daunting at first, following the steps outlined in this tutorial can help you secure your ejabberd server and enable encrypted and secure communication for your users. By taking the time to properly set up TLS encryption and Let’s Encrypt, you can create a safer and more secure environment for your users to communicate and collaborate.