I recently upgraded two production iRedMail servers from version 1.7.4 to 1.8.2. The official documentation is excellent but assumes a perfect world. In reality, you’ll encounter:

  • PHP version mismatches (older OS versions)
  • File permission issues after upgrade
  • Roundcube 1.7’s new public_html/ directory structure
  • The dreaded “config file not readable” error
  • Symlink confusion

This guide documents exactly what worked on Rocky Linux 10.1, with fixes for every issue we encountered.

What You’ll Achieve

BeforeAfter
iRedMail 1.7.4iRedMail 1.8.2
Roundcube 1.6.15Roundcube 1.7.1
Old Nginx structureNew public_html/ structure
Mixed file ownershipClean root:root with nginx:nginx for logs/temp
PHP system() possibly enabledPHP system() securely disabled

Time required: 15-20 minutes
Risk level: Low (with proper backups)
Skill level: Intermediate


Prerequisites

Before starting, verify your environment:

# Check your OS version
cat /etc/rocky-release

# Check current iRedMail version
cat /etc/iredmail-release

# Check PHP version (Rocky Linux 10.1 comes with PHP 8.3+)
php -v

# Check web server
nginx -v

Important: This guide is written for Rocky Linux 10.1 (or AlmaLinux 10.1) which ships with PHP 8.3.29. If you’re on CentOS 7 or Rocky Linux 8, you’ll need additional PHP module commands which are noted throughout.


The Critical Warning You Must Read

⚠️ This Will Save You Hours of Debugging

  1. Never skip the intermediate version – You must upgrade to 1.8.0 before 1.8.2. The database schema changes require this path.
  2. Roundcube 1.7.x requires Nginx changes – The new public_html/ directory structure means your old Nginx configuration WILL break. Don’t skip this step.
  3. Backup before EVERY step – One wrong permission can break webmail. Backups are not optional.
  4. PHP system() must be temporarily enabled – The Roundcube upgrade script needs it, but re-disable it immediately after for security.
  5. Symlinks can be confusing – After upgrade, your directory may still be named roundcubemail-1.6.15 but contain 1.7.1 files. This is normal.

Step-by-Step Upgrade Process

Step 1: Create Complete Backups (2 minutes)

# Create a dated backup directory
BACKUP_DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p /root/backup_$BACKUP_DATE

# Backup Roundcube files
sudo cp -r /opt/www/roundcubemail "/root/backup_$BACKUP_DATE/"

# Backup Nginx templates
sudo cp /etc/nginx/templates/roundcube.tmpl "/root/backup_$BACKUP_DATE/" 2>/dev/null
sudo cp /etc/nginx/templates/roundcube-subdomain.tmpl "/root/backup_$BACKUP_DATE/" 2>/dev/null

# Backup iRedMail version file
sudo cp /etc/iredmail-release "/root/backup_$BACKUP_DATE/"

# Backup Roundcube database
sudo mysqldump -u root -p roundcubemail > "/root/backup_$BACKUP_DATE/roundcubemail_backup.sql"

# Backup PHP configuration
sudo cp /etc/php.ini "/root/backup_$BACKUP_DATE/"

echo "✅ Backups saved to /root/backup_$BACKUP_DATE"

Step 2: Check Current Roundcube Version

# Check your current version
head -5 /opt/www/roundcubemail/index.php | grep Version

Expected output: Version 1.6.15

Step 3: Update iRedMail to 1.8.0

echo "1.8.0" | sudo tee /etc/iredmail-release

Step 4: Upgrade Roundcube to 1.6.15 (if not already)

cd /root
wget https://github.com/roundcube/roundcubemail/releases/download/1.6.15/roundcubemail-1.6.15-complete.tar.gz
tar xzf roundcubemail-1.6.15-complete.tar.gz

# Enable system() temporarily
sudo sed -i 's/disable_functions =.*/disable_functions = exec,passthru,shell_exec,proc_open,popen/' /etc/php.ini
sudo systemctl restart php-fpm

cd roundcubemail-1.6.15
echo "y" | sudo ./bin/installto.sh /opt/www/roundcubemail

# Re-disable system()
sudo sed -i 's/disable_functions =.*/disable_functions = exec,passthru,shell_exec,system,proc_open,popen/' /etc/php.ini
sudo systemctl restart php-fpm

Step 5: Update Nginx Templates (CRITICAL)

This is the most skipped step and the most common cause of post-upgrade failures.

5.1 Edit the main Roundcube template

sudo nano /etc/nginx/templates/roundcube.tmpl

Replace the entire content with:

# Block direct access to directories and files.
location ~ ^/mail/(SQL|bin|config|installer|logs|temp|vendor)/ { deny all; }
location ~ ^/mail/(.*\.md|composer\.*|INSTALL|LICENSE|Makefile|UPGRADING)$ { deny all; }
location ~ ^/mail/plugins/.*/config.inc.php.* { deny all; }
location ~ ^/mail/plugins/enigma/home($|/.*) { deny all; }

# Block access via public_html/static.php
location ~ ^/mail/static.php/(SQL|bin|config|installer|logs|temp|vendor)/ { deny all; }
location ~ ^/mail/static.php/(.*\.md|composer\.*|INSTALL|LICENSE|Makefile|UPGRADING)$ { deny all; }
location ~ ^/mail/static.php/plugins/.*/config.inc.php.* { deny all; }
location ~ ^/mail/static.php/plugins/enigma/home($|/.*) { deny all; }

# Redirect /mail to /mail/
location = /mail {
    return 301 /mail/;
}

location = /mail/ {
    alias /opt/www/roundcubemail/public_html/;
    index index.php;
}

location ~ ^/mail/static.php/(.*) {
    include /etc/nginx/templates/hsts.tmpl;
    alias /opt/www/roundcubemail/$1;
}

location ~ ^/mail/(.*\.php)$ {
    include /etc/nginx/templates/hsts.tmpl;
    include /etc/nginx/templates/fastcgi_php.tmpl;
    fastcgi_param SCRIPT_FILENAME /opt/www/roundcubemail/public_html/$1;
}

5.2 Edit the subdomain template (if used)

sudo nano /etc/nginx/templates/roundcube-subdomain.tmpl

Replace with:

# Block direct access to directories and files.
location ~ ^/(SQL|bin|config|installer|logs|temp|vendor)/ { deny all; }
location ~ ^/(.*\.md|composer\.*|INSTALL|LICENSE|Makefile|UPGRADING)$ { deny all; }
location ~ ^/plugins/.*/config.inc.php.* { deny all; }
location ~ ^/plugins/enigma/home($|/.*) { deny all; }

# Block access via public_html/static.php
location ~ ^/static.php/(SQL|bin|config|installer|logs|temp|vendor)/ { deny all; }
location ~ ^/static.php/(.*\.md|composer\.*|INSTALL|LICENSE|Makefile|UPGRADING)$ { deny all; }
location ~ ^/static.php/plugins/.*/config.inc.php.* { deny all; }
location ~ ^/static.php/plugins/enigma/home($|/.*) { deny all; }

location / {
    root    /opt/www/roundcubemail/public_html;
    index   index.php index.html;
    include /etc/nginx/templates/hsts.tmpl;
}

location ~ ^/static.php/(.*) {
    include /etc/nginx/templates/hsts.tmpl;
    alias /opt/www/roundcubemail/$1;
}

location ~ ^/(.*\.php)$ {
    include /etc/nginx/templates/hsts.tmpl;
    include /etc/nginx/templates/fastcgi_php.tmpl;
    fastcgi_param SCRIPT_FILENAME /opt/www/roundcubemail/public_html/$1;
}

5.3 Test and reload Nginx

sudo nginx -t
sudo systemctl reload nginx

Step 6: Update iRedMail to 1.8.2

echo "1.8.2" | sudo tee /etc/iredmail-release

Step 7: Upgrade Roundcube to 1.7.1

cd /root
wget https://github.com/roundcube/roundcubemail/releases/download/1.7.1/roundcubemail-1.7.1-complete.tar.gz
tar xzf roundcubemail-1.7.1-complete.tar.gz

# Enable system() for the upgrade
sudo sed -i 's/disable_functions =.*/disable_functions = exec,passthru,shell_exec,proc_open,popen/' /etc/php.ini
sudo systemctl restart php-fpm

cd roundcubemail-1.7.1
echo "y" | sudo ./bin/installto.sh /opt/www/roundcubemail

# Re-disable system()
sudo sed -i 's/disable_functions =.*/disable_functions = exec,passthru,shell_exec,system,proc_open,popen/' /etc/php.ini
sudo systemctl restart php-fpm

Step 8: Fix Permissions (The Most Critical Step)

This step is often overlooked and causes the “Oops… something went wrong” error.

# Stop services temporarily
sudo systemctl stop nginx php-fpm

# Rename directory to match version (cleaner)
sudo mv /opt/www/roundcubemail-1.6.15 /opt/www/roundcubemail-1.7.1 2>/dev/null

# Fix symlink
sudo rm -f /opt/www/roundcubemail
sudo ln -s /opt/www/roundcubemail-1.7.1 /opt/www/roundcubemail

# Set ownership: root for application files
sudo chown -R root:root /opt/www/roundcubemail-1.7.1

# Set nginx ownership for writeable directories
sudo chown -R nginx:nginx /opt/www/roundcubemail-1.7.1/logs
sudo chown -R nginx:nginx /opt/www/roundcubemail-1.7.1/temp

# Set correct file permissions
sudo find /opt/www/roundcubemail-1.7.1 -type d -exec chmod 755 {} \;
sudo find /opt/www/roundcubemail-1.7.1 -type f -exec chmod 644 {} \;

# Reapply write permissions to logs/temp
sudo chmod 755 /opt/www/roundcubemail-1.7.1/logs
sudo chmod 755 /opt/www/roundcubemail-1.7.1/temp

# Ensure config is readable
sudo chmod 644 /opt/www/roundcubemail-1.7.1/config/config.inc.php

# Restart services
sudo systemctl start nginx php-fpm

Step 9: Verify the Upgrade

# Check versions
echo "iRedMail: $(cat /etc/iredmail-release)"
head -5 /opt/www/roundcubemail/index.php | grep Version

# Check symlink
ls -la /opt/www/roundcubemail

# Check critical permissions
ls -ld /opt/www/roundcubemail-1.7.1/logs
ls -ld /opt/www/roundcubemail-1.7.1/temp
sudo -u nginx cat /opt/www/roundcubemail/config/config.inc.php > /dev/null && echo "✅ Config readable by nginx"

# Check PHP security
php -r "echo function_exists('system') ? '⚠️ system() enabled' : '✅ system() disabled';"

Step 10: Test Webmail

  1. Clear your browser cache (Ctrl+Shift+Delete)
  2. Navigate to https://mail.yourdomain.com/mail/
  3. Log in with a test user
  4. Verify the footer shows Roundcube Webmail 1.7.1
  5. Send and receive a test email

Common Pitfalls & Solutions

Pitfall 1: “Oops… something went wrong!” after upgrade

Cause: Config file not readable by nginx

Solution:

sudo chmod 644 /opt/www/roundcubemail/config/config.inc.php
sudo systemctl restart php-fpm nginx

Pitfall 2: “Config file is not readable” warning in logs

Cause: Ownership changed during upgrade

Solution:

sudo chown -R root:root /opt/www/roundcubemail-1.7.1
sudo chown -R nginx:nginx /opt/www/roundcubemail-1.7.1/logs
sudo chown -R nginx:nginx /opt/www/roundcubemail-1.7.1/temp

Pitfall 3: Database connection error

Cause: Roundcube can’t read database credentials

Solution:

# Check config file permissions
ls -la /opt/www/roundcubemail/config/config.inc.php
# Should be -rw-r--r--

# Verify database credentials
grep -E "db_dsnw|db_user|db_pass" /opt/www/roundcubemail/config/config.inc.php

Pitfall 4: Nginx 404 or 403 errors

Cause: Old Nginx configuration still pointing to old directory structure

Solution: Verify Nginx templates were updated correctly (Step 5)

sudo nginx -t
sudo systemctl reload nginx

Pitfall 5: PHP system() still enabled after upgrade

Cause: The re-disable step was skipped

Solution:

sudo sed -i 's/disable_functions =.*/disable_functions = exec,passthru,shell_exec,system,proc_open,popen/' /etc/php.ini
sudo systemctl restart php-fpm

Pitfall 6: Symlink points to wrong directory

Cause: Directory wasn’t renamed

Solution:

sudo rm -f /opt/www/roundcubemail
sudo ln -s /opt/www/roundcubemail-1.7.1 /opt/www/roundcubemail

Verification Checklist

Copy this checklist and mark off each item as you complete it:

Pre-Upgrade

  • [ ] Full backups created (files + database)
  • [ ] Current iRedMail version verified (1.7.4)
  • [ ] Current Roundcube version noted
  • [ ] PHP version confirmed (8.3+ for Rocky Linux 10.1)

During Upgrade

  • [ ] iRedMail 1.8.0 update applied
  • [ ] Roundcube 1.6.15 upgrade completed
  • [ ] Nginx templates replaced with new content
  • [ ] nginx -t passes
  • [ ] iRedMail 1.8.2 update applied
  • [ ] Roundcube 1.7.1 upgrade completed

Post-Upgrade

  • [ ] PHP system() re-disabled
  • [ ] File ownership corrected (root:root with nginx:nginx for logs/temp)
  • [ ] Symlink updated correctly
  • [ ] Config file readable by nginx
  • [ ] Services restarted
  • [ ] Webmail accessible
  • [ ] Roundcube footer shows 1.7.1
  • [ ] Email send/receive works

FAQ

Q: Can I skip upgrading to 1.8.0 and go directly to 1.8.2?

A: No. The database schema changes in 1.8.0 are required before upgrading to 1.8.2. Skipping will cause database errors.

Q: Why does my directory still say roundcubemail-1.6.15 but webmail shows 1.7.1?

A: The installto.sh script upgrades files in place. The directory name doesn’t automatically change. You can rename it as shown in Step 8.

Q: I’m on CentOS 7. Will this guide work?

A: Partially. CentOS 7 has PHP 5.4, which is not compatible with Roundcube 1.7+. You’ll need to stick with Roundcube 1.5.2 as noted in the official iRedMail documentation.

Q: My webmail shows a white screen after upgrade. What do I do?

A: Check PHP-FPM:

sudo systemctl status php-fpm
sudo tail -50 /var/log/php-fpm/error.log
sudo tail -50 /opt/www/roundcubemail/logs/errors.log

Q: How long does this upgrade take?

A: 15-20 minutes for the actual upgrade, plus backup time.

Q: Will my users lose any data?

A: No. The upgrade preserves all emails, contacts, and settings. The database schema is updated, not replaced.

Q: Can I downgrade if something goes wrong?

A: Only from your backups. Never attempt to downgrade without restoring from backup.

Q: Do I need to upgrade iRedAdmin separately?

A: iRedAdmin is upgraded automatically when you upgrade iRedMail.


The Complete Upgrade Script

Save this as upgrade-iredmail.sh and run it on your server:

#!/bin/bash
# Complete iRedMail Upgrade Script 1.7.4 → 1.8.2
# For Rocky Linux 10.1 / AlmaLinux 10.1

set -e

# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

DOMAIN="mail.yourdomain.com"  # CHANGE THIS

echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN}iRedMail Upgrade Script v2.0${NC}"
echo -e "${GREEN}========================================${NC}"
echo -e "Domain: ${YELLOW}$DOMAIN${NC}"

# Backup
BACKUP_DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p /root/backup_$BACKUP_DATE
sudo cp -r /opt/www/roundcubemail "/root/backup_$BACKUP_DATE/"
sudo cp /etc/nginx/templates/roundcube.tmpl "/root/backup_$BACKUP_DATE/" 2>/dev/null
sudo mysqldump -u root -p roundcubemail > "/root/backup_$BACKUP_DATE/roundcubemail_backup.sql"
echo -e "${GREEN}✓ Backups saved${NC}"

# Update to 1.8.0
echo "1.8.0" | sudo tee /etc/iredmail-release

# Upgrade Roundcube to 1.6.15
cd /root
wget -q https://github.com/roundcube/roundcubemail/releases/download/1.6.15/roundcubemail-1.6.15-complete.tar.gz
tar xzf roundcubemail-1.6.15-complete.tar.gz
sudo sed -i 's/disable_functions =.*/disable_functions = exec,passthru,shell_exec,proc_open,popen/' /etc/php.ini
sudo systemctl restart php-fpm
cd roundcubemail-1.6.15
echo "y" | sudo ./bin/installto.sh /opt/www/roundcubemail
sudo sed -i 's/disable_functions =.*/disable_functions = exec,passthru,shell_exec,system,proc_open,popen/' /etc/php.ini
sudo systemctl restart php-fpm

# Update Nginx templates (full content here - see Step 5)

# Update to 1.8.2
echo "1.8.2" | sudo tee /etc/iredmail-release

# Upgrade Roundcube to 1.7.1
cd /root
wget -q https://github.com/roundcube/roundcubemail/releases/download/1.7.1/roundcubemail-1.7.1-complete.tar.gz
tar xzf roundcubemail-1.7.1-complete.tar.gz
sudo sed -i 's/disable_functions =.*/disable_functions = exec,passthru,shell_exec,proc_open,popen/' /etc/php.ini
sudo systemctl restart php-fpm
cd roundcubemail-1.7.1
echo "y" | sudo ./bin/installto.sh /opt/www/roundcubemail
sudo sed -i 's/disable_functions =.*/disable_functions = exec,passthru,shell_exec,system,proc_open,popen/' /etc/php.ini
sudo systemctl restart php-fpm

# Fix permissions
sudo systemctl stop nginx php-fpm
sudo mv /opt/www/roundcubemail-1.6.15 /opt/www/roundcubemail-1.7.1 2>/dev/null
sudo rm -f /opt/www/roundcubemail
sudo ln -s /opt/www/roundcubemail-1.7.1 /opt/www/roundcubemail
sudo chown -R root:root /opt/www/roundcubemail-1.7.1
sudo chown -R nginx:nginx /opt/www/roundcubemail-1.7.1/logs
sudo chown -R nginx:nginx /opt/www/roundcubemail-1.7.1/temp
sudo find /opt/www/roundcubemail-1.7.1 -type d -exec chmod 755 {} \;
sudo find /opt/www/roundcubemail-1.7.1 -type f -exec chmod 644 {} \;
sudo chmod 755 /opt/www/roundcubemail-1.7.1/logs
sudo chmod 755 /opt/www/roundcubemail-1.7.1/temp
sudo chmod 644 /opt/www/roundcubemail-1.7.1/config/config.inc.php
sudo systemctl start nginx php-fpm

# Restart all services
sudo systemctl restart nginx php-fpm postfix dovecot

echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN}Upgrade Complete!${NC}"
echo -e "${GREEN}========================================${NC}"
echo -e "iRedMail: $(cat /etc/iredmail-release)"
echo -e "Roundcube: $(head -5 /opt/www/roundcubemail/index.php | grep Version)"
echo -e "Backup: /root/backup_$BACKUP_DATE"

Conclusion

What You’ve Accomplished

BeforeAfter
iRedMail 1.7.4iRedMail 1.8.2
Roundcube 1.6.15Roundcube 1.7.1
Old Nginx structureModern public_html/ structure
Mixed file ownershipClean, secure permissions
Potential PHP security gapsPHP system() properly disabled

Key Takeaways

  1. Always backup first – This saved us multiple times
  2. Don’t skip the intermediate version – 1.8.0 is required before 1.8.2
  3. Update Nginx templates – Roundcube 1.7’s public_html/ structure requires it
  4. Fix permissions after upgrade – This is the #1 cause of “white screen” errors
  5. Re-disable PHP system() – Security matters

Real-World Testing

This guide was tested on:

  • ✅ Rocky Linux 10.1 (production mail server)
  • ✅ Two separate iRedMail installations
  • ✅ Multiple upgrade attempts (to document all edge cases)
  • ✅ Both IPv4 and IPv6 configurations

Support

If you found this guide helpful:

  • ⭐ Star this post
  • 📤 Share it with others
  • 💬 Leave a comment below

Need professional help with your iRedMail server? Contact us for consulting services.