How to Setup a Home Server (Running from a USB Flash Drive)

On these page I describe how I did setup my own home server connected to the internet via FTTH. I use this server as personal e-mail and web server. It contains a fanless motherboard only. It boots and runs from a 64 GB USB flash drive, avoiding the need for an internal harddisk. The serial port is used as console, avoiding the use of a monitor.

This is my third server, which I installed in 2025. Click here for the description of how I did install my second server in 2007. And click here for the description of how I did install my first server in 2003, which used a fanless computer equiped with a 40 GB harddisk and a CD-ROM drive.

Contents:

1. My Requirements
2. The Hardware
3. The Operating System
4. Serial Cable
5. My Network Configuration
6. Partitioning the Flash Drive
7. Installing CentOS 8 Linux
8. Installing the GRUB2 UEFI Boot Loader
9. Preparations for First Boot
10. First Boot
11. Making a Backup First
12. Additional Configuration and Installing Additional Components
13. Configuring Startup
14. Personal Fine Tuning of CentOS 8 Linux
15. Creating Additional User Accounts
16. Crontab
17. Telnet
18. FTP
19. DNS
20. E-Mail
21. Protecting E-Mail with SPF, DKIM and DMARC
22. Filtering Spam
23. Auto-Replying to E-Mail
24. Web Server
25. Web Usage Statistics
26. Samba
27. Protection Against Brute Force Password Hacking
28. NAT Settings FTTH Modem
Glossary and Abbreviations
References

1. My Requirements

For my server I had the following requirements:


2. The Hardware

As hardware I have used a fanless industrial mini-computer with an Intel Celeron J4125 processor, 8GB DDR4 RAM, a 256GB SSD drive, 4 USB ports and 2 serial ports. The SSD drive I do not need, but I could not get it without.

It is a small 14x14x4cm box, which gets its power from a 12V DC input. It comes with an external 100-240V AC to 12V DC power adapter similar to the ones used with laptops.

For the network I use a TP Link UE306 USB 3.0 to gigabit ethernet adapter. Although the mini-computer has built-in ethernet ports I choose not to use them. Using an external ethernet adapter makes it easier to temporarily run the server from a laptop, by just plugging the USB flash drive with the OS and the ethernet addapter in a laptop.

I use one of the build-in serial ports as console. If one hase a computer withour serial ports one can use a USB to serial cable. I recommend using a cable with an FTDI chip. The FTDI chip is the most common one used in USB to serial cables, and is supported in the Linux kernel.

As boot drive I use a 64GB USB flash drive. It is recommended to buy a high-speed flash drive from a reputable manufacturer.




Picture 1: My server.

To setup the BIOS, I needed to connect a monitor and a keyboard. This is the only time the monitor and keyboard are needed. Operating the system can be done using the serial port. Installing the system onto the USB flash drive can be done from any (laptop) computer.

I configured the BIOS to boot from USB and to reboot automatically after a power failure. Secure boot must be disabled.


3. The Operating System

I not even considered Windows, since it is neither free nor well designed. Since I did want to have a free operating system, the choice was between one of the many Linux distributions and FreeBSD Unix. They are basically all variants of the same flavour.

I have chosen CentOS 8 Linux. CentOS is a freeware version of Red Hat Enterprise Linus. My previous servers were also running Linux versions origination from Red Hat. In 2025 CentOS 8 was already end-of-life. However in 2020 I installed a backup server in the cloud running CentOS 8, and I wanted to copy as much as possible from this installation. I think most of what is described below would also be valid for CentOS 9.

I used a DVD-DL disk titled "CentOS 8.2-2004 X86_64 everything", which I did download as an ISO file from the CentOS Download website. (Today it is no longer available since CentOS 8 is end-of-life.)


4. Serial Cable

To connect my server to my laptop a cross-over cable is needed, connecting TXD of the server to RXD of the laptop, and RXD of the server to TXD of the laptop. The hardware handshake signals are looped back. Figure 1 shows the cable pinning.

 

Figure 1: Serial cross-over cable.


5. My Network Configuration

I got a single public IPv4 address 77.174.241.175 from my internet provider. I got an IPv6 range 2a02:a466:5961/80 as well.

My home network is connected to the internet via an FritzBox FTTH modem. This modem provides Network Address Translation (NAT), Dynamic Host Configuration (DHCP) and a name server (DNS). It can connect to up to 4 ethernet devices via it's build-in hub.

My home network uses internal IP addresses, which can not be reached directly from the internet:

When IP packages pass through the FTTH modem, these internal IP addresses are translated into my public IP address and back. For traffic originating from my home network, the network address translator knows from which internal IP address the session originates. That way it is later able to send the response back to the right internal IP address.

For traffic originating from the internet, the network address translator has a table telling which protocols are handled by which internal IP address. If it receives an IP package of which the protocol is not listed in the table, they are discarded. By doing so it provides firewall functionality as a by-product of the network address translation.

For more information about Network Address Translation see Wikipedia [5].

 

Figure 2: My network configuration.

I have registered my own domain fwiarda.com at Network Solutions (see http://www.networksolutions.com/). Within this domain:

The name servers of Network Solutions are the name servers for my domain fwiarda.com.


6. Partitioning the Flash Drive

To install CentOS 8 Linux on the USB flash drive regular Linux laptop or desktop computer is used. The server hardware is not needed for this.

Two partitions are created on the flash drive:

Note that I do not make a swap partition. Swapping to a flash drive is a bad idea, since flash memory can withstand only a limmited number of write cycles. Instead we have choosen to use an abundant 8GB of RAM, making swapping not necessary.

Check the device name of the flash drive before continuing! Using the wrong device name can erase the operating system from your computer! In the above it is assumed that the flash drive is /dev/sda. It could also be /dev/sdb or /dev/sdc, depending on other drives present in your computer.

First the USB flash drive is completely erased with the command (being careful to use the right device name):

dd if=/dev/zero of=/dev/sda bs=512000 

The drive is now completely empty. I partition it using the more modern GUID Partition Table (GPT), instead of the older Master Boot Record (MBR) partition table. so the gdisk command is used instead of the older fdisk command:

gdisk /dev/sda

the gdisk program now prompts for input. the following commands are entered to the gdisk program:

n
p
(use default value)
+500mb
0700
n
2
(use default value)
+50g
8300
w

the newly created partition will be formatted and labeled with the following commands (being careful to use the right device name):

mkfs.vfat -F 32 -n FATBOOT /dev/sda1
mkfs.ext4 -L server:/ /dev/sda2

7. Installing CentOS 8 Linux

A regular laptop or desktop computer is booted from the DVD "CentOS 8.2-2004 X86_64 everything". The USB flash drive on which we want to install CentOS 8 Linux is inserted in this computer.

When CentOS 8 Linux boots up from the DVD it starts the Anaconda installer. The following choises are made in the Anaconda installer (again be carefull to select the right device to install to):


8. Installing the GRUB2 UEFI Boot Loader

The GRUB2 the GRUB2 boot loader is installed by just copying file to the FATBOOT partition. Click here to download a copy of the GRUB2 UEFI boot loader. Unzip this file and copy the boot loader to /EFI/Boot/bootx64.efi. This is the default file UEFI will load at boot time.

A file /EFI/Boot/grub.cfg is created to contain the following lines:

set default=0
set timeout=2
set check_signatures=no

menuentry "Linux with Regular Serial Console" {
        linux /EFI/Linux/vmlinuz logo.nologo console=ttyS0,19200n8 ro root=LABEL=server:/
        initrd /EFI/Linux/initramfs.img
}
menuentry "Linux with USB Serial Console" {
        linux /EFI/Linux/vmlinuz logo.nologo console=ttyUSB0,19200n8 ro root=LABEL=server:/
        initrd /EFI/Linux/initramfs.img
}
menuentry "Linux with Video Display Console" {
        linux /EFI/Linux/vmlinuz logo.nologo ro root=LABEL=server:/
        initrd /EFI/Linux/initramfs.img
}
menuentry "Setup" {
        exit 0
}
menuentry "Power Off" {
        halt
}

The first entry Linux with Regular Serial Console is the default entry that is used normally. The second entry Linux with USB Serial Console shall be used when using USB to serial cable instead of a regular serial port. The line set default=0 can be changed to set default=1 to use this entry permanently. The third entry Linux with Video Display Console shall be used when a regular computer with a video screen as console is used. E.g. to debug the server.

Now the Linux kernel to be booted must be transfered to the FAT32 FATBOOT partition. This is done on a computer running Linux with the following commands:

md /tmp/server_fatboot
md /tmp/server_root
mount /dev/sda1 server_fatboot
mount /dev/sda2 server_root
cp /tmp/server_root/boot/vmlinuz-4.18.0-193.el8.x86_64 /tmp/fatboot/EFI/Linux/vmlinuz
cp /tmp/server_root/boot/initrd-4.18.0-193.el8.x86_64.img /tmp/fatboot/EFFI/Linux/initramfs.img

Now the USB flash drive is ready to be booted for the first time.


9. Preparations for First Boot

In the following it is asumed that the root filesystem is still mounted at /tmp/server_root as done in the previous section.

The file /tmp/server_root/etc/fstab is edited to contain the following lines:

LABEL=server:/             /                   ext4    defaults,noatime        1 1
LABEL=FATBOOT              /fatboot            vfat    defaults                0 0

Note the parameter noatime for the root filesystem. Since USB flash drives have a limitted number of write times, it is undesirable that every file read operation is logged, resulting in a write to disk.


10. First Boot

At first boot the graphical user interface is started and we have to answer some questions. Because the target server hardware uses a serial console instead of a graphical display, the USB flash drive is booted the first time on the computer used to install it.

The USB flash drive is placed in the computer and we select it as UEFI boot device. At the boot screen we select:

Linux with Video Display Console

At the first boot screens we:

The USB flash drive is now put into the server. The server is connected with the serial cross-over cable to our Windows computer. On the windows computer we run a VT100 terminal emulation program (like Kermit 95). The serial port settings are 19200 baud, no-parity and 8 data bits. When the server is powered up it boots from the USB flash drive. We get the Linux login prompt at our terminal emulator.

Further configuration must be done while logged in as root.

To disable SELinux the file /etc/sysconfig/selinux is edited changing the following line:

SELINUX=disabled 

To make the system boot without graphical user interface next time, the following commands are issued:

rm -f /etc/systemd/system/default.target
ln -s /usr/lib/systemd/system/multi-user.target /etc/systemd/system/default.target

The USB flash drive is now ready to bootup our server with it.


11. Making a Backup First

In the remainder of this page we do edit a lot of files. It is a good practice to make a backup copy of the original file with a .old extension before editing.

The system configuration is basically determined by the files in the /etc tree. The whole tree can be backed up to a file /root/etc.tar.gz with the command:

tar -zcf /root/etc.tar.gz /etc 

And it can be restored again with the commands:

cd /
rm -rf /etc 
tar -zxf /root/etc.tar.gz

12. Additional Configuration and Installing Additional Components

We reboot the server and login as root.

A file /etc/sysconfig/network-scripts/ifcfg-enp0s21f0u2 is created with the network settings. I shall contain the following lines:

DEVICE=enp0s21f0u2
BOOTPROTO=static
IPADDR=10.0.0.254
DNS1=10.0.0.254
GATEWAY=10.0.0.138
NETMASK=255.0.0.0
IPV6ADDR=2a02:a466:5961:1::10.0.0.252/64
ONBOOT=yes

Note that the device name enp021f0u2 can change depending on the USB port the USB to ethernet connector is connected to. The right device name can be seen in the console messages when unplugging and replugging the ethernet addapter.

Because CentOS 8 is end-of-life the Yum repositories must be changes with the following commands:

sed -i 's/^mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
sed -i 's|^#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*

Some addtional packages are downloaded with the commands:

yum --downloadonly --downloaddir=/root/rmps install epel-release
yum --downloadonly --downloaddir=/root/rmps install yum-utils
yum --downloadonly --downloaddir=/root/rmps install bind
yum --downloadonly --downloaddir=/root/rmps install clamav clamav-update
yum --downloadonly --downloaddir=/root/rmps install dos2unix
yum --downloadonly --downloaddir=/root/rmps install fail2ban
yum --downloadonly --downloaddir=/root/rmps install ftp
yum --downloadonly --downloaddir=/root/rmps install genwqe-zlib
yum --downloadonly --downloaddir=/root/rmps install GeoIP
yum --downloadonly --downloaddir=/root/rmps install iptables-services
yum --downloadonly --downloaddir=/root/rmps install mailx
yum --downloadonly --downloaddir=/root/rmps install make
yum --downloadonly --downloaddir=/root/rmps install mod_ssl
yum --downloadonly --downloaddir=/root/rmps install perl-CPAN
yum --downloadonly --downloaddir=/root/rmps install php
yum --downloadonly --downloaddir=/root/rmps install sendmail sendmail-cf
yum --downloadonly --downloaddir=/root/rmps install telnet
yum --downloadonly --downloaddir=/root/rmps install tmpwatch
yum --downloadonly --downloaddir=/root/rmps install xinetd telnet-server
yum --downloadonly --downloaddir=/root/rpms install wireguard-tools
yum --downloadonly --downloaddir=/root/rpms install opendkim
yum --downloadonly --downloaddir=/root/rpms install opendkim-tools

The downloaded package files are installed with the command:

rpm -i /root/rpms/*

The following command is issued to make the real time clock use UTC time:

timedatectl set-local-rtc 0

13. Configuring Startup

The following commands deletes unnecessary startup files:

rm -rf /etc/systemd/user
rm -rf /etc/systemd/system/basic.target.wants
rm -rf /etc/systemd/system/bluetooth.target.wants
rm -rf /etc/systemd/system/graphical.target.wants
rm -rf /etc/systemd/system/nfs-blkmap.service.requires
rm -rf /etc/systemd/system/nfs-idmapd.service.requires
rm -rf /etc/systemd/system/nfs-mountd.service.requires
rm -rf /etc/systemd/system/nfs-server.service.requires
rm -rf /etc/systemd/system/nginx.service.d
rm -rf /etc/systemd/system/php-fmp.service.d
rm -rf /etc/systemd/system/remote-fs.target.wants
rm -rf /etc/systemd/system/rpc-gssd.service.requires
rm -rf /etc/systemd/system/rpc-statd-notify.service.requires
rm -rf /etc/systemd/system/rpc-statd.service.requires
rm -rf /etc/systemd/system/sysinit.target.wants
rm -rf /etc/systemd/system/sysstat.service.wants
rm -rf /etc/systemd/system/vmtoolsd.service.requires
rm -f /etc/systemd/system/dbus-org.bluez.service
rm -f /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service
rm -f /etc/systemd/system/dbus-org.freedesktop.Avahi.service
rm -f /etc/systemd/system/dbus-org.freedesktop.ModemManager1.service
rm -f /etc/systemd/system/dbus-org.freedesktop.nm-dispatcher.service
rm -f /etc/systemd/system/dbus-org.freedesktop.timedate1.service
rm -f /etc/systemd/system/display-manager.service
rm -f /etc/systemd/system/syslog.service
rm -f /etc/systemd/system/multi-user.target.wants/ModemManager.service
rm -f /etc/systemd/system/multi-user.target.wants/NetworkManager.service NetworkManager.service
rm -f /etc/systemd/system/multi-user.target.wants/abrt-ccpp.service
rm -f /etc/systemd/system/multi-user.target.wants/abrt-oops.service
rm -f /etc/systemd/system/multi-user.target.wants/abrt-vmcore.service
rm -f /etc/systemd/system/multi-user.target.wants/abrt-xorg.service
rm -f /etc/systemd/system/multi-user.target.wants/abrtd.service
rm -f /etc/systemd/system/multi-user.target.wants/atd.service
rm -f /etc/systemd/system/multi-user.target.wants/auditd.service
rm -f /etc/systemd/system/multi-user.target.wants/avahi-deamon.service
rm -f /etc/systemd/system/multi-user.target.wants/chronyd.service
rm -f /etc/systemd/system/multi-user.target.wants/dnf-makecache.timer
rm -f /etc/systemd/system/multi-user.target.wants/firewalld.service
rm -f /etc/systemd/system/multi-user.target.wants/kdump.service
rm -f /etc/systemd/system/multi-user.target.wants/ksm.service
rm -f /etc/systemd/system/multi-user.target.wants/ksmtuned.service
rm -f /etc/systemd/system/multi-user.target.wants/libstoragemgmt.service
rm -f /etc/systemd/system/multi-user.target.wants/libvirtd.service
rm -f /etc/systemd/system/multi-user.target.wants/mcelog.service
rm -f /etc/systemd/system/multi-user.target.wants/mdmonitor.service
rm -f /etc/systemd/system/multi-user.target.wants/named.service
rm -f /etc/systemd/system/multi-user.target.wants/nfs-client.service
rm -f /etc/systemd/system/multi-user.target.wants/pmcd.service
rm -f /etc/systemd/system/multi-user.target.wants/pmie.service
rm -f /etc/systemd/system/multi-user.target.wants/pmlogger.service
rm -f /etc/systemd/system/multi-user.target.wants/remote-fs.target
rm -f /etc/systemd/system/multi-user.target.wants/rhsmcert.service
rm -f /etc/systemd/system/multi-user.target.wants/rpcbind.service
rm -f /etc/systemd/system/multi-user.target.wants/smartd.service
rm -f /etc/systemd/system/multi-user.target.wants/smb.service
rm -f /etc/systemd/system/multi-user.target.wants/sssd.service
rm -f /etc/systemd/system/multi-user.target.wants/sysstat.service
rm -f /etc/systemd/system/multi-user.target.wants/tuned.service
rm -f /etc/systemd/system/multi-user.target.wants/vdo.service
rm -f /etc/systemd/system/multi-user.target.wants/vmtoolsd.service
rm -f /etc/systemd/system/multi-user.target.wants/xinetd.service
rm -f /etc/systemd/system/sockets.target.wants/avahi-deamon.socket
rm -f /etc/systemd/system/sockets.target.wants/pcscd.socket
rm -f /etc/systemd/system/sockets.target.wants/rcpbind.socket
rm -f /etc/systemd/system/sockets.target.wants/sssd-kcm.socket

To prevent some services that I have no clue about how and why they are started from being started, the follwing commands are executed:

ln -s /dev/null /etc/systemd/system/serial-getty@ttyS0.service
ln -s /dev/null /etc/systemd/system/serial-getty@ttyUSB0.service
ln -s /dev/null /etc/systemd/system/systemd-timedated.service

To determine which services are being started at startup, the directory "/etc/systemd/system/multi-user.target.wants" is filled with the following commands:

cd /etc/systemd/system/multi-user.target.wants
ln -s /usr/lib/systemd/system/crond.service crond.service
ln -s /usr/lib/systemd/system/dovecot.service dovecot.service
ln -s /usr/lib/systemd/system/fail2ban.service fail2ban.service
ln -s /usr/lib/systemd/system/httpd.service httpd.service
ln -s /usr/lib/systemd/system/irqbalance.service irqbalance.service
ln -s /usr/lib/systemd/system/named.service named.service
ln -s /usr/lib/systemd/system/ntfilter.service ntfilter.service
ln -s /usr/lib/systemd/system/rsyslog.service rsyslog.service
ln -s /usr/lib/systemd/system/saslauthd.service saslauthd.service
ln -s /usr/lib/systemd/system/sendmail.service sendmail.service
ln -s /usr/lib/systemd/system/smb.service smb.service
ln -s /usr/lib/systemd/system/sshd.service sshd.service
ln -s /usr/lib/systemd/system/vsftpd.service vsftpd.service
ln -s /usr/lib/systemd/system/xinetd.service xinetd.service

The file "/usr/lib/systemd/system/serial-getty@.service" is copied to "/etc/systemd/system/serial-getty-19200@.service". The following lines in this file are changed (to change set the baud rate to 19200):

Description=Modified Serial Getty on %I
ExecStart=-/sbin/agetty -o '-p -- \\u' 19200 %I $TERM

To determine where login prompts will apear, the directory "/etc/systemd/system/getty.target.wants" is filled with the following commands:

cd /etc/systemd/system/getty.target.wants
ln -s /lib/systemd/system/getty@.service getty@tty1.service 
ln -s /etc/systemd/system/serial-getty-19200@.service serial-getty@ttyS0.service 
ln -s /etc/systemd/system/serial-getty-19200@.service serial-getty@ttyUSB0.service

The first line starts a login prompt at the video display /dev/tty1. The second line starts a login prompt at the regular serial port /dev/ttyS0. The third line starts a login prompt at the first USB to serial interface /dev/ttyUSB0.


14. Personal Fine Tuning of CentOS 8 Linux

The changes in this section are fine tunings which are a matter of personal taste. The system will work fine without them.

The file /etc/bashrc is edited to contain the following lines:

# If we are an interactive shell and the terminal is an xterm,
# the environment variable PROMPT_COMMAND is set to manipulate
# the window title.
if [ "$PS1" ]; then
    case $TERM in
        xterm*)
                PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME%%.*}:${PWD/#
$HOME/~}"; echo -ne "\007"'
                ;;
        *)
                PROMPT_COMMAND=''
            ;;
    esac
fi

# Set prompt.
PS1='\u@\h:\w \$ '

# Group and world do not get write permision on newly created files.
umask 022

# Define the equivalent of DOS commands as aliases.
alias cls="clear"
alias copy="cp -v"
alias del="rm"
alias dir="ls --color=never --time-style=long-iso -p -l -L"
alias md="mkdir"
alias rd="rmdir"
alias ren="mv -i"

# These changes reflect my personal taste.
alias info="info --vi-keys"
alias l.="ls --color=never --time-style=long-iso -p -a"
alias ll="ls --color=never --time-style=long-iso -p -l"
alias ls="ls --color=never --time-style=long-iso -p"
alias vi="/bin/vi"

# Stop bash offering to install packages.
unset command_not_found_handle 

The following lines are added to /etc/profile:

# A VT100 is a subset of of the ansi definition and more reliable.
if [ $TERM = ansi ] ; then TERM=vt100 ; fi
export TERM

# Define keys for command line editing. Note that ^H is 
# actually the backspace character.
if [ "$TERM" != "xterm" -a "$TERM" != "linux" -a "$TERM" != "cygwin" ] ; then
	stty erase ^H
fi
bind -f /etc/inputrc

# Get rid of strange (UTF8) characters in man pages and have ISO date
# formats.
LANG=en_DK
export LANG

# Define the prompt to be "user@host:directory $".
PS1='\u@\h:\w \$ '
export PS1

# Use the global vi preferences file.
EXINIT='so /etc/exrc'
export EXINIT

# Man shall look for man pages in /usr/local/share/man as well.
MANPATH=/usr/share/man:/usr/local/share/man
export MANPATH

# If it exists, add ~/bin to the path as well.
if [ -d ~/bin ] ; then
        PATH=~/bin:$PATH
fi

# Login shells seem to fail to run ~/.bashrc, so we do it explicitly.
if [ -f ~/.bashrc ]; then
	. ~/.bashrc
fi 

The files /etc/skel/.bashrc and /root/.bashrc shall contain the follwing lines:

# Source global definitions.
if [ -f /etc/bashrc ]; then
	. /etc/bashrc
fi

# User specific aliases and functions.

Existing profile files have been deleted using the following commands:

rm -f /etc/skel/.bash_profile
rm -f /root/.bash_profile
rm -f /home/*/.bash_profile

A global vi settings file /etc/exrc is created to contain the following lines:

# Autoindentation on.
set autoindent

# Color syntax off.
syn off

I like to have Windows XP style command line editing. To enable this the file /etc/inputrc must contain the following lines:

# Windows style command line editing. 
set completion-ignore-case on
set mark-directories off
set match-hidden-files off

tab: menu-complete

# Note that the command "stty erase ^H" must have been executed before, 
# to be able to re-map the delete key.
del: delete-char
control-h: backward-delete-char
$if term=xterm
	"\e[3~": delete-char
	del: backward-delete-char
$endif
$if term=linux
	"\e[3~": delete-char
	del: backward-delete-char
$endif

# Re-mapping of some keys that where not mapped well.
"\e[5~": beginning-of-history
"\e[6~": end-of-history

# A VT100 does not have a Home, End, PgUp and PgDn key. In my
# terminal emulator I programmed the vi key sequences for these
# actions under the these keys.
"\e\C-u": beginning-of-history
"\e\C-d": end-of-history
"\e0": beginning-of-line
"\e$": end-of-line

"\e[5~": beginning-of-history
"\e\C-u": beginning-of-history

"\e[6~": end-of-history
"\e\C-d": end-of-history

"\e0": beginning-of-line

"\e$": end-of-line

"\e[1;5C": forward-word
"\e[5C": forward-word
"\e\e[C": forward-word

"\e[1;5D": backward-word
"\e[5D": backward-word
"\e\e[D": backward-word

The file /etc/mail.rc has been edited to contain the following lines:

# Ask for the mail subject when accepting mail from a terminal.
set asksub

# Terminate mail input with a line containing a single dot.
set dot

# Retain read messages in the system mailbox instead of moving them
# to the mbox file.
set hold

# Don't save a message to the file dead.letter when input of the message
# is aborted with ctrl-C.
set nosave

# Don't display Received headers.
ignore Received

15. Creating Additional User Accounts

Two additional user accounts are created.

The account server is used for administrative purposes, like storing the web pages with usage statistics.

The account fwiarda is my personal account. My personal web site is stored under this account. I do receive my personal e-mail on this account. I mount the home directory of this account as an additional drive on my PC.

Creating the additional accounts is done by issuing the following comands:

useradd server -c "Server Administration"
useradd fwiarda -c "Frits Wiarda"
chmod 755 /home/server
chmod 755 /home/fwiarda
passwd server
passwd fwiarda

Note that with the chmod commands I make users home directories readable for all. The default for CentOS 8 Linux is that users home directories are strictly private. I consider this not handy since my users are myself in different roles, and now and then perhaps a well trusted friend.

I create a link /home/root as an alias to the root's home directory. I make the root's home directory world readable as well. Issuing the following commands does this:

ln -s /root /home/root
chmod 755 /root

16. Crontab

After installation the root mail is flooded with mail containing all kind of periodic reports. So I consider it desirable to clean all crontabs, and then add the things I consider useful.

Crontab is a feature which periodically executes certain tasks. There are two types of crontabs, user crontabs and system crontabs.

User crontabs are managed with the command crontab. 

System crontabs are managed by editing the file /etc/crontab. By default this file contains 4 entries which periodically executes all executable files in the directories /etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly, and /etc/cron.monthly. The file /etc/crontab is edited to contain the following lines:

SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
MAILTO=root
HOME=/root

0 * * * * root run-parts /etc/cron.hourly
10 0 * * * root run-parts /etc/cron.daily
20 0 * * 0 root run-parts /etc/cron.weekly
30 0 1 * * root run-parts /etc/cron.monthly

The directories containing the files to be executed periodically are cleaned with the following commands:

mv /etc/cron.hourly /etc/cron.hourly.old
mv /etc/cron.daily /etc/cron.daily.old
mv /etc/cron.weekly /etc/cron.weekly.old
mv /etc/cron.monthly /etc/cron.monthly.old
mkdir /etc/cron.hourly
mkdir /etc/cron.daily
mkdir /etc/cron.weekly
mkdir /etc/cron.monthly

A file /etc/cron.daily/cleanup has been created containing the following
lines:

#!/bin/bash
/usr/sbin/tmpwatch -u -m -c -f 24 /tmp
/usr/sbin/tmpwatch -u -m -c -f 24 /var/spool/squirrelmail/attach

After editing, the permissions for this file have been changed with the command:

chmod 755 /etc/cron.daily/cleanup

For more information about crontabs see Wikipedia [6].


17. Telnet

By default telnet is disabled on CentOS 8 Linux. To enable it edit the file /etc/xinetd.d/telnet and change disable = yes into disable = no. The change becomes effective after the xinet-daemon has been restarted, or after a system reboot.

By default CentOS 8 Linux disallows root login via telnet, since it is considered insecure because telnet uses unencrypted password verification. However on a home network behind a firewall security is not an issue. To enable root login via telnet add the following lines to the file /etc/securetty:

pts/0
pts/1
pts/2
  .
  .
pts/19

The following lines shall also be pressent to enable root login from the serial console:

ttyS0
ttyUSB0

18. FTP

By default CentOS 8 Linux disallows root login via FTP, since it is considered insecure because FTP uses unencrypted password verification. To change this the file /etc/vsftpd/ftpusers is edited. The entry root is removed.

To disable anonymous FTP, to enable ASCII transfers, to increase the idle session timeout, and to define the ports used for passive mode (which must be opened in my FTTH modem as well), the file /etc/vsftpd/vsftpd.conf has been edited changing or adding the following lines:

anonymous_enable=NO
ascii_upload_enable=YES
ascii_download_enable=YES
idle_session_timeout=3600
pasv_enable=YES
pasv_min_port=20000
pasv_max_port=20255

19. DNS

A directory /etc/named is created to store our zone files. I do not like the CentOS 8 Linux default /var/named. Having all configuration files in the /etc tree makes it easier to backup the servers configuration.

The root hints file /var/named/named.ca is copied to /etc/named/named.root. This file contains references to the internet's master name servers. It is advisable to check yearly for updates of this file at ftp://ftp.rs.internic.net/domain/.

For each domain for which we have the authority, we have to create a zone file resolving that domain.

Since my server is connected to the internet via a network address translating (NAT) FTTH modem, different IP addresses are needed to approach my server from the internet and from my home network. From the internet my server has to be approached with the public IP address 77.174.241.175 provided by my internet service provider. The FTTH modem translates this address into the internal IP address 10.0.0.254. If I approach my server from my internal home network, I have to use the internal IP address 10.0.0.254 directly.

My DNS returns an internal IP address to clients locally on my home network (e.g. my laptop). My DNS is the authorizing DNS for clients with local IP addresses only. Clients on the internet will be served by the DNS from my registrar Network Solutions. The settings with my registrar are outside the scope of this page. Registrars typically have their DNSs be configuered via a webpage. The data to be entered is simmilar to the data in our local DNS, with local IP addresses replaced by my public IP address.

Ofcause the above requires that I specify my own DNS server 10.0.0.254 as the prefered DNS in the network configuration of all my local clients. That can be done either by editing the network settings for each client, or by editing the settings for the DHCP server in the FTTH modem.

To cater for the above, the file /etc/named.conf must contain the following lines:

options {
	directory "/etc/named";
	max-cache-size 1m;
	listen-on {any; };
};

logging {
	category lame-servers { null; };
};

view "local" IN {
	match-clients { localnets; };
	recursion yes;
	zone "fwiarda.com." IN {
		type master;
		file "fwiarda.com.lzone";
	};
	zone "." IN {
		type hint;
		file "named.root";
	};
};
The zone file fwiarda.com.lzone resolving local requests for the fwiarda.com domain contains the following lines:
$TTL 2h

@  IN  SOA   ns.fwiarda.com.   fwiarda.xs4all.nl. (
                                  1 ; serial
                                  3h ; refresh
                                  1h ; retry
                                  1w ; expire
                                  1h ) ; negative caching ttl

@ IN  NS    ns.fwiarda.com.

@ IN  A     10.0.0.254

@ IN  MX    0    mail.fwiarda.com.

@ IN  TXT   "v=spf1 a ~all"

default._domainkey.fwiarda.com.   IN  TXT    "v=DKIM1; k=rsa; p=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

_dmarc.fwiarda.com.               IN  TXT    "v=DMARC1; p=none; sp=none; pct=100"

ftp.fwiarda.com.                  IN  A      10.0.0.254
mail.fwiarda.com.                 IN  A      10.0.0.254
ns.fwiarda.com.                   IN  A      10.0.0.254
pc.fwiarda.com.                   IN  A      10.0.0.201
telnet.fwiarda.com.               IN  A      10.0.0.254
server.fwiarda.com.               IN  A      10.0.0.254
ssh.fwiarda.com.                  IN  A      10.0.0.254
www.fwiarda.com.                  IN  A      10.0.0.254

mail.fwiarda.com.                 IN  MX  0   mail.fwiarda.com.

mail.fwiarda.com.                 IN  TXT     "v=spf1 a ~all"

In the above the xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx has to be replaced by the real DKIM key, which for obvious reasons I am not publishing on the internet.

Note that I have not used my regular e-mail address fwiarda@fwiarda.com in the SOA record , but the e-mail address fwiarda@xs4a11.n1 (which is written in SOA format as fwiarda.xs4all.nl), which I got from my internet service provider XS4ALL. If there are problems with my name server or my domain, it is likely that my e-mail address is experiencing problems as well. Therefore I use my e-mail address fwiarda@xs4a11.n1 for things like domain registration and maintenance. Normally this address is forwarded to my regular e-mail address fwiarda@fwiarda.com, but when I am experiencing problems I can cancel this forward and use the fwiarda@xs4a11.n1 address to communicate with the helpdesk.

The changes in this section become effective after the named-daemon is started manually or after a system reboot. 

For more information about DNS see the book titled "DNS and BIND" ([1]);


20. E-Mail

To speed up mail delivery I have edited the file /etc/sysconfig/sendmail, and changed SENDMAIL_OPTS="-q1h" into SENDMAIL_OPTS="-q10m". This change makes that the mail queue is processed every 10 minutes instead of every hour.

I have edited the file /etc/mail/sendmail.mc. to contain the following lines:

include(`/usr/share/sendmail-cf/m4/cf.m4')
OSTYPE(`linux')
VERSIONID(`linux setup for CentOS Linux')
define(`confAUTH_MECHANISMS',`GSSAPI DIGEST-MD5 CRAM-MD5 KERBEROS_V4 LOGIN PLAIN')
define(`confCW_FILE',`/etc/mail/local-host-names')
define(`confDOMAIN_NAME',`mail.fwiarda.com')
define(`confDONT_BLAME_SENDMAIL',`GroupWritableDirPathFile')
define(`confDONT_BLAME_SENDMAIL',`GroupWritableDirPathFileSafe')
define(`confDONT_BLAME_SENDMAIL',`GroupWritableForwardFile')
define(`confDONT_BLAME_SENDMAIL',`GroupWritableForwardFileSafe')
define(`confDONT_BLAME_SENDMAIL',`GroupWritableIncludeFile')
define(`confDONT_BLAME_SENDMAIL',`GroupWritableIncludeFileSafe')
define(`confDOUBLE_BOUNCE_ADDRESS',`null')
define(`confFORWARD_PATH',`$z/.forward')
define(`confMAX_MESSAGE_SIZE',`0')
define(`confPRIVACY_FLAGS',`noexpn,novrfy')
define(`ALIAS_FILE',`/etc/mail/aliases')
TRUST_AUTH_MECH(`GSSAPI DIGEST-MD5 CRAM-MD5 KERBEROS_V4 LOGIN PLAIN')
FEATURE(`accept_unresolvable_domains')
FEATURE(`allmasquerade')
FEATURE(`always_add_domain')
FEATURE(`limited_masquerade')
FEATURE(`masquerade_envelope')
FEATURE(`no_default_msa')
FEATURE(`use_cw_file')
FEATURE(`virtusertable',`hash /etc/mail/virtusertable.db')
MASQUERADE_AS(`mail.fwiarda.com')
MASQUERADE_DOMAIN(`server.fwiarda.com')
MAILER(`smtp')
dnl #
dnl # The parameter "M=S" defines sendmail sends mail without using TLS.
dnl #
CLIENT_OPTIONS(`Family=inet,M=S,Addr=0.0.0.0.')
dnl #
dnl # As long as I do not have IPv6 DNS records my mail can be classified
dnl # as spam when send via IPv6. Therefore the localhost address
dnl # "::1" is specified as sender address for IPv6, to prevent mail to
dnl # be send via IPv6.
dnl #
CLIENT_OPTIONS(`Family=inet6,M=S,Addr=::1')
dnl #
dnl # Sendmail by default listens on IPv4.
dnl # No DAEMON_OPTIONS are needed.
dnl #
dnl
dnl #
dnl # The following makes sendmail listens on IPv6 as well.
dnl #
DAEMON_OPTIONS(`Family=inet6,Port=smtp,Name=MTA6')
DAEMON_OPTIONS(`Family=inet6,Port=submission,Name=MSA6') 
dnl #
dnl # Add DKIM signature to mails.
dnl #
INPUT_MAIL_FILTER(`opendkim',`S=inet:8891@localhost') 

I have edited the file /etc/mail/submit.mc to contain the following lines:

include(`/usr/share/sendmail-cf/m4/cf.m4')
OSTYPE(`linux')
VERSIONID(`linux setup for CentOS Linux')
define(`confCF_VERSION',`Submit')
define(`confPID_FILE',`/var/run/sm-client.pid')
define(`confTIME_ZONE',`USE_TZ')
FEATURE(`msp',`[127.0.0.1]') 

I have edited the file /etc/mail/local-host-names to contain the following lines:

server.fwiarda.com
mail.fwiarda.com
fwiarda.com 

I have edited the file /etc/mail/aliases to contain the following lines:

adm: 			bounce
amanda: 		bounce
apache: 		bounce
bin: 			bounce
canna: 			bounce
desktop: 		bounce
ftp: 			bounce
games: 			bounce
gdm: 			bounce
gopher: 		bounce
halt: 			bounce
ident: 			bounce
ldap: 			bounce
lp: 			bounce
mail: 			bounce
mailman: 		bounce
mailnull: 		bounce
mysql: 			bounce
named: 			bounce
netdump: 		bounce
news: 			bounce
nfsnobody: 		bounce
nobody: 		bounce
nscd: 			bounce
ntp: 			bounce
pcap: 			bounce
postfix: 		bounce
postgres: 		bounce
privoxy: 		bounce
pvm: 			bounce
radvd: 			bounce
rpc: 			bounce
rpcuser: 		bounce
rpm: 			bounce
shutdown: 		bounce
smmsp: 			bounce
squid: 			bounce
sshd: 			bounce
sync: 			bounce
uucp: 			bounce
vcsa: 			bounce
webalizer: 		bounce
wnn: 			bounce
xfs: 			bounce

mailer-daemon: 		/dev/null
null: 			/dev/null
root: 			fwiarda

server 	        	bounce

I have edited the file /etc/mail/virtusertable to contain the following lines:

fwiarda@fwiarda.com		fwiarda
null@fwiarda.com		null
bounce@fwiarda.com		bounce
@fwiarda.com			error:5.1.6:550 Mail to fwiarda@fwiarda.com instead

When hosting additional e-mail domains, a tab-separated list of e-mail addresses and the local mailboxes or aliases on which they must be mapped must be added to the file /etc/mail/virtusertable. Leaving the part of the e-mail address before the @ sign away maps the entire domain. Note that all domains for which e-mail can be received must be listed in the file /etc/mail/local-host-names.

For more information about e-mail see the book titled "Sendmail" ([2]).


21. Protecting E-Mail with SPF, DKIM and DMARC

Nowadays it is common to protect e-mail against spoofing. Spammers offten spoof the sender address of an e-mail so the receiver thinks the mail is comming from a trusted person. Big e-mail providers like GMail refuse mail from which the sender cannot be authenticated.

SPF (Sender Policy Framework) is the easiest. In the DNS (Domain Name System) it is registered which IP addresses are allowed to send mail for that domain. Mail send from other IP addresses shall be considered illigitimate. SPF does not work if e-mail is forwarded from one account to another account. The recieving account sees the e-mail comming from the IP address of the mailserver of the forwarding account instead of from the sending mail server. For more information about SPF see Wikipedia [7].

DKIM (DomainKeys Identified Mail) is more complex. E-mail is signed with a secret key, while in the DNS the matching public key is registered. To add the DKIM signature to outgoing e-mail, extra software is needed to be installed, through which all outgoing e-mail is filtered. For more information about DKIM see Wikipedia [8].

DMARC (Domain-based Message Authentication, Reporting and Conformance) is an advisory protocol that tells how to treat e-mail failing SPF and/or DKIM. In the DNS a record is published advising how to treat e-mail failing SPF and/or DKIM. For more information about DKIM see Wikipedia [9].

SPF

I have inplemented SPF by registring an TXT record in the DNS for both my fwiarda.com domain and for my mail.fwiarda.com sub-domain containing the text "v=spf1 a ~all". It authorizes the IP address which is in the A-record for this domain to send e-mail. It advices a soft-fail for non matching IP addresses. A soft-fail means the e-mail is quarentined in the spam folder.

The following lines in the zone file fwiarda.com.lzone define the SPF records:

@                              IN  TXT   "v=spf1 a ~all"
mail.fwiarda.com.              IN  TXT   "v=spf1 a ~all"

In the DNS of my registrar Network Solutions I had to make similar changes.

DKIM

I use opendkim as software to sign outgoing e-mail with a DKIM key. The file /etc/opendkim.comf is the configuratin file for opendkim. I have made the following changes to it:

# Only sign outgoing e-mail.
Mode                    s

# Define the socket throug which sendmail accesses opendkim.
Socket                  inet:8891@localhost

# No error reports.
SendReports             no

# Pointers to further configuration files. Note that refile: is used instead 
of file: to allow for the use of wildcards in the files.
KeyTable                /etc/opendkim/KeyTable
SigningTable            refile:/etc/opendkim/SigningTable
ExternalIgnoreList      refile:/etc/opendkim/TrustedHosts
InternalHosts           refile:/etc/opendkim/TrustedHosts

The file /etc/opendkim/KeyTable shall contain the following lines:

default._domainkey.fwiarda.com fwiarda.com:default:/etc/opendkim/fwiarda.com.default.private

The file /etc/opendkim/SigningTable shall contain the following lines:

*@fwiarda.com default._domainkey.fwiarda.com
*@mail.fwiarda.com default._domainkey.fwiarda.com
*@server.fwiarda.com default._domainkey.fwiarda.com

The file /etc/opendkim/TrustedHosts shall only contain the IPv4 and IPv6 address of the localhost. So it shall contain the following lines:

127.0.0.1
::1

We generate the DKIM key pair with the following commands:

opendkim-genkey -a -d fwiarda.com
mv default.private /etc/opendkim/fwiarda.com.default.private
mv default.txt /etc/opendkim/fwiarda.com.txt_record

The file /etc/opendkim/fwiarda.com.default.private contains the private key that is used to sign outgoing e-mail. The file /etc/opendkim/fwiarda.com/txt_record comtains the DKIM record with the public key that has to be entered into the DNS. Note that everytime the keys are generated one gets a different key pair.

All files in the directory /etc/opendkim must be owned by the user opendkim and the group opendkim. They are not allowed to be world readable. If these conditions are not fulfilled opendkim will not start. To do so, the following commands are executed:

chown opendkim:opendkim /etc/opendkim/*
chmod 640 /etc/opendkim/*

The following line in the zone file fwiarda.com.lzone defines the DKIM record:

default._domainkey.fwiarda.com.   IN  TXT    "v=DKIM1; k=rsa; p=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Ofcause the xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx has to be replaced by the real DKIM key, which for obvious reasons I am not publishing on the internet. This key can be found in the file /etc/opendkim/fwiarda.com.txt_record.

DMARC

I do not want to loose any outgoing e-mails due to misconfiguration. Therefore I set DMARC to not enforcing SPF and/or DKIM.

The following line in the zone file fwiarda.com.lzone defines the DMARC record:

_dmarc.fwiarda.com.               IN  TXT    "v=DMARC1; p=none; sp=none; pct=100"

22. Filtering Spam

I use spamassassin to tag spam for mail send to my personal mail account. My spamassassin configuration file /etc/mail/spamassassin/local.cf contains the following lines:

report_safe 0
add_header all Report "_REPORT_" 

Besides the lines above, I have added some personal rules to the file /etc/mail/spamassassin/local.cf . These rules are outside the scope of this document.

I have created a file /etc/mail/spamassassin/whitelist.cf  containing the e-mail addresses of my contacts in lines like:

whitelist_from user@domain

I have created a file /etc/mail/spamassassin/blacklist.cf  containing the e-mail addresses of people from who I do not want to receive e-mail in lines like:

blacklist_from user@domain

I have written a procmail script which moves spam to a seperate mailbox ~/mail/Spam. The suspected spammer will receive a mail that his e-mail has been deleted. In this mail he is informed that he can bypass the spam filter by starting the subject field with the keyword NOSPAM. Real spammers do not read bounced messages. But legitimate senders whose mail is accidentally tagged as spam will do. Click here for a copy of the script. Beware DOS to Unix text file conversion (CR-LF to LF) when downloading it. The script is self ducmenting. Copy it to /usr/local/bin/spamfilter. The file must be executable for everybody. This can be done with the command:

chmod 755 /usr/local/bin/spamfilter

To have all my e-mail filtered, I have created a /home/fwiarda/.forward containing the following line:

"|/usr/local/bin/spamfilter email=fwiarda@fwiarda.com"

Note that sendmail requires the /home/fwiarda/.forward file to be owned by fwiarda and not being world readable. When the file has been created by root, the following commands fix this:

chmod 644 /home/fwiarda/.forward
chown fwiarda:fwiarda /home/fwiarda/.forward

For more information about spamassassin see Wikipedia [10].


23. Auto-Replying to E-Mail


CentOS 8 Linux does not come with a vacation program, to auto-reply to your mail. I have written a perl script myself, which mimics the Unix vacation program.

In most aspects this script is stripped down in functionality compared to the Unix vacation program. However, with the handling of .forward files it is more advanced. If a .forward file already exists and contains forwards to something else then vacation, it adds a line to the original .forward file instead of overwriting it. Later, when vacation is disabled, this line is deleted again. This behaviour leaves other forwards intact. 

Click here for a copy of the script. Beware DOS to Unix text file conversion (CR-LF to LF) when downloading it. The script is self ducmenting. Copy it to /usr/local/bin/vacation. The file must be executable for everybody. This can be done with the command:

chmod 755 /usr/local/bin/vacation

24. Web Server

The following lines must be added to or changed in the main server configuration section of /etc/httpd/conf/httpd.conf:

# Set my e-mail address as the server administrators e-mail.
ServerAdmin "fwiarda@fwiarda.com"

# Set the name of the server. An IP address is OK here.
ServerName "10.0.0.254"

# The following options are necessary for HTTPS.
SSLCertificateFile "/etc/pki/tls/certs/fwiarda.com.crt"
SSLCertificateKeyFile "/etc/pki/tls/private/fwiarda.com.key"

# Each directory to which Apache has access can be configured with respect
# to which services and features are allowed and/or disabled in that
# directory (and its subdirectories).
#
# We configure the default to be a very relaxed set of features,
# so we do not have to switch them on seperately for each virtual
# server.
<Directory "/">
	Options All
	AllowOverride All
	Order allow,deny
	Allow from all
</Directory>

# We set the documents defining a directory index.
<IfModule dir_module>
	DirectoryIndex "index.htm" "index.html" "index.txt" "index.cgi" "index.php"
</IfModule>

# We define the format of directory listings.
IndexOptions FancyIndexing NameWidth=* FoldersFirst SuppressDescription 

# All files ending with .cgi are scripts, even if they are not placed
# in a special directory for cgi-scripts.
AddHandler cgi-script .cgi .pl .py

# We do not want .htaccess, .htpasswd and .htgroup files to be displayed.
<Files ~ "^\.ht">
	Order allow,deny
	Deny from all
</Files>

# We lookup the hostnames for the IP addresses to which
# we provide pages. This makes our log files more readable.
HostnameLookups On

# We set the error log file.
ErrorLog "/var/log/httpd/error_log"

# We set the access log file.
CustomLog "/var/log/httpd/access_log" combined

# Disable http://server.fwiarda.com/cgi-bin/ to be a server
# wide script directory.
#ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"

These settings are valid for all virtual hosts. The following lines have been added to or changed in the virtual host section of /etc/httpd/conf/httpd.conf:

# We define we are going to use name based virtual hosts.
NameVirtualHost "*:80"

# This entry is the default entry for HTTP. It is used when the hostname 
# in the URL is not known to us. Hackers just trying our IP address end up
# here. We will always return an empty page with mime-type text/plain. All 
# settings for this entry are taken from the main server configuration
# section above.
<VirtualHost "*:80">
	<Directory "/dev">
		ForceType text/plain
	</Directory>
	AliasMatch .* "/dev/null"
	CustomLog "/var/log/httpd/access_log" combined
	ErrorLog "/var/log/httpd/error_log"
</VirtualHost>

# This entry is the entry used for all HTTPS connections. Because
# name based virtual hosts are not working for SSL connections we
# use a trick. We change "https://" in the URL into "http://" 
# using mod_rewrite. Apache now internally forwards the HTTPS 
# request to itself as an HTTP request.
<VirtualHost "*:443">
	SSLEngine on
	RewriteEngine On
	RewriteRule (.*) http://%{HTTP_HOST}%{REQUEST_URI} [proxy]
	CustomLog "/dev/null" combined
	CustomLog "/var/log/httpd/ssl_access_log" combined
	ErrorLog "/var/log/httpd/ssl_error_log"
</VirtualHost>

# The entry for calls to http://mail.fwiarda.com/ . It accesses
# SquirrelMail, a web based mail client which is part of the Red Hat
# Linux 8.0 distribution. Since it is a web site on it's own,
# it has it's own error log and access log files.
<VirtualHost "*:80">
	ServerName "mail.fwiarda.com"
	DocumentRoot "/usr/share/squirrelmail"
	ErrorLog "/var/log/httpd/mail.fwiarda.com.error_log"
	CustomLog "/var/log/httpd/mail.fwiarda.com.access_log" combined
</VirtualHost>

# The entry for calls to http://server.fwiarda.com/ . 
# It has it's own error log and access log files. 
<VirtualHost "*:80">
	ServerName "server.fwiarda.com"
	DocumentRoot "/home/server/www"
	ErrorLog "/var/log/httpd/server.fwiarda.com.error_log"
	CustomLog "/var/log/httpd/server.fwiarda.com.access_log" combined
</VirtualHost>

# The entry for calls to my personal web site
# http://www.fwiarda.com/ . It has it's own document root, and it's
# own, error log and access log files.
<VirtualHost "*:80">
	ServerName "www.fwiarda.com"
	ServerAlias "fwiarda.com"
	DocumentRoot "/home/fwiarda/www"
	ErrorLog "/var/log/httpd/www.fwiarda.com.error_log"
	CustomLog "/var/log/httpd/www.fwiarda.com.access_log" combined
</VirtualHost> 

The following files have been edited commenting everything out by placing a # at the beginning of each line:

/etc/httpd/conf.d/mailman.conf
/etc/httpd/conf.d/manual.conf
/etc/httpd/conf.d/mrtg.conf
/etc/httpd/conf.d/squid.conf
/etc/httpd/conf.d/squirrelmail.conf
/etc/httpd/conf.d/ssl.conf
/etc/httpd/conf.d/webalizer.conf
/etc/httpd/conf.d/welcome.conf

The document root directory, the directory containing the log files, and all the directories above them, must be searchable and readable for the user apache. To be able to test this, it practical to login as user apache. However, by default no login shell is assigned to the user apache. We fix this editing the file /etc/passwd and changing the line:

apache:x:48:48:Apache:/var/www:/sbin/nologin

into:

apache:x:48:48:Apache:/var/www:/bin/bash

When logged-in as root, we can now log-in as apache by issuing the following command:

su - apache

If there is any flaw in file access permission settings, they will become clearly noticeable.

The web site http://server.fwiarda.com/ is used for accessing the access and error logs, and the usage statistics of my server. The directory /home/server/www is the document root for this web site. It must be created, as well as sub-directories for usage statistics and a link to the directory containing the servers log files:

mkdir /home/server/www
mkdir /home/server/www/usage
mkdir /home/server/www/usage/mail.fwiarda.com
mkdir /home/server/www/usage/server.fwiarda.com
ln -s /var/log/httpd /home/server/www/log
chmod 755 /var/log/httpd

I do not want everybody to have access to my logs and usage statistics. Therefore  a file /home/server/www/.htaccess is created, containing the following lines:

AuthUserFile /home/server/www/.htpasswd
AuthName "Server Administrator"
AuthType Basic
<Limit GET POST>
	require valid-user
</Limit>

A file /home/server/www/.htpasswd is created by issuing the following commands:

htpasswd /home/server/www/.htpasswd root
htpasswd /home/server/www/.htpasswd fwiarda

The htpasswd program prompts for the appropriate passwords.

The ownership of the /home/server/www tree shall belong to the user server. If this directory tree has been created while being logged-in as root, the ownership must be transferred with the following command:

chown -R server:server /home/server/www

For more information about the Apache web server see "Apache; The Definitive Guide" ([3]). 


25. Web Usage Statistics

Webalizer is a tool for generating usage statistics for web pages. The webalizer binary and the man page has been extracted from an old CentOS 7 RMP "GeoIP-1.5.0-14.el7.x86_64.rpm" that cannot be installed on CentOS 8. See here for a copy of these files. They must be copied to "/usr/bin/webalizer" and to "/usr/share/man1/webalizer.1.gz". After copying the following command must be executed:

chmod +x /usr/bin/webalizer

In order to make the webalizer binary work, links mimicking old libraries must be created with the comands:

cd /usr/lib64
ln -s libgd.so.3.0.5 libgd.so.2
ln -s libpng16.so.16.34.0 libpng15.so.15

The file /etc/webalizer.conf is edited, to ensure the following parameters are defined or commented out:

# We will specify the log file at the command line.
# The entry LogFile is commented out.
#LogFile /var/log/httpd/access_log
# We will specify the output directory at the command line.
# The entry OutputDir is commented out.
#OutputDir .
# The file webalizer.hist in the output directory will
# contain the data for previous months.
HistoryName webalizer.hist
# We only process entries not yet processed before. We
# retrieve the old usage information form the files
# webalizer.hist and webalizer.current
Incremental yes
# The file webalizer.current in the output directory will
# contain the data for the current month.
IncrementalName webalizer.current
# For debugging purposes we enable log messages. When 
# webalizer is called from a script, we suppres all messages 
# by adding the -Q option at the command line.
Quiet no

A file /etc/cron.daily/webalizer is created. This file is executed daily since it resides in the /etc/cron.daily directory. It must contain the following lines:

#!/bin/bash
if [ -s /var/log/httpd/server.fwiarda.com.access_log ] ; then
	/usr/bin/webalizer -Q \
		-n server.fwiarda.com \
		-r server.fwiarda.com \
		-o /home/server/www/usage/server.fwiarda.com \
		/var/log/httpd/server.fwiarda.com.access_log
fi
if [ -s /var/log/httpd/mail.fwiarda.com.access_log ] ; then
	/usr/bin/webalizer -Q \
		-n mail.fwiarda.com \
		-r mail.fwiarda.com \
		-o /home/server/www/usage/mail.fwiarda.com \
		/var/log/httpd/mail.fwiarda.com.access_log
fi
if [ -s /var/log/httpd/www.fwiarda.com.access_log ] ; then
	/usr/bin/webalizer -Q \
		-n www.fwiarda.com \
		-r www.fwiarda.com \
		-r fwiarda.com \
		-o /home/server/www/usage/www.fwiarda.com \
		/var/log/httpd/www.fwiarda.com.access_log
fi 

After editing this file must be made executable with the command:

chmod 755 /etc/cron.daily/webalizer

For more information about webalizer see Wikipedia, [11].


26. Samba

The file /etc/samba/smb.conf is edited and shall contain the following lines:

[global]
workgroup = fwiarda-group
netbios name = fwiarda-server
server string = Frits Wiarda's Server
encrypt passwords = yes
security = user
time service = yes
follow symlinks = yes
wide links = yes
unix extensions = no

[fwiarda]
path = /home/fwiarda
comment = /home/fwiarda
read only = no
create mask = 644
force create mode = 644
directory mask = 755
force directory mode = 755
guest ok = no 

Samba uses the passwords from file /etc/smbpasswd instead of /etc/passwd or /etc/shadow. That means separate passwords for samba must be created. This is done with the following comand:

smbpasswd -a fwiarda

The smbpasswd program prompts for the appropriate password.

For more information on samba see "Using Samba" ([4]).


27. Protection Against Brute Force Password Hacking

After running a server for some time, one will discover in the log files that hackers are trying to discover passwords by just trying out huge volumes of passwords. To make this kind of attacks more difficult it is wise not to use easy to guess passwords like regular words from the dictionary. The best passwords consist out of letters, digits and other characters.

To make brute force password hacking even more difficult, I use fail2ban. Fail2ban scans the log files for failed login attempts, and blocks a couple of hours the IP addresses from which to many failed login attempts are made. It uses the iptables command to discard all IP packets from these IP addresses. That makes my server totally unreachable from these IP addresses, stopping the attack after a few attempts.

For more information about fail2ban see Wikipedia. [12].


28. NAT Settings FTTH Modem

To be able to reach my server from the internet, the some NAT settings must me made in the FTTH modem. 

The easiest option is to set  the default  address to which IP packages from the internet must be routed to the servers internal IP address 10.0.0.254. Now  all IP packages from the internet are send to the server.

The best option is to list explicitly for which TCP and UDP ports IP packages must be routed to the servers internal IP address 10.0.0.254. Other IP packages can be discarded, making life for hackers more difficult. The ports which must be opened are:

For more information about Network Address Translation see Wikipedia [5].


Glossary and Abbreviations

BIOS Basic Input Output System.
   
DHCP Dynamic Host Configuration Protocol.
   
DKIM DomainKeys Identified Mail.
   
DMARC Domain-based Message Authentication and Conformance.
   
DNS Domain Name System.
   
FTP File Transfer Protocol.
   
FTTH Fiber To The Home.
   
GTP GUID Partition Table.
   
HTML HyperText Mark-up Language.
   
HTTP HyperText Transfer Protocol.
   
HTTPS HyperText Transfer Protocol Secure.
   
IMAP Internet Mail Access Protocol.
   
IP Internet Protocol.
   
IPv4 Internet Protocol Version 4.
   
IPv6 Internet Protocol Version 6.
   
MBR Master Boot Record.
   
POP3 Post Office Protocol version 3.
   
NAT Network Address Translation.
   
RFC Request For Comment.
   
RXD Receive Data.
   
SMTP Simple Mail Transfer Protocol.
   
SPF Sender Policy Framework.
   
SSH Secure SHell.
   
SSL Secure Socket Layer.
   
STL Secure Transport Layer.
   
TCP Transmission Control Protocol.
   
TXD Transmit Data.
   
UDP User Datagram Protocol.
   
UEFI Universal Extendable Firmware Interface.
   
USB Universal Serial Bus.


References

[1] DNS and BIND; Paul Albitz and Cricket Liu; O'Reilly Publishing

[2] Sendmail; Bryan Costales with Eric Alllman; O'Reilly Publishing

[3] Apache; The Definitive Guide; Ben Laurie and Peter Laurie; O'Reilly Publishing

[4] Using Samba; Jay Ts, Robert Eckstein and David Colloier-Brown; O'Reilly Publishing; Digital copy of an old edition available at http://www.samba.org/samba/docs/using_samba/toc.html

[5] Network Address Translation; Wikipedia; See https://en.wikipedia.org/wiki/Network_address_translation

[6] Cron; Wikipedia; See https://en.wikipedia.org/wiki/Cron

[7] Sender Policy Framework; Wikipedia; See https://en.wikipedia.org/wiki/Sender_Policy_Framework

[8] DomainKeys Identified Mail; Wikipedia; See https://en.wikipedia.org/wiki/DomainKeys_Identified_Mail

[9] DMARC; Wikipedia; See https://en.wikipedia.org/wiki/DMARC

[10] Apache SpamAssassin; Wikipedia; See https://en.wikipedia.org/wiki/Apache_SpamAssassin

[11] Webalizer; Wikipedia; See https://en.wikipedia.org/wiki/Webalizer

[12] Fail2ban; Wikipedia; See https://en.wikipedia.org/wiki/Fail2ban


Home  fwiarda@fwiarda.com