Dovecot 2.3 to 2.4 update problems

Dovecot, which is a secure IMAP server, released version 2.4.0 on 24 January 2025 and a minor revision of 2.4.1 on 28 March 2025. As such, I recently decided to update my instances from the 2.3 branch (version 2.3.21.1 to be exact) to this new 2.4 branch. Though major revision updates can often be problematic, this one posed some additional challenges due to many backwards-incompatible changes. Though that linked upgrade documentation was helpful, I still ran into some problems with the update that I will explain in this post. Hopefully these tips will help others avoid some of the mistakes that I made.

My Dovecot IMAP configuration is rather simple, making some of the backwards-incompatible changes that applied to me easy enough to address:

  • Variable expansions (or so I thought; more on this one later)
  • Naming of userdb and passdb
    • These two directives now require a name, which can be the name of the lookup database or simply arbitrary
  • Arguments supplied to userdb and passdb separated into individual directives
    • Instead of having, say, passdb { args = username_format=%n $path_to_file }, the args are separated into:
      • passdb_driver = passwd-file
      • auth_username_format =
      • passwd_file_path = $path_to_file
  • Changes to the names of some directives (including SSL)
    • ssl_cert became ssl_server_cert_file
    • ssl_key became ssl_server_key_file
  • Separation of the mail_location directive into individual components
    • Instead of having mail_location = $mailbox_format:$mailbox_path (e.g. mail_location = maildir:/var/mail/), it is now:
      • mail_driver = $mailbox_format –> mail_driver = maildir
      • mail_path = $mailbox_path –> mail_path = /var/mail/
      • mail_home = $mailbox_home –> mail_home = /var/mail/home
  • Some new defaults for base settings
    • The base_dir now defaults to /var/run/dovecot, so it should be omitted and shouldn’t be changed
    • The listen directive now defaults to listen = *, ::, which will listen on all available IPv4 and IPv6 addresses
    • The disable_plaintext_auth directive was renamed to auth_allow_cleartext and now defaults to no for better security

I also took this upgrade window as an opportunity to shift all of my configuration from the included conf.d/ files to a single dovecot.conf file with all of my settings. Though I was able to make a copy of my Dovecot 2.3 configuration files that I could modify in preparation for the update to Dovecot 2.4, the new configuration didn’t work perfectly.

SSL errors when starting Dovecot

The first unexpected error I encountered was when trying to start Dovecot 2.4 with my new configuration. It refused to start, throwing an error message of ‘SSL certificates too long’. The problem here ended up being that certificates no longer need to be redirected into the directive. More simply put, the less-than sign (<) needed to be removed from the certificate lines:

In Dovecot 2.3:
ssl_cert = </etc/ssl/mail_server/fullchain.pem
ssl_key = </etc/ssl/mail_server/privkey.pem
In Dovecot 2.4
ssl_server_cert_file = /etc/ssl/mail_server/fullchain.pem
ssl_server_key_file = /etc/ssl/mail_server/privkey.pem
The important part here is that the ‘<‘ has been removed for each of the SSL server files (both cert and key).

Variable expansion not working as intended

With the documentation provided by the Dovecot team regarding changes to variables, I thought that the expansion would be a non-issue, but I was mistaken. After upgrading to Dovecot 2.4, I could no longer log in to any of my email addresses across multiple domains using any of my IMAP clients. Looking at the mail authentication logs, I found many error messages similar to this one:

Jul 03 00:57:06 [dovecot] auth(z@z-issue.com,$IP,sasl:login): passwd-file: missing passwd file: /var/mail/vhosts/%domain/shadow

This first error was a simple syntax mistake on my part where I accidentally omitted the needed curly braces around any variables. In particular, I referenced %domain instead of %{domain} in many directives, such as mail_home, mail_path, and for this exact error, the passwd_file_path line of passdb.

After correcting my mistake by adding the curly braces, I anticipated the problem would be resolved. However, I was still unable to log in using my IMAP clients. The error messages in the mail authentication logs did change, though, to ones like this:

Jul 03 01:14:52 [dovecot] auth(z@z-issue.com,$IP,sasl:cram-md5)<+ssPdf84tMAYz+f6>: Error: passwd-file: Failed to expand passwd-file path /var/mail/vhosts/%{domain}/shadow: domain: No value to get domain from

This error was more obtuse to me. The %{domain} variable should have been available based on the email address logging in. In this error message above, the email address (which is a fake example) of z@z-issue.com should have resulted in:

%{user} --> expanding to 'z'
%{domain} --> expanding to 'z-issue.com'

but it didn’t. Looking again at the Dovecot 2.4 upgrade documentation for variable expansion, I finally figured out what I needed to do. In the table under the ‘List of common short variables and their replacements‘, the row showing %d being replaced by %{user|domain} was confusing to me. I wrongly interpreted that syntax as the boolean “or” in Regular Expressions (RegEx), meaning that I can use %{user} as a variable containing the username portion of the email address, and %{domain} as a variable containing the domain portion of the email address.

My interpretation of that syntax was incorrect. The chart is showing the literal variable to use, and the pipe (or vertical bar) here is serving as a filter. That results in the variable expansion being:

Old variableNew syntaxExplanation
%d%{user|domain}Referencing the ‘user’ variable, extract only the ‘domain’ portion.
%n%{user|username}Referencing the ‘user’ variable, extract only the ‘username’ portion.

Now that I understood the proper syntax, I was able to update the relevant sections of my Dovecot auth directives:

mail_driver = maildir
mail_home = /var/mail/vhosts/%{user|domain}/%{user|username}/
mail_path = /var/mail/vhosts/%{user|domain}/%{user|username}/

userdb passwd-file {
        userdb_driver = passwd-file
        auth_username_format = %{user|username}
        passwd_file_path = /var/mail/vhosts/%{user|domain}/passwd
}

passdb passwd-file {
        passdb_driver = passwd-file
        auth_username_format = %{user|username}
        passwd_file_path = /var/mail/vhosts/%{user|domain}/shadow
}

After restarting Dovecot, I was able to connect via my IMAP clients once again.

Cheers,
Nathan Zachary

Gentoo Linux on the Framework 13 AMD 7840U with 2.8K display

Introduction

Until recently, I had been using a very old Dell laptop for my personal needs. However, when the motherboard started failing I decided it was time to look into options for replacing the laptop. I looked through many, many options from the “mainstream” manufacturers (e.g. Dell, Lenovo, Acer) and some of the lesser-known manufacturers who specialise in Linux (e.g. System76, Tuxedo Computers, Star Labs). Though I preferred the latter, neither they nor the mainstream manufacturers had options that met all of my goals. That’s when I remembered a relative new-comer to the laptop hardware industry: Framework.

Specifications

Checking their site, I found that the new Framework 13 met many of my needs:

  • AMD options (instead of Intel or NVIDIA)
  • Small form factor (13″)
  • Matte display with 2560×1440 resolution (or higher) and 90Hz (or higher)
  • UVC-supported webcam that wasn’t objectively awful
  • No components soldered onto the motherboard (meaning, all upgradeable)
    • Even better if it came bare-bones so that I could choose the components
  • A BIG bonus of the ports being expansion cards that are interchangeable
    • This allows the owner to install, say, 4 USB-C ports, or 2 of them with 2 HDMI ports for additional monitors, or any other combination needed at the time

So, I joined the pre-order list for the new Framework 13 with the following specs:

  • AMD Ryzen 7 7840U with AMD 780M integrated GPU
  • 13.5″ matte display at 2880×1920, 120Hz, and >500 nit brightness
  • Omnivision 9.2MP OVO8X sensor webcam (assembled by Chicony)

and “brought my own” additional components:

Configurations

Having gone through all that background information, I would like to document here some of the less-than-obvious configurations that I had to apply in order to get everything working nicely under Gentoo Linux. Though this guide focuses on Gentoo, much of the information is likely applicable to other Linux distributions.

This write-up isn’t meant to be an exhaustive list of Linux configurations for the Framework 13 laptop. There are some other great resources out there pertaining to getting this hardware working properly in Linux, including:

Now, onward to the configurations…

Firmware

AMD 780M iGPU

One of the more challenging parts to kernel configuration is the firmware blobs that are necessary for the AMD 780M iGPU (integrated graphics) that comes with the AMD Ryzen 7 7840U processor. Often with these chipsets, figuring out the firmware is a bit of trial-and-error by booting, checking dmesg to see which firmware blobs tried to load but couldn’t, adding them, and repeating until there are no further Failed to load firmware "$FIRMWARE_NAME.bin" error messages. Going through that process, I found the following list of firmware is needed:

dcn_3_1_4_dmcub.bin
gc_11_0_1_imu.bin
gc_11_0_1_me.bin
gc_11_0_1_mec.bin
gc_11_0_1_mes.bin
gc_11_0_1_mes1.bin
gc_11_0_1_mes_2.bin
gc_11_0_1_pfp.bin
gc_11_0_1_rlc.bin
psp_13_0_4_ta.bin
psp_13_0_4_toc.bin
sdma_6_0_1.bin
vcn_4_0_2.bin

I prefer to build the AMDGPU driver directly into the kernel instead of loading it as a module. As such, it’s necessary for me to list these firmware bin files directly via the kernel’s “Firmware loading facility”:

Device Drivers  --->
  Generic Driver Options --->
    Firmware loader  --->
      [*] Firmware loading facility 
      () 
      (/lib/firmware) Firmware blobs root directory

That results in this long single-line string being put into the “()” section of the kernel configuration:

amdgpu/dcn_3_1_4_dmcub.bin amdgpu/gc_11_0_1_imu.bin amdgpu/gc_11_0_1_me.bin amdgpu/gc_11_0_1_mec.bin amdgpu/gc_11_0_1_mes.bin amdgpu/gc_11_0_1_mes1.bin amdgpu/gc_11_0_1_mes_2.bin amdgpu/gc_11_0_1_pfp.bin amdgpu/gc_11_0_1_rlc.bin amdgpu/psp_13_0_4_ta.bin amdgpu/psp_13_0_4_toc.bin amdgpu/sdma_6_0_1.bin amdgpu/vcn_4_0_2.bin

If you don’t want to deal with that mess of building the firmware and driver directly into the kernel, you can always build the AMDGPU driver as a module and leave it out of your initramfs, so that it loads later in the boot process. It should then select the appropriate firmware blobs for you.

Intel AX210 WiFi

This generation of Framework 13 laptops (at least the AMD variants) ship with the AMD RZ616 WiFi chip, which is manufactured by MediaTek. This chipset has been known to have performance problems in Linux, and also requires at least a 6.5 kernel. Instead of dealing with those problems, I decided to replace it with an Intel AX210 WiFi chip.

As with the AMD iGPU mentioned above, the Intel AX210 WiFi chipset requires two firmware blobs be added to the kernel. In this case, the two needed ones are:

iwlwifi-ty-a0-gf-a0-89.ucode
iwlwifi-ty-a0-gf-a0.pnvm

and they can simply be appended to the “Firmware loading facility” line mentioned above.

Display

One of the reasons that I wanted the Framework 13 was this generation’s new display panel. I like that it’s a 13.5″ display with matte finish, 2880×1920 resolution, and 120Hz refresh rate. However, the colours were quite drab by default. By decoding the EDID for the panel, I found the actual model to be a BOE NE135A1M-NY1:

$ cat /sys/class/drm/card0-eDP-1/edid | edid-decode | grep -e 'Manufacturer' -e 'Display Product Name'
    Manufacturer: BOE
    Display Product Name: 'NE135A1M-NY1'

Knowing the panel manufacturer and model allowed me to get an Image Colour Management (ICM) file for the panel, which is essentially a colour profile for a more accurate calibration. I have uploaded the ICM file here for safekeeping (which you are free to download directly), but it was originally found on the NotebookCheck website.

In Linux, the method for applying a colour profile varies based on your Desktop Environment or Window Manager. For instance, KDE and GNOME both have colour management GUI applications available with easy ways of importing and managing profiles. I use the OpenBox Window Manager, so I would prefer to have a desktop-agnostic approach. The solution for me is a combination of colord and xiccd.

The colord application allows for importing the colour profile and assigning it to a particular device (i.e. a particular display panel), and then xiccd acts as a bridge between colord and Xorg. It is xiccd that will automatically apply the colour profile to the panel when starting Xorg, and subsequently, my OpenBox Window Manager session.

One “gotcha” is that xiccd must already be running before issuing these colormgr commands below. Start it beforehand in another terminal window.
## Get the Device ID of the display panel:
$ colormgr get-devices | grep 'Device ID'
Device ID:     xrandr-BOE-NE135A1M-NY1

## Copy the ICM file to the proper location and change the extension:
$ sudo mv $CURRENT_LOCATION/BOE0CB4.icm /usr/share/color/icc/colord/BOE0CB4.icc

## Import the colour profile into colormgr:
$ colormgr import-profile /usr/share/color/icc/colord/BOE0CB4.icc

## Find the Profile ID for the newly-imported colour profile:
$ colormgr get-profiles | grep -A1 'BOE0CB4.icc'
Filename:      /usr/share/color/icc/colord/BOE0CB4.icc
Profile ID:    icc-6cf5096a086792f1797bc4fa262bdfae

## Using the Device ID and the Profile ID, add the profile to the device:
## Syntax is:  colormgr device-add-profile $DEVICE_ID $PROFILE_ID$ colormgr device-add-profile xrandr-BOE-NE135A1M-NY1 icc-6cf5096a086792f1797bc4fa262bdfa
## Make that profile the default for the device:
## Syntax is:  colormgr device-make-profile-default $DEVICE_ID $PROFILE_ID
$ colormgr device-make-profile-default xrandr-BOE-NE135A1M-NY1 icc-6cf5096a086792f1797bc4fa262bdfae

## Confirm that the colour profile is applied to the device:
$ colormgr get-devices | grep -A2 'xrandr-BOE-NE135A1M-NY1'
Device ID:     xrandr-BOE-NE135A1M-NY1
Profile 1:     icc-6cf5096a086792f1797bc4fa262bdfae
               /usr/share/color/icc/colord/BOE0CB4.icc

As mentioned above, xiccd has to be running with the Window Manager session, so I choose to have it start automatically with OpenBox by adding xiccd & to ~/.config/openbox/autostart.

Keyboard bindings

As said, I use OpenBox as my Window Manager, so there isn’t a GUI application by default for adding or modifying the function keys. Instead, I mapped the keys to the actual functions that I wanted to perform. Here are my specific choices (with comments for the details of each binding):

    <!-- Keybinding for exiting Openbox with prompt with Alt+Esc -->
    <keybind key="A-Escape">
      <action name="Exit">
        <prompt>yes</prompt>
      </action>
    </keybind>
    <!-- Keybinding for showing the menu with left Windows key -->
    <keybind key="Super_L">
      <action name="ShowMenu">
        <menu>root-menu</menu>
      </action>
    </keybind>
    <!-- Keybinding for muting audio -->
    <keybind key="XF86AudioMute">
      <action name="Execute">
        <command>/usr/bin/amixer set Master toggle</command>
      </action>
    </keybind>
    <!-- Keybinding for lowering audio volume -->
    <keybind key="XF86AudioLowerVolume">
      <action name="Execute">
        <command>/usr/bin/amixer set Master 2%-</command>
      </action>
    </keybind>
    <!-- Keybinding for raising audio volume -->
    <keybind key="XF86AudioRaiseVolume">
      <action name="Execute">
        <command>/usr/bin/amixer set Master 2%+</command>
      </action>
    </keybind>
    <!-- Keybinding for audio previous track set in Audacious -->
    <!-- Keybinding for audio pause/play set in Audacious -->
    <!-- Keybinding for audio next track set in Audacious -->
    <!-- Keybinding for decreasing the brightness -->
    <keybind key="XF86MonBrightnessDown">
      <action name="Execute">
        <command>/usr/bin/xbacklight -dec 10</command>
      </action>
    </keybind>
    <!-- Keybinding for increasing the brightness -->
    <keybind key="XF86MonBrightnessUp">
      <action name="Execute">
        <command>/usr/bin/xbacklight -inc 10</command>
      </action>
    </keybind>

UGREEN USB-C ethernet adapter

Even though this particular adapter isn’t directly related to the Framework 13, I think it warrants a section here as I prefer it to the protrusive Framework Ethernet Expansion Card. The UGREEN USB-C gigabit ethernet adapter is based on the ASIX AX88179A chipset, which is supported directly in recent Linux kernels:

Device Drivers  --->
  Network Device Support --->
    USB Network Adapters --> 
      <*> Multipurpose USB Networking Framework
      <*>   ASIX AX88XXX Based USB 2.0 Ethernet Adapters
      <*>   ASIX AX88179/178A USB 3.0/2.0 to Gigabit Ethernet
      ...
      <*>   CDC NCM Support

The “gotcha” here, though, is that enabling the two ASIX AX88 drivers doesn’t automatically include the needed ‘CDC NCM Support’. For more information, see the following kernel bug 217204.

Conclusion

Hopefully this guide helped answer some questions about configuring the Framework 13’s hardware under Linux. As said, it wasn’t meant to be an exhaustive guide, but rather one focusing on some of the “gotchas” that I encountered when setting up mine with Gentoo Linux. If you run into any trouble, please feel free to comment and I will try to help.

OpenSSL 3 Dovecot error Failed to initialize SSL server context – dh key too small

Recently on one of my personal servers, I upgraded OpenSSL to 3.2.1 and everything seemed to go smoothly. However, I then noticed that though my Postfix MTA (Mail Transfer Agent) seemed to be working, I didn’t get any updates in my email client. That, to me, indicated a problem with my Dovecot MDA (Mail Delivery Agent).

Looking through the logs, I noticed the following error message repeated regularly:

Apr 04 01:50:55 [dovecot] imap-login: Error: Failed to initialize SSL server context: Can't load DH parameters (ssl_dh setting): error:0A00018A:SSL routines::dh key too small: user=<>, rip=REMOVED, lip=REMOVED, session=<l+Y27D4VaM2s3ZZS>
Apr 04 01:50:55 [dovecot] imap-login: Error: Failed to initialize SSL server context: Can't load DH parameters (ssl_dh setting): error:0A00018A:SSL routines::dh key too small: user=<>, rip=REMOVED, lip=REMOVED, session=<Hf827D4Vcs2s3ZZS>
Apr 04 01:50:57 [dovecot] imap-login: Error: Failed to initialize SSL server context: Can't load DH parameters (ssl_dh setting): error:0A00018A:SSL routines::dh key too small: user=<>, rip=REMOVED, lip=REMOVED, session=<HzBb7D4VfM2s3ZZS>
Apr 04 01:50:57 [dovecot] imap-login: Error: Failed to initialize SSL server context: Can't load DH parameters (ssl_dh setting): error:0A00018A:SSL routines::dh key too small: user=<>, rip=REMOVED, lip=REMOVED, session=<UElb7D4ViM2s3ZZS>
Apr 04 01:50:58 [dovecot] imap-login: Error: Failed to initialize SSL server context: Can't load DH parameters (ssl_dh setting): error:0A00018A:SSL routines::dh key too small: user=<>, rip=REMOVED, lip=REMOVED, session=<zilq7D4ViuOs3ZZS>
Apr 04 01:50:58 [dovecot] imap-login: Error: Failed to initialize SSL server context: Can't load DH parameters (ssl_dh setting): error:0A00018A:SSL routines::dh key too small: user=<>, rip=REMOVED, lip=REMOVED, session=<3EJq7D4VhOOs3ZZS>

The main error message is Failed to initialize SSL server context: Can't load DH parameters (ssl_dh setting) and the specific cause of the failure is dh key too small. Some additional details regarding the errors are:

  • rip –> Remote IP address (the email client residing on my workstation at home)
  • lip –> Local IP address (the mail server software residing on my personal server in the datacentre)
  • session –> a unique session ID provided by Dovecot for a particular client-to-server connection

Armed with this error message, I remembered that the aforementioned ssl_dh setting is handled in the /etc/dovecot/conf.d/10-ssl.conf file (at least in Gentoo Linux; the location may be different on other distributions). I looked at that file, and conveniently enough, there was a comment explaining exactly what needed to be done:

# grep -A5 'SSL DH parameters' /etc/dovecot/conf.d/10-ssl.conf 
# SSL DH parameters
# Generate new params with `openssl dhparam -out /etc/dovecot/dh.pem 4096`
# Or migrate from old ssl-parameters.dat file with the command dovecot
# gives on startup when ssl_dh is unset.
ssl_dh = </etc/dovecot/dh.pem

I made a backup copy of the current dh.pem, and then ran openssl dhparam -out /etc/dovecot/dh.pem 4096.

That openssl command can potentially take quite some time depending on the underlying hardware and level of generated entropy.

With the new 4096-bit certificate in place, I simply restarted Dovecot, and my mail stack worked correctly again. Ultimately, the problem was that my previous Dovecot dh.pem certificate was 2048-bit and that is no longer acceptable. For more information, see the Dovecot SSL page.