Controlling fan speed for Dell PowerEdge servers

In my home lab I’m running a Dell PowerEdge T630.

While the T630 is a very powerful machine for a home lab, the fans are just as powerful. Personally I prefer quiet – and I’m not concerned if CPU throttling is occuring.

Today I wrote a script to make it easier to control the fan speed with ipmitool

In order to use this script with your PowerEdge – you will need to enable IPMI in iDRAC

#!/bin/bash

# Function to display usage
usage() {
    echo "Usage: $0 -h host [-l username] [-p password] [-p percentage]"
    echo "  -h host: IP address or hostname of the iDRAC (mandatory)"
    echo "  -l username: Username for IPMI authentication"
    echo "  -p password: Password for IPMI authentication"
    echo "  -p percentage: Percentage value (0-100) to set fan speed (default: 0)"
    exit 1
}

# Check if ipmitool is installed
if ! command -v ipmitool &> /dev/null
then
    echo "Error: ipmitool is not installed. Please install ipmitool to proceed."
    exit 1
fi

# Initialize variables
username=""
password=""
host=""
percentage="0"

# Parse command-line options
while getopts "h:l:p:" opt
do
    case $opt in
        h) host="$OPTARG" ;;
        l) username="$OPTARG" ;;
        p) 
            if [[ "$OPTARG" =~ ^[0-9]+$ && "$OPTARG" -ge 0 && "$OPTARG" -le 100 ]]
            then
                percentage="$OPTARG"
            else
                echo "Error: Percentage value must be an integer between 0 and 100."
                usage
            fi
            ;;
        \?) usage ;;
    esac
done

# Check if mandatory -h option is provided
if [[ -z ${host} ]]
then
    echo "Error: -h (host) option is mandatory."
    usage
fi

# Prompt for username if not provided via getopts
if [[ -z ${username} ]]
then
    echo -n "Enter username: "
    read username
fi

# Prompt for password if not provided via getopts
if [[ -z ${password} ]]
then
    echo -n "Enter password: "
    read -s password
fi

# Disable automatic fan speed control
ipmitool -I lanplus -H "${host}" -U "${username}" -P "${password}" raw 0x30 0x30 0x01 0x00

# Set fan speed based on percentage
if [[ -n ${percentage} ]]
then
    value=$(printf "%x\n" $((percentage * 64 / 100)))
    ipmitool -I lanplus -H "${host}" -U "${username}" -P "${password}" raw 0x30 0x30 0x02 0xff 0x${value}
fi

Migrating VMWare ESXi 7 virtual machines with EFI booting, to Proxmox 8.2 from VMDK files

Quick guide on how to migrate virtual machines from VMWare ESXi 7 to Proxmox 8.2. I’ve been using VMWare ESXi in my home lab and wanted to migrate this machine to Proxmox 8.2. The only mechanism available for this kind of migration was offline, as I did not have two physical machines to run both VMWare ESXi and Proxmox concurrently.

  1. Make a backup of the VMFS filesystem that contains your virtual machines
    Its an extra hurdle to read your VMFS filesystem within Linux, so I opted to use SCP to copy to my Windows machine

    Don’t skimp. Backup every file in this location
  2. Make sure you have an idea of the hardware configurations of each virtual machine as this process will require you to manually configure the hardware
  3. After installing Proxmox, copy your backup to the Proxmox filesystem
    In my case I used SCP to upload them from my Windows machine
  4. Create a virtual machine for your target vm to migrate
    Ensure you configure the hardware to the requirements
    Do not add a hard disk, delete the SCSI disk created by the wizard
    However – ensure you configure an EFI disk and disable Pre-Enrolled Keys (does anyone even use Secure Boot?)
  5. Exclude net as a boot option from the Options tab, for the virtual machine, in the Proxmox web UIThis image has an empty alt attribute; its file name is image-1.png

    This step seemed critial and undocumented. If I did not do this step, I was unable to boot the virtual machine
  6. SSH to Proxmox, identify the VMID with qm list and identify the location of your SCP
  7. Migrate the disk image with qm importdisk with the syntax
    qm importdisk VMID VMDK-FILE STORAGE-NAME

    Example:
    qm importdisk 200 /nvme/vmware/kube-master/kube-master.vmdk nvme
  8. Boot the virtual machine and open the console
  9. When you are dropped to the EFI shell, enter the command exit which should take you to the BIOS
  10. Follow the guide to add the path to your EFI boot file – https://pve.proxmox.com/wiki/OVMF/UEFI_Boot_Entries
  11. Reset the virtual machine – and it should boot just the same as it did on VMWare
    You may need to reconfigure the network and other hardware drivers and devices

systemd automatic restart on failure

I had an issue with apache web server recently where the service was crashing. A simple poor mans fix was to make use of systemd’s ability to automatically restart a failed service

At first I located the systemd unit file with systemctl status httpd

I then edited the file with vi /usr/lib/systemd/system/httpd.service

Under the [Service] block I then added the restart variables

[Service]

# Auto-restart
Restart=on-failure
RestartSec=5s

I then reloaded systemd with systemctl daemon-reload

Generate ppk files for all existing keys

Recently I did an automation task involving the automated generation of ppk files when ssh-keygen is run. I also wanted to generate ppk files for the existing keys on this machine.

The command I ended up using, to generate a ppk file for every /home/*/.ssh/id_rsa file was:

set -x;for user in $(find /home/*/.ssh -name id_rsa -type f);do puttygen ${user} --ppk-param version=2 -o ${user}.ppk;chown $(ls -l ${user} | awk '{print $3":"$4}') ${user}.ppk;chmod 600 ${user}.ppk;done;set +x

Replacing telnet with netcat

A stupid post it note for my own benefit mostly. My employer refuses to allow telnet on any of their machines, citing audit compliance and the pre-existance of netcat

So to test that a port is open with netcat you run:

nc -zv victim.host.com 8080

Setting the hostname on Oracle Cloud

I built out a number of images with Oracle Cloud using Oracle Linux 8. I was facing the trouble that due to the way I configured my instances, Oracle Cloud was not supplying a domain name via DHCP which caused my instances to return a short host name when I ran hostname -f. This in turn caused many scripts to fail, as they could not enumerate a FQDN.

So the answer was actually extremely simple:

echo 'DOMAIN="domain.com"' >> /etc/sysconfig/network
echo machine.domain.com > /etc/hostname
sed -i 's/PRESERVE_HOSTINFO=0/PRESERVE_HOSTINFO=2/g' /etc/oci-hostname.conf
reboot

Also ensure that the entry for the hostname in /etc/hosts references the FQDN first, and the shortname last, or else hostname -f will produce the shortname and not the FQDN

Add check_mk agent to 3CX Debian Phone System

I run a check_mk deployment and try to add everything to it. I recently deployed 3CX for a relative and wanted to include this on my check_mk monitoring.

  • SSH to the 3CX host, either as root or sudo -i after login
  • Execute the following commands
  • wget https://check_mk/agent/url/from/your/check_mk/deployment
  • dpkg -i check-mk-agent_2.0.0p17-1_all.deb
  • systemctl enable check_mk-async
  • systemctl start check_mk-async
  • vi /etc/nftables.conf
  • Add the following firewall rule, substituting 192.168.0.1 with the IP address of your check_mk master
table inet filter {
    chain input {
[..]
        # check_mk
        ip saddr { 192.168.0.1 } tcp dport { 6556 } counter accept comment "check_mk agent"
[..]
    }
}
  • Save the file with :wq!
  • reboot
  • Login to check_mk and add a new host with the 3CX supplied FQDN

ISPConfig on Oracle Linux 8 aarch64

This article is a modification of https://www.howtoforge.com/tutorial/perfect-server-centos-8-apache-mysql-php-pureftpd-postfix-dovecot-and-ispconfig/

1 Requirements

  • Oracle Linux 8 aarch64 – most likely on Oracle Cloud, possibly on Always Free tier

2 Preliminary Note

In this tutorial, I use the hostname server1.example.com with the IP address 192.168.0.100 and the gateway 192.168.0.1. These settings might differ for you, so you have to replace them where appropriate.

3 Prepare the server

ISPConfig ships with the Bastille firewall script that I will use as the firewall, therefor I disable the default CentOS firewall now. Of course, you are free to leave the CentOS firewall on and configure it to your needs (but then you shouldn’t use any other firewall later on as it will most probably interfere with the CentOS firewall).

Run…

dnf install net-tools wget rsyslog curl
systemctl stop firewalld.service
systemctl disable firewalld.service

to stop and disable the CentOS firewall. It is ok when you get errors here, this just indicates that the firewall was not installed.

Now I will install the network configuration editor:

dnf install wget yum-utils

Check your /etc/resolv.conf if it lists all nameservers that you’ve previously configured:

cat /etc/resolv.conf

If you do not have at least 3 lines, starting with nameserver, domain & search. You have a problem that must be resolved or many services will not function correctly.

Your box should have a FQDN (Fully Qualified Domain Name) when running

hostname -f

Set SELinux to permissive

SELinux is a security extension of CentOS that should provide extended security. ISPConfig does not ship with an SELinux rule set, therefore I set it to permissive (this is a must if you want to install ISPConfig later on).

Edit /etc/selinux/config and set SELINUX=permissive:

vi /etc/selinux/config
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#     enforcing - SELinux security policy is enforced.
#     permissive - SELinux prints warnings instead of enforcing.
#     disabled - No SELinux policy is loaded.
SELINUX=permissive
# SELINUXTYPE= can take one of these two values:
#     targeted - Targeted processes are protected,
#     mls - Multi Level Security protection.
SELINUXTYPE=targeted

Afterwards we must reboot the system:

reboot

4 Enable Additional Repositories and Install Some Software

Then we enable the EPEL repository on our Oracle Linux system as lots of the packages that we are going to install in the course of this tutorial are not available in the default Oracle Linux 8 repositories:

dnf install oracle-epel-release-el8
dnf config-manager --set-enabled ol8_developer_EPEL
dnf config-manager --set-enabled ol8_codeready_builder
dnf update

5 Quota

(If you have chosen a different partitioning scheme than I did, you must adjust this chapter so that quota applies to the partitions where you need it.)

To install quota, we run this command:

dnf install quota

Now we check if the quota is already enabled for the file system where the website (/var/www) and Maildir data (var/vmail) is stored. In this example setup, I have one big root partition, so I search for ‘ / ‘:

mount | grep ' / '
[root@server1 ~]# mount | grep ' / '
/dev/mapper/centos-root on / type xfs (rw,relatime,attr2,inode64,noquota)
[root@server1 ~]#

If you have a separate /var partition, then use:

mount | grep ' /var '

instead. If the line contains the word “noquota“, then proceed with the following steps to enable quota.

Enabling quota on the / (root) partition

Normally you would enable quota in the /etc/fstab file, but if the filesystem is the root filesystem “/”, then quota has to be enabled by a boot parameter of the Linux Kernel.

Edit the grub configuration file:

vi /etc/default/grub

Search for the line that starts with GRUB_CMDLINE_LINUX and add rootflags=uquota,gquota to the commandline parameters so that the resulting line looks like this:

GRUB_CMDLINE_LINUX="crashkernel=auto resume=/dev/mapper/cl-swap rd.lvm.lv=cl/root rd.lvm.lv=cl/swap rootflags=uquota,gquota"

and apply the changes by running the following command.

cp /boot/grub2/grub.cfg /boot/grub2/grub.cfg_bak # /boot/grub2/grub.cfg doesnt exist on Oracle Linux 8
grub2-mkconfig -o /boot/grub2/grub.cfg

and reboot the server.

reboot

Now check if quota is enabled:

mount | grep ' / '
[root@server1 ~]# mount | grep ' / '
/dev/mapper/centos-root on / type xfs (rw,relatime,attr2,inode64,usrquota,grpquota)
[root@server1 ~]#

When quota is active, we can see “usrquota,grpquota” in the mount option list.

Enabling quota on a separate /var partition

If you have a separate /var partition, then edit /etc/fstab and add ,uquota,gquota to the / partition (/dev/mapper/centos-var):

vi /etc/fstab

#
# /etc/fstab
# Created by anaconda on Sun Sep 21 16:33:45 2014
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/centos-root / xfs defaults 1 1
/dev/mapper/centos-var /var xfs defaults,uquota,gquota 1 2
UUID=9ac06939-7e43-4efd-957a-486775edd7b4 /boot xfs defaults 1 3
/dev/mapper/centos-swap swap swap defaults 0 0

Then run

mount -o remount /var
quotacheck -avugm
quotaon -avug

to enable quota. When you get an error that there is no partition with quota enabled, then reboot the server before you proceed.

6 Install Apache, PHP, MySQL and phpMyAdmin

We can install the needed packages with one single command:

dnf install httpd mod_ssl mariadb-server php php-mysqlnd php-mbstring

To ensure that the server cannot be attacked through the HTTPOXY vulnerability, we will disable the HTTP_PROXY header in apache globally. 

Add the apache header rule at the end of the httpd.conf file:

echo "RequestHeader unset Proxy early" >> /etc/httpd/conf/httpd.conf

And restart httpd to apply the configuration change.

service httpd restart

Install phpMyAdmin:

cd /tmp
wget https://files.phpmyadmin.net/phpMyAdmin/5.1.1/phpMyAdmin-5.1.1-english.tar.gz
tar xfz phpMyAdmin-5.1.1-english.tar.gz
mkdir /usr/share/phpmyadmin
mv phpMyAdmin-5.1.1-english/* /usr/share/phpmyadmin/
mkdir /usr/share/phpmyadmin/tmp
chown -R apache:apache /usr/share/phpmyadmin
chmod 777 /usr/share/phpmyadmin/tmp

Optional: Change the Apache MPM Module

CentOS 8 uses the Apache MPM Event module by default, this is good on one side, as it allows you to use HTTP/2 protocol. On the other hand, it does not allow you to use the apache mod_php module. In general, one should use PHP-FPM as default today and ISPConfig supports that. In case you need the old mod_php mode for compatibility reasons, then you can switch the Apache MPM like this:

vi /etc/httpd/conf.modules.d/00-mpm.conf

Add a # in front of the MPM event line so it looks like this:

# LoadModule mpm_event_module modules/mod_mpm_event.so

Then remove the # in from of the MPM Prefork line, so it looks like this:

LoadModule mpm_prefork_module modules/mod_mpm_prefork.so

Then restart httpd to apply the configuration change.

service httpd restart

7 Install Dovecot

Dovecot can be installed as follows:

dnf install dovecot dovecot-mysql dovecot-pigeonhole

Create an empty dovecot-sql.conf file and create symlinks:

touch /etc/dovecot/dovecot-sql.conf
ln -s /etc/dovecot/dovecot-sql.conf /etc/dovecot-sql.conf
ln -s /etc/dovecot/dovecot.conf /etc/dovecot.conf

Now create the system startup links and start Dovecot:

systemctl enable dovecot
systemctl start dovecot

8 Install Postfix

Postfix can be installed as follows:

dnf install postfix postfix-mysql

Next, open the TLS/SSL and submission ports in Postfix:

vi /etc/postfix/master.cf

Uncomment the submission and smtps sections as follows and add lines where necessary so that this section of the master.cf file looks exactly like the one below. IMPORTANT: Remove the # in front of the lines that start with smtps and submission too and not just from the -o lines after these lines!

[...]
submission inet n - n - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
# -o smtpd_reject_unlisted_recipient=no
# -o smtpd_client_restrictions=$mua_client_restrictions
# -o smtpd_helo_restrictions=$mua_helo_restrictions
# -o smtpd_sender_restrictions=$mua_sender_restrictions
# -o smtpd_recipient_restrictions=
# -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
# -o milter_macro_daemon_name=ORIGINATING
smtps inet n - n - - smtpd
-o syslog_name=postfix/smtps
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
# -o smtpd_reject_unlisted_recipient=no
# -o smtpd_client_restrictions=$mua_client_restrictions
# -o smtpd_helo_restrictions=$mua_helo_restrictions
# -o smtpd_sender_restrictions=$mua_sender_restrictions
# -o smtpd_recipient_restrictions=
# -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
# -o milter_macro_daemon_name=ORIGINATING
[...]

Then turn off Sendmail and start Postfix and MariaDB (MySQL):

systemctl enable mariadb.service
systemctl start mariadb.service
systemctl enable postfix.service
systemctl restart postfix.service

We disable sendmail to ensure that it does not get started in case it is installed on your server. So the error message “Failed to issue method call: Unit sendmail.service not loaded.” can be ignored.

9 Install Getmail

Getmail can be installed as follows:

dnf install python2
cd /tmp
wget http://pyropus.ca/software/getmail/old-versions/getmail-5.14.tar.gz
tar xvfz getmail-5.14.tar.gz
cd getmail-5.14
python2 setup.py build
python2 setup.py install

10 Set MySQL Passwords and Configure phpMyAdmin

Set passwords for the MySQL root account:

mysql_secure_installation
[root@server1 tmp]# mysql_secure_installation


NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB
SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY!
In order to log into MariaDB to secure it, we'll need the current
password for the root user. If you've just installed MariaDB, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.
Enter current password for root (enter for none):
OK, successfully used password, moving on...
Setting the root password ensures that nobody can log into the MariaDB
root user without the proper authorisation.

Set root password? [Y/n]
 <-- ENTER
New password: <-- yourrootsqlpassword
Re-enter new password: <-- yourrootsqlpassword
Password updated successfully!
Reloading privilege tables..
 ... Success!


By default, a MariaDB installation has an anonymous user, allowing anyone
to log into MariaDB without having to have a user account created for
them. This is intended only for testing, and to make the installation
go a bit smoother. You should remove them before moving into a
production environment.

Remove anonymous users? [Y/n]
 <-- ENTER
 ... Success!

Normally, root should only be allowed to connect from 'localhost'.  This
ensures that someone cannot guess at the root password from the network.

Disallow root login remotely? [Y/n]
 <-- ENTER
 ... Success!

By default, MariaDB comes with a database named 'test' that anyone can
access. This is also intended only for testing, and should be removed
before moving into a production environment.

Remove test database and access to it? [Y/n]
 <-- ENTER
 - Dropping test database...
 ... Success!
 - Removing privileges on test database...
 ... Success!

Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.

Reload privilege tables now? [Y/n]
 <-- ENTER
 ... Success!

Cleaning up...



All done! If you've completed all of the above steps, your MariaDB
installation should now be secure.

Thanks for using MariaDB!

[root@server1 tmp]#

Now we configure phpMyAdmin. Create this phpMyAdmin configuration file:

vi /etc/httpd/conf.d/phpmyadmin.conf

Add this content to the file:

# phpMyAdmin - Web based MySQL browser written in php
#
# Allows only localhost by default
#
# But allowing phpMyAdmin to anyone other than localhost should be considered
# dangerous unless properly secured by SSL

Alias /phpMyAdmin /usr/share/phpmyadmin
Alias /phpmyadmin /usr/share/phpmyadmin

<Directory /usr/share/phpmyadmin/>
   <IfModule mod_authz_core.c>
     # Apache 2.4
  #  <RequireAny>
     #  Require ip 127.0.0.1
     #  Require ip ::1
  #  </RequireAny>
   </IfModule>
   <IfModule !mod_authz_core.c>
     # Apache 2.2
     Order Deny,Allow
     Deny from All
     Allow from 127.0.0.1
     Allow from ::1
   </IfModule>
</Directory>

Next, we change the authentication in phpMyAdmin from cookie to http:

cp -pf /usr/share/phpmyadmin/config.sample.inc.php /usr/share/phpmyadmin/config.inc.php
vi /usr/share/phpmyadmin/config.inc.php
[...]
/* Authentication type */
$cfg['Servers'][$i]['auth_type'] = 'http';
[...]

Then we create the system startup links for Apache and start it:

systemctl enable httpd
systemctl restart httpd

Now you can direct your browser to http://server1.example.com/phpmyadmin/ or http://192.168.0.100/phpmyadmin/ and log in with the user name root and your new root MySQL password.

11 Install Amavisd-new, SpamAssassin, ClamAV, and Postgrey

To install amavisd-new, SpamAssassin and ClamAV, run the following command:

dnf install amavisd-new spamassassin clamav-server clamav-data clamav-update clamav-filesystem clamav clamav-scanner-systemd clamav-devel clamav-lib clamav-server-systemd unzip bzip2 perl-DBD-mysql postgrey re2c

Then we start freshclam, amavisd, and clamd.amavisd:

sa-update
freshclam
systemctl enable amavisd.service
systemctl start amavisd.service
systemctl start clamd@amavisd.service
systemctl enable postgrey.service
systemctl start postgrey.service

In the next step, we configure postgrey. Open the file /etc/sysconfig/postgrey in an editor:

vi /etc/sysconfig/postgrey

and change the line:

POSTGREY_TYPE="--unix=/var/spool/postfix/postgrey/socket"

to

POSTGREY_TYPE="--inet=10023"

Save the file and restart postgrey:

service postgrey restart

To configure amavisd, edit the file /etc/clamd.d/amavisd.conf:

vi /etc/clamd.d/amavisd.conf

and change the line:

LocalSocket /run/clamd.amavisd/clamd.sock

to

LocalSocket /var/spool/amavisd/clamd.sock

Save the changed configuration file and restart ClamAV:

systemctl restart clamd@amavisd.service

Now we have to create a system unit for the freshclam service. Create a new file /usr/lib/systemd/system/freshclam.service:

vi /usr/lib/systemd/system/freshclam.service

and enter the following content into that file:

[Unit]
Description = ClamAV Scanner
After = network.target

[Service]
Type = forking
# if you want to scan more than one in a day change the number 1 with your desired number in below line.
ExecStart = /usr/bin/freshclam -d -c 1
Restart = on-failure
PrivateTmp =true

[Install]
WantedBy=multi-user.target

Save the file and then enable and start the service.

systemctl enable freshclam.service
systemctl start freshclam.service
systemctl status freshclam.service

12 Installing Apache with mod_php, mod_fcgi/PHP, PHP-FPM

ISPConfig 3 allows you to use mod_php, mod_fcgi/PHP, cgi/PHP, and PHP-FPM on a per website basis.

We can install Apache2 with mod_php, mod_fcgid, and PHP as follows:

dnf install php php-devel php-gd php-ldap php-mysqlnd php-odbc php-pear php-xml php-xmlrpc php-pecl-apcu php-mbstring php-snmp php-soap curl curl-devel perl-libwww-perl ImageMagick libxml2 libxml2-devel mod_fcgid php-cli httpd-devel php-fpm php-intl php-json wget

Next, we open /etc/php.ini

vi /etc/php.ini

… and change the error reporting (so that notices aren’t shown any longer), set the timezone and uncomment cgi.fix_pathinfo=1:

[...]
;error_reporting = E_ALL & ~E_DEPRECATED
error_reporting = E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT
[...]
; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI.  PHP's
; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok
; what PATH_INFO is.  For more information on PAppp.tldTH_INFO, see the cgi specs.  Setting
; this to 1 will cause PHP CGI to fix its paths to conform to the spec.  A setting
; of zero causes PHP to behave as before.  Default is 1.  You should fix your scripts
; to use SCRIPT_FILENAME rather than PATH_TRANSLATED.
; http://www.php.net/manual/en/ini.core.php#ini.cgi.fix-pathinfo
cgi.fix_pathinfo=1
[...]
date.timezone = 'Europe/Berlin' [...]

Enable httpd and PHP-FPM to get started at boot time and start the PHP-FPM service.

systemctl enable php-fpm.service
systemctl start php-fpm.service
systemctl enable httpd.service

Finally, we restart Apache:

systemctl restart httpd.service

Now we will add support for Let’s encrypt. ISPConfig is using acme.sh now as Let’s Encrypt client. Install acme.sh using the following command:

dnf install socat
curl https://get.acme.sh | sh -s

13 Installation of mod_python

The Apache module mod_python is not available as RPM package, therefore we will compile it from source. The first step is to install the python development files and download the current mod_python version as .tar.gz file

dnf install python3-devel git flex redhat-rpm-config
cd /usr/local/src/
wget http://dist.modpython.org/dist/mod_python-3.5.0.tgz
tar xfz mod_python-3.5.0.tgz
cd mod_python-3.5.0

and then configure and compile the module.

./configure --with-python=/usr/bin/python3
make

There is an error in the compiled module that will cause the installation to fail with the error “version = “fatal: Not a git repository (or any of the parent directories): .git“. To fix that, run this sed command (the command is one line!).

sed -e 's/(git describe --always)/(git describe --always 2>\/dev\/null)/g' -e 's/`git describe --always`/`git describe --always 2>\/dev\/null`/g' -i $( find . -type f -name Makefile\* -o -name version.sh )

Then install the module with this command.

make install

and enable the module in Apache:

echo 'LoadModule python_module modules/mod_python.so' > /etc/httpd/conf.modules.d/10-python.conf
systemctl restart httpd.service

14 Install PureFTPd

PureFTPd can be installed with the following command:

dnf install pure-ftpd

Then create the system startup links and start PureFTPd:

systemctl enable pure-ftpd.service
systemctl start pure-ftpd.service

Now we configure PureFTPd to allow FTP and TLS sessions. FTP is a very insecure protocol because all passwords and all data are transferred in clear text. By using TLS, the whole communication can be encrypted, thus making FTP much more secure.

OpenSSL is needed by TLS; to install OpenSSL, we simply run:

dnf install openssl

Open /etc/pure-ftpd/pure-ftpd.conf

vi /etc/pure-ftpd/pure-ftpd.conf

If you want to allow FTP and TLS sessions, set TLS to 1 by removing the # in front of the TLS line. It is highly recommended to enable TLS.

[...]
# This option can accept three values :
# 0 : disable SSL/TLS encryption layer (default).
# 1 : accept both traditional and encrypted sessions.
# 2 : refuse connections that don't use SSL/TLS security mechanisms,
#     including anonymous sessions.
# Do _not_ uncomment this blindly. Be sure that :
# 1) Your server has been compiled with SSL/TLS support (--with-tls),
# 2) A valid certificate is in place,
# 3) Only compatible clients will log in.

TLS                      1
[...]

In order to use TLS, we must create an SSL certificate. I create it in /etc/ssl/private/, therefore I create that directory first:

mkdir -p /etc/ssl/private/

Afterward, we can generate the SSL certificate as follows:

openssl req -x509 -nodes -days 7300 -newkey rsa:2048 -keyout /etc/ssl/private/pure-ftpd.pem -out /etc/ssl/private/pure-ftpd.pem

Country Name (2 letter code) [XX]: <– Enter your Country Name (e.g., “DE”).
State or Province Name (full name) []:
<– Enter your State or Province Name.
Locality Name (eg, city) [Default City]:
<– Enter your City.
Organization Name (eg, company) [Default Company Ltd]:
<– Enter your Organization Name (e.g., the name of your company).
Organizational Unit Name (eg, section) []:
<– Enter your Organizational Unit Name (e.g. “IT Department”).
Common Name (eg, your name or your server’s hostname) []:
<– Enter the Fully Qualified Domain Name of the system (e.g. “server1.example.com”).
Email Address []:
<– Enter your Email Address.

Change the permissions of the SSL certificate:

chmod 600 /etc/ssl/private/pure-ftpd.pem

Create a DHParam file:

openssl dhparam -out /etc/ssl/private/pure-ftpd-dhparams.pem 2048

Finally, restart PureFTPd:

systemctl restart pure-ftpd.service

That’s it. You can now try to connect using your FTP client; however, you should configure your FTP client to use TLS.

15 Install BIND

We can install BIND as follows:

dnf install bind bind-utils haveged

Make a backup of the existing /etc/named.conf file and create a new one as follows:

cp /etc/named.conf /etc/named.conf_bak
cat /dev/null > /etc/named.conf
vi /etc/named.conf
//
// named.conf
//
// Provided by Red Hat bind package to configure the ISC BIND named(8) DNS
// server as a caching only nameserver (as a localhost DNS resolver only).
//
// See /usr/share/doc/bind*/sample/ for example named configuration files.
//
options {
        listen-on port 53 { any; };
        listen-on-v6 port 53 { any; };
        directory       "/var/named";
        dump-file       "/var/named/data/cache_dump.db";
        statistics-file "/var/named/data/named_stats.txt";
        memstatistics-file "/var/named/data/named_mem_stats.txt";
        allow-query     { any; };
				allow-recursion {"none";};
        recursion no;
};
logging {
        channel default_debug {
                file "data/named.run";
                severity dynamic;
        };
};
zone "." IN {
        type hint;
        file "named.ca";
};
include "/etc/named.conf.local";

Create the file /etc/named.conf.local that is included at the end of /etc/named.conf (/etc/named.conf.local will later on get populated by ISPConfig if you create DNS zones in ISPConfig):

touch /etc/named.conf.local

Then we create the startup links and start BIND:

systemctl enable named.service
systemctl start named.service
systemctl enable haveged.service
systemctl start haveged.service

16 Install AWStats

AWStats can be installed as follows:

dnf install awstats perl-DateTime-Format-HTTP perl-DateTime-Format-Builder

The alternative web statistics application ‘webalizer’ is not available for CentOS 8 anymore, so you will only be able to use AWStats.

17 Install Jailkit

Jailkit is used to chroot SSH users and cronjobs. It can be installed as follows:

ln -s /usr/bin/python2 /usr/bin/python
cd /tmp
wget http://olivier.sessink.nl/jailkit/jailkit-2.21.tar.gz
tar xvfz jailkit-2.21.tar.gz
cd jailkit-2.21
./configure
make
make install
cd ..
rm -rf jailkit-2.21*

18 Install Fail2Ban

This is optional but recommended, because the ISPConfig monitor tries to show the log.

dnf install iptables-services fail2ban fail2ban-systemd
systemctl stop firewalld.service
systemctl mask firewalld.service
systemctl disable firewalld.service

Next we create the /etc/fail2ban/jail.local file and enable monitoring for ssh, email and ftp service.

vi /etc/fail2ban/jail.local

Add the following content to the jail.local file:

[sshd]
enabled = true
action = iptables[name=sshd, port=ssh, protocol=tcp]

[pure-ftpd]
enabled = true
action = iptables[name=FTP, port=ftp, protocol=tcp]
maxretry = 3

[dovecot]
enabled = true
action = iptables-multiport[name=dovecot, port="pop3,pop3s,imap,imaps", protocol=tcp]
maxretry = 5

[postfix-sasl]
enabled = true
action = iptables-multiport[name=postfix-sasl, port="smtp,smtps,submission", protocol=tcp]
maxretry = 3

Then create the system startup links for fail2ban and start it:

systemctl enable fail2ban.service
systemctl start fail2ban.service

19 Install rkhunter

rkhunter can be installed as follows:

dnf install rkhunter

20 Install Mailman

If you like to manage mailing lists with Mailman on your server, then install mailman now. Mailman is supported by ISPConfig, so you will be able to create new mailing lists trough ISPConfig later.

dnf install mailman

Before we can start Mailman, a first mailing list called mailman must be created:

touch /var/lib/mailman/data/aliases
postmap /var/lib/mailman/data/aliases
/usr/lib/mailman/bin/newlist mailman
ln -s /usr/lib/mailman/mail/mailman /usr/bin/mailman

[root@server1 tmp]# /usr/lib/mailman/bin/newlist mailman
Enter the email of the person running the list:
 <– admin email address, e.g. listadmin@example.com
Initial mailman password: <– admin password for the mailman list
To finish creating your mailing list, you must edit your /etc/aliases (or
equivalent) file by adding the following lines, and possibly running the
`newaliases’ program:

## mailman mailing list
mailman:              “|/usr/lib/mailman/mail/mailman post mailman”
mailman-admin:        “|/usr/lib/mailman/mail/mailman admin mailman”
mailman-bounces:      “|/usr/lib/mailman/mail/mailman bounces mailman”
mailman-confirm:      “|/usr/lib/mailman/mail/mailman confirm mailman”
mailman-join:         “|/usr/lib/mailman/mail/mailman join mailman”
mailman-leave:        “|/usr/lib/mailman/mail/mailman leave mailman”
mailman-owner:        “|/usr/lib/mailman/mail/mailman owner mailman”
mailman-request:      “|/usr/lib/mailman/mail/mailman request mailman”
mailman-subscribe:    “|/usr/lib/mailman/mail/mailman subscribe mailman”
mailman-unsubscribe:  “|/usr/lib/mailman/mail/mailman unsubscribe mailman”

Hit enter to notify mailman owner…
 <– ENTER

[root@server1 tmp]#

Open /etc/aliases afterwards…

vi /etc/aliases

… and add the following lines:

[...]
mailman:              "|/usr/lib/mailman/mail/mailman post mailman"
mailman-admin:        "|/usr/lib/mailman/mail/mailman admin mailman"
mailman-bounces:      "|/usr/lib/mailman/mail/mailman bounces mailman"
mailman-confirm:      "|/usr/lib/mailman/mail/mailman confirm mailman"
mailman-join:         "|/usr/lib/mailman/mail/mailman join mailman"
mailman-leave:        "|/usr/lib/mailman/mail/mailman leave mailman"
mailman-owner:        "|/usr/lib/mailman/mail/mailman owner mailman"
mailman-request:      "|/usr/lib/mailman/mail/mailman request mailman"
mailman-subscribe:    "|/usr/lib/mailman/mail/mailman subscribe mailman"
mailman-unsubscribe:  "|/usr/lib/mailman/mail/mailman unsubscribe mailman"

Run

newaliases

afterwards and restart Postfix:

systemctl restart postfix.service

Now open the Mailman Apache configuration file /etc/httpd/conf.d/mailman.conf

vi /etc/httpd/conf.d/mailman.conf

… and add the line ScriptAlias /cgi-bin/mailman/ /usr/lib/mailman/cgi-bin/. Comment out Alias /pipermail/ /var/lib/mailman/archives/public/ and add the line Alias /pipermail /var/lib/mailman/archives/public/:

#
#  httpd configuration settings for use with mailman.
#

ScriptAlias /mailman/ /usr/lib/mailman/cgi-bin/
ScriptAlias /cgi-bin/mailman/ /usr/lib/mailman/cgi-bin/
<Directory /usr/lib/mailman/cgi-bin/>
    AllowOverride None
    Options ExecCGI
    Order allow,deny
    Allow from all
</Directory>


#Alias /pipermail/ /var/lib/mailman/archives/public/
Alias /pipermail /var/lib/mailman/archives/public/
<Directory /var/lib/mailman/archives/public>
    Options Indexes MultiViews FollowSymLinks
    AllowOverride None
    Order allow,deny
    Allow from all
    AddDefaultCharset Off
</Directory>

# Uncomment the following line, to redirect queries to /mailman to the
# listinfo page (recommended).

# RedirectMatch ^/mailman[/]*$ /mailman/listinfo

Restart Apache:

systemctl restart httpd.service

Create the system startup links for Mailman and start it:

systemctl enable mailman.service
systemctl start mailman.service

After you have installed ISPConfig 3, you can access Mailman as follows:

You can use the alias /cgi-bin/mailman for all Apache vhosts (please note that suExec and CGI must be disabled for all vhosts from which you want to access Mailman!), which means you can access the Mailman admin interface for a list at http://<vhost>/cgi-bin/mailman/admin/<listname>, and the web page for users of a mailing list can be found at http://<vhost>/cgi-bin/mailman/listinfo/<listname>.

Under http://<vhost>/pipermail/<listname> you can find the mailing list archives.

21 Install Roundcube webmail

To install the RoundCube webmail client, download the latest version with wget to the /tmp folder:

cd /tmp
wget https://github.com/roundcube/roundcubemail/releases/download/1.5.1/roundcubemail-1.5.1-complete.tar.gz

Unpack the tar.gz archive and move the RoundCube source to /usr/share/roundcubemail

tar xfz roundcubemail-1.5.1-complete.tar.gz
mkdir /usr/share/roundcubemail
mv /tmp/roundcubemail-1.5.1/* /usr/share/roundcubemail/
chown apache /usr/share/roundcubemail/temp
chown apache /usr/share/roundcubemail/logs

Create a roundcubemail.conf configuration file with nano editor:

vi /etc/httpd/conf.d/roundcubemail.conf

And add the following content to that file:

#
# Round Cube Webmail is a browser-based multilingual IMAP client
#

Alias /roundcubemail /usr/share/roundcubemail
Alias /webmail /usr/share/roundcubemail # Define who can access the Webmail # You can enlarge permissions once configured <Directory /usr/share/roundcubemail/> Options none AllowOverride Limit Require all granted </Directory> # Define who can access the installer # keep this secured once configured <Directory /usr/share/roundcubemail/installer> Options none AllowOverride Limit Require all granted </Directory> # Those directories should not be viewed by Web clients. <Directory /usr/share/roundcubemail/bin/> Order Allow,Deny Deny from all </Directory> <Directory /usr/share/roundcubemail/plugins/enigma/home/> Order Allow,Deny Deny from all </Directory>

Restart Apache:

systemctl restart httpd.service

Now we need a database for RoundCube mail, we will initialize it as follows:

mysql -u root -p

At MariaDB prompt use:

CREATE DATABASE roundcubedb;
CREATE USER roundcubeuser@localhost IDENTIFIED BY 'roundcubepassword';
GRANT ALL PRIVILEGES on roundcubedb.* to roundcubeuser@localhost ;
FLUSH PRIVILEGES;
exit

I am using the details for the RoundCube database as an example, please replace the values as per your choice for security reasons.

Now we will install RoundCube in the browser at http://192.168.0.100/roundcubemail/installer

Now create the config.inc.php file:

vi /usr/share/roundcubemail/config/config.inc.php
<?php

/* Local configuration for Roundcube Webmail */

// ----------------------------------
// SQL DATABASE
// ----------------------------------
// Database connection string (DSN) for read+write operations
// Format (compatible with PEAR MDB2): db_provider://user:password@host/database
// Currently supported db_providers: mysql, pgsql, sqlite, mssql, sqlsrv, oracle
// For examples see http://pear.php.net/manual/en/package.database.mdb2.intro-dsn.php
// NOTE: for SQLite use absolute path (Linux): 'sqlite:////full/path/to/sqlite.db?mode=0646'
// or (Windows): 'sqlite:///C:/full/path/to/sqlite.db'
$config['db_dsnw'] = 'mysql://roundcubeuser:roundcubepassword@localhost/roundcubedb';

// ----------------------------------
// IMAP
// ----------------------------------
// The IMAP host chosen to perform the log-in.
// Leave blank to show a textbox at login, give a list of hosts
// to display a pulldown menu or set one host as string.
// To use SSL/TLS connection, enter hostname with prefix ssl:// or tls://
// Supported replacement variables:
// %n - hostname ($_SERVER['SERVER_NAME'])
// %t - hostname without the first part
// %d - domain (http hostname $_SERVER['HTTP_HOST'] without the first part)
// %s - domain name after the '@' from e-mail address provided at login screen
// For example %n = mail.domain.tld, %t = domain.tld
// WARNING: After hostname change update of mail_host column in users table is
// required to match old user data records with the new host.
$config['default_host'] = 'localhost';
$config['smtp_server'] = 'localhost';
$config['smtp_port'] = 25;

// provide an URL where a user can get support for this Roundcube installation
// PLEASE DO NOT LINK TO THE ROUNDCUBE.NET WEBSITE HERE!
$config['support_url'] = '';

// This key is used for encrypting purposes, like storing of imap password
// in the session. For historical reasons it's called DES_key, but it's used
// with any configured cipher_method (see below).
$config['des_key'] = 'pb0UucO0eqjgvhrqYlFTBVjE';

// ----------------------------------
// PLUGINS
// ----------------------------------
// List of active plugins (in plugins/ directory)
$config['plugins'] = array();

// Set the spell checking engine. Possible values:
// - 'googie' - the default (also used for connecting to Nox Spell Server, see 'spellcheck_uri' setting)
// - 'pspell' - requires the PHP Pspell module and aspell installed
// - 'enchant' - requires the PHP Enchant module
// - 'atd' - install your own After the Deadline server or check with the people at http://www.afterthedeadline.com before using their API
// Since Google shut down their public spell checking service, the default settings
// connect to http://spell.roundcube.net which is a hosted service provided by Roundcube.
// You can connect to any other googie-compliant service by setting 'spellcheck_uri' accordingly.
$config['spellcheck_engine'] = 'pspell';
$config['enable_installer'] = true;

Then press “continue” in the web installer. On the following page, press on the button “Initialize database”.

Finally, disable the Roundecubemail installer. Change the RoundCube config.inc.php configuration file

nano /usr/share/roundcubemail/config/config.inc.php

and change the line:

$config['enable_installer'] = true;

to:

$config['enable_installer'] = false;

Roundcube is available now under the aliases /webmail and /roundcubemail on your server:

http://192.168.0.100/webmail

The RoundCube login is the email address and password of an email account that you create later in ISPConfig.

22 Install ISPConfig 3.2

The ISPConfig installer will configure all services like Postfix, Dovecot, etc. for you.

You now also have the possibility to let the installer create an SSL vhost for the ISPConfig control panel so that ISPConfig can be accessed using https:// instead of http://. To achieve this, just press ENTER when you see this question: Do you want a secure (SSL) connection to the ISPConfig web interface (y,n) [y]:.

To install ISPConfig 3.2 nightly build, do this:

cd /tmp 
wget -O ispconfig.tar.gz https://www.ispconfig.org/downloads/ISPConfig-3-stable.tar.gz
tar xfz ispconfig.tar.gz
cd ispconfig3*/install/

The next step is to run:

php -q install.php

This will start the ISPConfig 3 installer. The installer will configure all services like Postfix, Dovecot, etc. for you.

[root@server1 install]# php install.php

--------------------------------------------------------------------------------
_____ ___________ _____ __ _ ____
|_ _/ ___| ___ \ / __ \ / _(_) /__ \
| | \ `--.| |_/ / | / \/ ___ _ __ | |_ _ __ _ _/ /
| | `--. \ __/ | | / _ \| '_ \| _| |/ _` | |_ |
_| |_/\__/ / | | \__/\ (_) | | | | | | | (_| | ___\ \
\___/\____/\_| \____/\___/|_| |_|_| |_|\__, | \____/
__/ |
|___/
--------------------------------------------------------------------------------

>> Initial configuration
Operating System: CentOS 8.2
Following will be a few questions for primary configuration so be careful.
Default values are in [brackets] and can be accepted with <ENTER>.
Tap in "quit" (without the quotes) to stop the installer.

Select language (en,de) [en]: <-- Hit Enter
Installation mode (standard,expert) [standard]: <-- Hit Enter
Full qualified hostname (FQDN) of the server, eg server1.domain.tld [server1.example.com]: <-- Hit Enter
MySQL server hostname [localhost]: <-- Hit Enter
MySQL server port [3306]: <-- Hit Enter
MySQL root username [root]: <-- Hit Enter
MySQL root password []: <-- Ente the MySQL root password here
MySQL database to create [dbispconfig]: <-- Hit Enter
MySQL charset [utf8]: <-- Hit Enter
Configuring Postgrey
Configuring Postfix
Generating a 4096 bit RSA private key
................................++
.....................................................................................................................................................................................................................................................................................................................................................++
writing new private key to 'smtpd.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]: <-- Enter 2 Letter country code, e.g. US
State or Province Name (full name) []: <-- Enter anme of State or Province
Locality Name (eg, city) [Default City]: <-- Name of city
Organization Name (eg, company) [Default Company Ltd]: <-- Company name
Organizational Unit Name (eg, section) []: <-- Hit Enter
Common Name (eg, your name or your server's hostname) []: <-- Enter server hostname here, in my case: server1.example.com
Email Address []: <-- Enter Email address
Configuring mailman
Configuring Dovecot
Configuring Spamassassin
Configuring Amavisd
Configuring Getmail
Configuring Jailkit
Configuring Pureftpd
Configuring BIND
Configuring Apache
Configuring vlogger
[INFO] service OpenVZ not detected
Configuring Bastille Firewall
[INFO] service Metronome XMPP Server not detected
Configuring Fail2ban
Configuring Apps vhost
Installing ISPConfig
ISPConfig Port [8080]: <-- Hit Enter
Admin password [fad579a6]: <-- Enter new password for ISPConfig admin user
Re-enter admin password []: <-- Repeat the password
Do you want a secure (SSL) connection to the ISPConfig web interface (y,n) [y]: <-- Hit Enter
Generating RSA private key, 4096 bit long modulus
.................................................................................++
.....++
e is 65537 (0x10001)
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]: <-- Enter 2 Letter country code, e.g. US
State or Province Name (full name) []: <-- Enter anme of State or Province
Locality Name (eg, city) [Default City]: <-- Name of city
Organization Name (eg, company) [Default Company Ltd]: <-- Company name
Organizational Unit Name (eg, section) []: <-- Hit Enter
Common Name (eg, your name or your server's hostname) []: <-- Enter server hostname here, in my case: server1.example.com
Email Address []: <-- Enter Email address
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []: <-- Hit Enter
An optional company name []: <-- Hit Enter
writing RSA key

Configuring DBServer
Installing ISPConfig crontab
Installing ISPConfig crontab
no crontab for root
no crontab for getmail
Detect IP addresses
Restarting services ...
Installation completed.

The installer automatically configures all underlying services, so there is no manual configuration needed.

23 First ISPConfig Login

Afterwards you can access ISPConfig 3 under http(s)://server1.example.com:8080/ or http(s)://192.168.0.100:8080/ (http or https depends on what you chose during installation).

Enable epel-release and PowerTools on Oracle Linux 8

I’ve been trying out Oracle Cloud, particularly the “Always Free” offering as it permits free hosting for up to 6 virtual machines. This then got me trying Oracle Linux as an OS.

Oracle Linux is based on CentOS and has alot of similarities but some small differences. CentOS’s epel-release and PowerTools repos are of course, Oracle branded and not installed by default.

Enable epel-release

dnf install oracle-epel-release-el8
dnf config-manager --set-enabled ol8_developer_EPEL
dnf update

Enable PowerTools

dnf config-manager --set-enabled ol8_codeready_builder