Ubuntu 22.04 – Extending the root partition

Introduction

I run several virtual machines based on Ubuntu. I create a base image that is cloned when I need a new virtual machine. Since most of my VMs don’t need a large disk image I keep the base image on the small side. So I extend the size of the disk image when needed. After the disk image size is increased you need to allocate that space to use it. The steps below will show you how to extend the root partition to the new size.

The Steps

I’m assuming that the disk image or physical hard drive of the machine has been increased.

Do a df -h to get the logical volume name of the partition you want to extend.
> df -h

Filesystem                        Size Used Avail Use% Mounted on
tmpfs                             393M 1.1M  392M   1% /run
/dev/mapper/ubuntu--vg-ubuntu--lv  24G 9.0G   14G  41% /
tmpfs                             2.0G    0  2.0G   0% /dev/shm
tmpfs                             5.0M    0  5.0M   0% /run/lock
/dev/sda2                         2.0G 367M  1.5G  21% /boot
tmpfs                             393M 4.0K  393M   1% /run/user/1000

Now check to be sure the volume group has free space. The free space is the possible max amount you can extend the partition.
> vgdisplay

With the information above I can expand the partition 23G. Here’s the command I would use.
> sudo lvextend -L +23G /dev/mapper/ubuntu–vg-ubuntu–lv

Finally we extend the filesystem to the new logical volume size.
> sudo resize2fs /dev/mapper/ubuntu–vg-ubuntu–lv                     

Now that we’re done, lets reboot the system.
> sudo reboot

Log back into the ubuntu system. Check that your partition has been extended.
> df -h

Conclusion

Thanks to LVM the process of extending the root partition is simple and straight forward.

HOWTO Ubuntu 22.04 Virtual Web Hosting With Apache, PHP, vsFTPD and Let’s Encrypt

Introduction

The focus of this howto is for those users who need to host their own domains and maybe a few customer domains. This is not aimed at being used for mass web hosting.

There are many ways to do virtual websites under linux. The technique I am going to use is multiple domains on one ip address. I’m using standard linux users to log into the virtual domains.

Setting Up The Base Server

For a dedicated server start with the base server setup:

Howto Ubuntu 22.04 Base Server Setup

Introduction All of our servers will start with this install. This base server is based on Ubuntu 22.04 LTS Server.  I don’t explain much in the howto so if you have a question leave a comment or use Google. Downloading … Continue reading

NOTE: If you don’t follow the base server setup then you may run into problems with this howto.

Install Software

We need to install an FTP server and Let’s Encrypt. So type the following:
> sudo add-apt-repository ppa:certbot/certbot
> sudo apt update
> sudo apt install vsftpd python3-certbot-apache

Setup Default User Directory

A new user’s directory needs to have some files and folders created for them.  We will modify the user skel directory so when a new user is created the required folder structure will be there.

Type the following.
> sudo mkdir -p /etc/skel/{website,logs,cgi-bin,backup}
> sudo echo “HELLO WORLD” > index.html
> sudo mv index.html /etc/skel/website/

Configuring vsftpd

Lets create the configuration file.  Replace the contents of /etc/vsftpd.conf with the text below.

listen=NO
listen_ipv6=YES
anonymous_enable=NO
local_enable=YES
write_enable=YES
#local_umask=022
dirmessage_enable=YES
use_localtime=YES
xferlog_enable=YES
connect_from_port_20=YES
chroot_local_user=YES
secure_chroot_dir=/var/run/vsftpd/empty
pam_service_name=vsftpd
rsa_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
rsa_private_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
ssl_enable=NO
allow_writeable_chroot=YES
pasv_enable=Yes
pasv_min_port=40000
pasv_max_port=40100

Start vsftpd.
> sudo systemctl enable vsftpd
> sudo systemctl start vsftpd.service

Configuring Apache

Most of the apache configuration is already done.  We are going to do some changes to make managing websites easier.

Create the virtual host config file. I defined macros to make virtual host creation easier.  I also turn on compression. Create /etc/apache2/conf-available/virtual.conf with the following:

# Go ahead and accept connections for these vhosts
# from non-SNI clients
SSLStrictSNIVHostCheck off

# define a macro for the virtual hosts
# the user's directory should be setup as follows:
# |- cgi-bin
# |- logs
# |- website
# |- ssl
#
LoadModule macro_module modules/mod_macro.so

<Macro virtHost $type $user $host>
    use $type $host

    ServerName $host
    ServerAlias www.$host 
    DocumentRoot /home/$user/website
    ScriptAlias "/cgi-bin/" "/home/$user/cgi-bin"
    LogFormat "%h %l %u %t \"%r\" %>s %b" common
    CustomLog /home/$user/logs/access_log common
    ErrorLog /home/$user/logs/error_log
    <Directory /home/$user/website>
      DirectoryIndex index.html index.php
      Options Indexes FollowSymLinks
      AllowOverride All
      Require all granted

      # setup file compression
      use CompressFiles

      # setup browser caching
      use BrowserCache

      # disable hotlinking for some files
      use DisableHotLink $host
    </Directory>
  </VirtualHost>
</Macro>

<Macro BrowserCache>
  # Enable expires cache
  <IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType text/css "access 1 month"
    ExpiresByType text/html "access 1 month"
    ExpiresByType image/gif "access 1 year"
    ExpiresByType image/png "access 1 year"
    ExpiresByType image/jpg "access 1 year"
    ExpiresByType image/jpeg "access 1 year"
    ExpiresByType image/x-icon "access 1 year"
    ExpiresByType application/pdf "access 1 month"
    ExpiresByType application/javascript "access 1 month"
    ExpiresByType text/x-javascript "access 1 month"
    ExpiresDefault "access 1 month"
  </IfModule>

  # Cache-Control Headers
  <ifModule mod_headers.c>
    <filesMatch "\.(ico|jpe?g|png|gif|swf)$">
      Header set Cache-Control "public"
    </filesMatch>
    <filesMatch "\.(css)$">
      Header set Cache-Control "public"
    </filesMatch>
    <filesMatch "\.(js)$">
      Header set Cache-Control "private"
    </filesMatch>
    <filesMatch "\.(x?html?|php)$">
      Header set Cache-Control "private, must-revalidate"
    </filesMatch>
  </ifModule>
</Macro>

<Macro CompressFiles>
  # enable compression
  <IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE "application/atom+xml"
    AddOutputFilterByType DEFLATE "application/javascript"
    AddOutputFilterByType DEFLATE "application/json"
    AddOutputFilterByType DEFLATE "application/ld+json"
    AddOutputFilterByType DEFLATE "application/manifest+json"
    AddOutputFilterByType DEFLATE "application/rdf+xml"
    AddOutputFilterByType DEFLATE "application/rss+xml"
    AddOutputFilterByType DEFLATE "application/schema+json"
    AddOutputFilterByType DEFLATE "application/vnd.geo+json"
    AddOutputFilterByType DEFLATE "application/vnd.ms-fontobject"
    AddOutputFilterByType DEFLATE "application/x-font"
    AddOutputFilterByType DEFLATE "application/x-font-opentype"
    AddOutputFilterByType DEFLATE "application/x-font-otf"
    AddOutputFilterByType DEFLATE "application/x-font-truetype"
    AddOutputFilterByType DEFLATE "application/x-font-ttf"
    AddOutputFilterByType DEFLATE "application/x-javascript"
    AddOutputFilterByType DEFLATE "application/x-web-app-manifest+json"
    AddOutputFilterByType DEFLATE "application/xhtml+xml"
    AddOutputFilterByType DEFLATE "application/xml"
    AddOutputFilterByType DEFLATE "font/eot"
    AddOutputFilterByType DEFLATE "font/otf"
    AddOutputFilterByType DEFLATE "font/ttf"
    AddOutputFilterByType DEFLATE "font/opentype"
    AddOutputFilterByType DEFLATE "image/bmp"
    AddOutputFilterByType DEFLATE "image/svg+xml"
    AddOutputFilterByType DEFLATE "image/vnd.microsoft.icon"
    AddOutputFilterByType DEFLATE "image/x-icon"
    AddOutputFilterByType DEFLATE "text/cache-manifest"
    AddOutputFilterByType DEFLATE "text/css"
    AddOutputFilterByType DEFLATE "text/html"
    AddOutputFilterByType DEFLATE "text/javascript"
    AddOutputFilterByType DEFLATE "text/plain"
    AddOutputFilterByType DEFLATE "text/vcard"
    AddOutputFilterByType DEFLATE "text/vnd.rim.location.xloc"
    AddOutputFilterByType DEFLATE "text/vtt"
    AddOutputFilterByType DEFLATE "text/x-component"
    AddOutputFilterByType DEFLATE "text/x-cross-domain-policy"
    AddOutputFilterByType DEFLATE "text/xml"
  </IfModule>
</Macro>

<Macro DisableHotLink $host >
  # Disable file hotlinking - jpg jpeg png gif pdf
  <IfModule mod_rewrite.c>
    RewriteEngine on
    RewriteCond %{HTTP_REFERER} !^$
    RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?$host [NC]
    RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?google.com [NC]
    RewriteRule \.(jpg|jpeg|png|gif|pdf)$ – [NC,F,L]
  </IfModule>
</macro>

<Macro VHost443 $host >
  <VirtualHost *:443>
    SSLEngine on
    SSLProtocol all -SSLv2
    SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5
    SSLCertificateFile /etc/letsencrypt/live/$host/cert.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/$host/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/$host/fullchain.pem
</Macro>

<Macro VHost80 $host >
  <VirtualHost *:80>
</Macro>

Enable the configuration.
> sudo a2enconf virtual

Enable macros and ssl.
> sudo a2enmod macro
> sudo a2enmod ssl

Restart apache
> sudo service apache2 restart

Configuring Let’s Encrypt

Let’s Encrypt needs to be configured to auto renew certs. Lets create a daily cron job
> sudo nano -w /etc/cron.daily/letsencrypt

#!/usr/bin/bash
# letsencrypt auto renew
/usr/bin/certbot renew --no-self-upgrade >> /var/log/le-renew.log

Adding a Default Website

Now we will create a default website.  This site will be used when no other website can be found.

Setup a DNS record for the new domain. I won’t cover this here.

Add a user. This user will be associated with the new domain name. Type the following.
> sudo useradd -m -U -s /bin/bash -c “default website” defaultweb
> sudo passwd defaultweb

Add the apache user to the new user’s group.
> sudo usermod -a -G defaultweb www-data

Update directory permissions.
> sudo chmod g+rwx /home/defaultweb
> sudo chown -R defaultweb:defaultweb /home/defaultweb

Create the virtual host file.  For the default server we will use port 80. Past the text below into the file.  Type:
> sudo nano -w /etc/apache2/sites-available/00-default.conf

# Virtual host config file
#
# MACRO FORMAT
# virtHost [type] [user] [host]
#  type = VHost80 or VHost443
#  user = the username of the website
#  host = domain name or virtual host name
#
# Use the line below to configure a site on port 80
use virtHost VHost80 defaultweb myserver.mydomain.tld

# Uncomment the line below once lets encrypt is setup
# use virtHost VHost443 defaultweb myserver.mydomain.tld

Disable the old default site and enable our default site.
> sudo a2dissite 000-default
> sudo a2ensite 00-default

Reload apache config
> sudo service apache2 reload

Test out the new website.  You should get a page that says ‘Hello World’.

Now we will setup lets encrypt for the default website.  The website must be reachable from the internet.  So lets get the cert:
> sudo certbot certonly –webroot -w /home/defaultweb/website/ -d <YOUR_DOMAIN> –email <YOUR_EMAIL_ADDRESS> –agree-tos

Edit /etc/httpd/virtualHosts.d/00-default.conf
Uncomment the last line to enable ssl connections for the virtual host.

Reload apache.
> sudo service apache2 reload

Test it out.  Connect to your default host via https.

Setup Additional Virtual Hosts

Adding a new virtual host is like adding the default virtual host.  Lets go through the steps.

Be sure DNS is configured for the new virtual host.

Setup a new user. This user will be associated with the new domain name. Type the following. Change ‘NEWUSER’ to the username you want.
> sudo useradd -m -U -s /bin/bash -c “Virtual Website User” NEWUSER
> sudo passwd NEWUSER
> sudo usermod -a -G NEWUSER www-data
> sudo chmod g+rwx /home/NEWUSER
> sudo chown -R NEWUSER:NEWUSER /home/NEWUSER

Create the virtual host file.  For the virtual server we will use port 80. Past the text below into the file.  Replace ‘NEWUSER’ with your user name.  Replace NEWVHOST with your hostname.
> sudo nano -w /etc/apache2/sites-available/NEWUSER.conf

# Virtual host config file
#
# MACRO FORMAT
# virtHost [type] [user] [host]
#  type = VHost80 or VHost443
#  user = the username of the website
#  host = domain name or virtual host name
#
# Use the line below to configure a site on port 80
use virtHost VHost80 NEWUSER NEWVHOST

# Uncomment the line below once lets encrypt is setup
# use virtHost VHost443 NEWUSER NEWVHOST

Enable the new site and reload apache config
> sudo a2ensite NEWUSER
> sudo service apache2 reload

Now we will setup lets encrypt for the new website.  The website must be reachable from the internet.  Replace NEWUSER and NEWVHOST with the info you have.  So lets get the cert.
> sudo certbot certonly –webroot -w /home/NEWUSER/website/ -d NEWHOST -d www.NEWHOST –email YOUR_EMAIL_ADDRESS –agree-tos

Edit /etc/httpd/virtualHosts.d/NEWUSER.conf
Uncomment the last line to enable ssl connections for the virtual host.

Reload apache.
> sudo service apache2 reload

Test it out.  Connect to your new host via https.

Conclusion

That’s the complete setup.

Howto Ubuntu 22.04 Base Server Setup

Introduction

All of our servers will start with this install. This base server is based on Ubuntu 22.04 LTS Server.  I don’t explain much in the howto so if you have a question leave a comment or use Google.

Downloading the ISO

Visit the Ubuntu website and download the ubuntu 22.04 server ISO.

Initial Install

The install screens are straight forward.  I’m not going to cover them in much detail.  Unless you need to customize a setting, just choose the default settings.  Boot the install DVD.

Click ‘Reboot’ when it appears.

First boot

Reboot the machine when the install finishes.
The OS will boot. Log in. All the commands need to be run as root so lets start a shell with root privilleges.
> sudo bash

Get everything updated and install a couple of items.
> sudo apt update
> sudo apt dist-upgrade
> sudo apt install software-properties-common

Install and enable ssh.
> sudo apt install ssh
> sudo systemctl enable –now ssh

WARNING: My server isn’t directly connected to the internet. The firewall is disabled to help with installation, configuration and testing easier. Once everything is working, turn on the firewall and configure it. I wil remind you to secure your server at the end of this howto.

now reboot the server.

The Second Boot – Installing Additional Packages

We need quite a few other packages. In this howto I’m installing packages regardless if they were already installed by another dependency. This guards against package changes that could cause a package to not be installed. Once again log in to your server.

Let’s add a 3rd party repo for Apache.
> add-apt-repository ppa:ondrej/apache2

Add a 3rd party repo for PHP.
> sudo add-apt-repository ppa:ondrej/php

Now bring everything up to date.
> sudo apt update && sudo apt upgrade

Install the following packages. Multiple lines to make cut and paste easier.
> sudo apt install make screen snmp composer libcurl4 unzip net-tools
> sudo apt install apache2 libapache2-mod-php mysql-server mysql-client
> sudo apt install libapache2-mod-fcgid php8.2-opcache php-apcu

Install some extra PHP libraries.
> sudo apt install php-gd php-snmp php-mbstring php-mysql
> sudo apt install php-odbc php-imap
> sudo apt install php-xmlrpc php8.2-dba
> sudo apt install php-soap php-zip php-intl php-curl

Configure Apache and PHP

Enable the rewrite module.
> sudo a2enmod rewrite actions fcgid alias proxy_fcgi expires headers

Enable Apache.
> sudo systemctl enable apache2.service

Reload apache.
> sudo systemctl restart apache2.service

Configuring MySQL

We need to set the root password in mysql. so type:
> sudo mysql

Set the root password for mysql.
mysql> ALTER USER ‘root’@’localhost’ IDENTIFIED WITH mysql_native_password by ‘my-secret-password’;
mysql> exit

Configure mysql.
> sudo mysql_secure_installation

Installing and Configuring phpMyAdmin

I prefer to phpMyAdmin to manage my MySQL databases.

Now install phpMyAdmin.
> sudo apt install phpmyadmin

Restart Apache.
> sudo systemctl restart apache2.service

NOTE: You should think about limiting access to phpMyAdmin. This will help secure your server.

Installing Postfix

Lets install postfix.
> sudo apt install postfix

When prompted select internet site. Next set the mail server name.

Installing cockpit

I’m using cockpit as my server admin tool.  Do the following to set it up.
> sudo apt install cockpit
> sudo systemctl start cockpit
> sudo systemctl enable cockpit.socket

You can now login to https://yourserver.tld:9090 to administer your server.

NOTE: You should limit access to this service.

Getting root’s and other’s mail

You need to get some local system user’s mail. We’ll use postfix’s virtual file to get the emails to the right place.

Add the following to /etc/postfix/virtual

root admin@yourdomain.tld
postmaster admin@yourdomain.tld
abuse admin@yourdomain.tld

Now add the configuration option to main.cf
> sudo postconf -e “virtual_alias_maps = hash:/etc/postfix/virtual”

Just a couple commands to wrap everything up.
> sudo postmap /etc/postfix/virtual
> sudo systemctl restart postfix
> sudo systemctl enable postfix

Remove Cloud Init

Our server won’t be using cloud-init.  To keep from causing you trouble in the future we will remove it now.

Type:
> sudo apt remove cloud-init cloud-initramfs-copymods cloud-initramfs-dyn-netconf

Final Settings

You may want to enable the linux firewall.
Set your timezone in /etc/php.ini

Conclusion

That’s it for the basic server setup. This is an example of a standard linux server setup. Be sure to use cockpit to set which services you want to start at boot time. See the other pages for info on configuring servers for virtual webhosting or virtual email hosting. Remember to configure the firewall on the server.

HOWTO: Change Thin LVM to Directory Storage in Proxmox 7.x

Introduction

In Proxmox 7.x LVM thin is the default local storage for VMs.  However I prefer the old method of directory based storage for local storage.  You can find this information in the proxmox wiki.  These are my terse notes to get the job done.

The Conversion

This should only be done on a new installation of proxmox.  We will be mounting the storage to /var/lib/vz. If you have data in that directory you will lose it.

Start by logging into the Proxmox gui. Click on cluster then select storage. Remove the lvm-thin storage.

Next you will need to ssh into your Proxmox node. Type the following to set everything up.
> sudo lvremove pve/data
> sudo lvcreate –name data -l +100%FREE pve
> sudo mkfs.ext4 /dev/pve/data

Add the following to /etc/fstab
> nano -w /etc/fstab

/dev/pve/data /var/lib/vz ext4 defaults 0 1

Restart proxmox.
> sudo reboot

Conclusion

Once rebooted you can log into the gui and see your new local directory storage.  Maybe someday I’ll switch to lvm-thin or zfs.

Configure Proxmox 7.x for a Low Power Home Server

Introduction

I’ve been using low power CPUs for some time. This has caused some issues when I’ve needed more CPU processing power. My goal is to move to more power hungry CPUs but still try and save power. To this end I decided to change the CPU governor Proxmox uses. I also switched to using a small form factor case with its lower power power supply.

Configure CPU for Low Power

To make these changes you’ll need to ssh into your proxmox host.

Lat’s start by looking at your current CPU freequency.
> cat /proc/cpuinfo | grep MHz

The above command returns the following for my server.

cpu MHz : 3800.000
cpu MHz : 1760.822
cpu MHz : 3800.000
cpu MHz : 3800.000

First update repos.
> sudo apt update

Install acpi utilities.
> sudo apt install acpi-support acpid acpi

Its time to edit grub.
> nano -w /etd/default/grub

Look for the line that starts with “GRUB_CMDLINE_LINUX_DEFAULT” and add “intel_pstate=disable”..

Mine looks like this.

GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_pstate=disable"

Save and now rebuild grub.
> update-grub

Reboot the system and ssh back in. Change the governor being used.
> echo “conservative” | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

Check your new CPU frequency.
> cat /proc/cpuinfo | grep MHz

Mine shows then following when idle.

cpu MHz : 1605.058
cpu MHz : 1600.000
cpu MHz : 1600.000
cpu MHz : 1600.000

Edit crontab to make the changes permanent.
> crontab -e

add the following to the bottom and save.

@reboot  echo "conservative" | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

 

Conclusion

This is a quick tutorial that I hope helps someone out.

Ubuntu 18.04 Upgrade Apache to Latest Version

Introduction

The apache2 version that is installed on Ubuntu is a couple updates behind.  This unfortunately exposes your server to unpatched vulnerabilities. This can be fixed easily.  So lets get started.

A few quick steps

We will start things off by adding a third party repo.
> sudo add-apt-repository ppa:ondrej/apache2

Now bring everything up to date.
> sudo apt update
> sudo apt dist-upgrade

Conclusion

Not much to it. Enjoy.

HOWTO Ubuntu 20.04 Virtual Web Hosting With Apache, PHP, vsFTPD and Let’s Encrypt

Introduction

The focus of this howto is for those users who need to host their own domains and maybe a few customer domains. This is not aimed at being used for mass web hosting.

There are many ways to do virtual websites under linux. The technique I am going to use is multiple domains on one ip address. I’m using standard linux users to log into the virtual domains.

Setting Up The Base Server

For a dedicated server start with the base server setup:

HOWTO Ubuntu 20.04 LTS Base Server Setup

Introduction All of our servers will start with this install. This base server is based on Ubuntu 20.04 LTS Server.  I don’t explain much in the howto so if you have a question leave a comment or use Google. Downloading … Continue reading

NOTE: If you don’t follow the base server setup then you may run into problems with this howto.

Install Software

We need to install an FTP server and Let’s Encrypt. So type the following:
> sudo add-apt-repository ppa:certbot/certbot
> sudo apt update
> sudo apt install vsftpd python3-certbot-apache

Setup Default User Directory

A new user’s directory needs to have some files and folders created for them.  We will modify the user skel directory so when a new user is created the required folder structure will be there.

Type the following.
> sudo mkdir -p /etc/skel/{website,logs,cgi-bin,backup}
> sudo echo “HELLO WORLD” > index.html
> sudo mv index.html /etc/skel/website/

Configuring vsftpd

Lets create the configuration file.  Replace the contents of /etc/vsftpd.conf with the text below.

listen=NO
listen_ipv6=YES
anonymous_enable=NO
local_enable=YES
write_enable=YES
#local_umask=022
dirmessage_enable=YES
use_localtime=YES
xferlog_enable=YES
connect_from_port_20=YES
chroot_local_user=YES
secure_chroot_dir=/var/run/vsftpd/empty
pam_service_name=vsftpd
rsa_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
rsa_private_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
ssl_enable=NO
allow_writeable_chroot=YES
pasv_enable=Yes
pasv_min_port=40000
pasv_max_port=40100

Start vsftpd.
> sudo systemctl enable vsftpd
> sudo systemctl start vsftpd.service

Configuring Apache

Most of the apache configuration is already done.  We are going to do some changes to make managing websites easier.

Create the virtual host config file. I defined macros to make virtual host creation easier.  I also turn on compression. Create /etc/apache2/conf-available/virtual.conf with the following:

# Go ahead and accept connections for these vhosts
# from non-SNI clients
SSLStrictSNIVHostCheck off

# define a macro for the virtual hosts
# the user's directory should be setup as follows:
# |- cgi-bin
# |- logs
# |- website
# |- ssl
#
LoadModule macro_module modules/mod_macro.so

<Macro virtHost $type $user $host>
    use $type $host

    ServerName $host
    ServerAlias www.$host 
    DocumentRoot /home/$user/website
    ScriptAlias "/cgi-bin/" "/home/$user/cgi-bin"
    LogFormat "%h %l %u %t \"%r\" %>s %b" common
    CustomLog /home/$user/logs/access_log common
    ErrorLog /home/$user/logs/error_log
    <Directory /home/$user/website>
      DirectoryIndex index.html index.php
      Options Indexes FollowSymLinks
      AllowOverride All
      Require all granted

      # setup file compression
      use CompressFiles

      # setup browser caching
      use BrowserCache

      # disable hotlinking for some files
      use DisableHotLink $host
    </Directory>
  </VirtualHost>
</Macro>

<Macro BrowserCache>
  # Enable expires cache
  <IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType text/css "access 1 month"
    ExpiresByType text/html "access 1 month"
    ExpiresByType image/gif "access 1 year"
    ExpiresByType image/png "access 1 year"
    ExpiresByType image/jpg "access 1 year"
    ExpiresByType image/jpeg "access 1 year"
    ExpiresByType image/x-icon "access 1 year"
    ExpiresByType application/pdf "access 1 month"
    ExpiresByType application/javascript "access 1 month"
    ExpiresByType text/x-javascript "access 1 month"
    ExpiresDefault "access 1 month"
  </IfModule>

  # Cache-Control Headers
  <ifModule mod_headers.c>
    <filesMatch "\.(ico|jpe?g|png|gif|swf)$">
      Header set Cache-Control "public"
    </filesMatch>
    <filesMatch "\.(css)$">
      Header set Cache-Control "public"
    </filesMatch>
    <filesMatch "\.(js)$">
      Header set Cache-Control "private"
    </filesMatch>
    <filesMatch "\.(x?html?|php)$">
      Header set Cache-Control "private, must-revalidate"
    </filesMatch>
  </ifModule>
</Macro>

<Macro CompressFiles>
  # enable compression
  <IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE "application/atom+xml"
    AddOutputFilterByType DEFLATE "application/javascript"
    AddOutputFilterByType DEFLATE "application/json"
    AddOutputFilterByType DEFLATE "application/ld+json"
    AddOutputFilterByType DEFLATE "application/manifest+json"
    AddOutputFilterByType DEFLATE "application/rdf+xml"
    AddOutputFilterByType DEFLATE "application/rss+xml"
    AddOutputFilterByType DEFLATE "application/schema+json"
    AddOutputFilterByType DEFLATE "application/vnd.geo+json"
    AddOutputFilterByType DEFLATE "application/vnd.ms-fontobject"
    AddOutputFilterByType DEFLATE "application/x-font"
    AddOutputFilterByType DEFLATE "application/x-font-opentype"
    AddOutputFilterByType DEFLATE "application/x-font-otf"
    AddOutputFilterByType DEFLATE "application/x-font-truetype"
    AddOutputFilterByType DEFLATE "application/x-font-ttf"
    AddOutputFilterByType DEFLATE "application/x-javascript"
    AddOutputFilterByType DEFLATE "application/x-web-app-manifest+json"
    AddOutputFilterByType DEFLATE "application/xhtml+xml"
    AddOutputFilterByType DEFLATE "application/xml"
    AddOutputFilterByType DEFLATE "font/eot"
    AddOutputFilterByType DEFLATE "font/otf"
    AddOutputFilterByType DEFLATE "font/ttf"
    AddOutputFilterByType DEFLATE "font/opentype"
    AddOutputFilterByType DEFLATE "image/bmp"
    AddOutputFilterByType DEFLATE "image/svg+xml"
    AddOutputFilterByType DEFLATE "image/vnd.microsoft.icon"
    AddOutputFilterByType DEFLATE "image/x-icon"
    AddOutputFilterByType DEFLATE "text/cache-manifest"
    AddOutputFilterByType DEFLATE "text/css"
    AddOutputFilterByType DEFLATE "text/html"
    AddOutputFilterByType DEFLATE "text/javascript"
    AddOutputFilterByType DEFLATE "text/plain"
    AddOutputFilterByType DEFLATE "text/vcard"
    AddOutputFilterByType DEFLATE "text/vnd.rim.location.xloc"
    AddOutputFilterByType DEFLATE "text/vtt"
    AddOutputFilterByType DEFLATE "text/x-component"
    AddOutputFilterByType DEFLATE "text/x-cross-domain-policy"
    AddOutputFilterByType DEFLATE "text/xml"
  </IfModule>
</Macro>

<Macro DisableHotLink $host >
  # Disable file hotlinking - jpg jpeg png gif pdf
  <IfModule mod_rewrite.c>
    RewriteEngine on
    RewriteCond %{HTTP_REFERER} !^$
    RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?$host [NC]
    RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?google.com [NC]
    RewriteRule \.(jpg|jpeg|png|gif|pdf)$ – [NC,F,L]
  </IfModule>
</macro>

<Macro VHost443 $host >
  <VirtualHost *:443>
    SSLEngine on
    SSLProtocol all -SSLv2
    SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5
    SSLCertificateFile /etc/letsencrypt/live/$host/cert.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/$host/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/$host/fullchain.pem
</Macro>

<Macro VHost80 $host >
  <VirtualHost *:80>
</Macro>

Enable the configuration.
> sudo a2enconf virtual

Enable macros and ssl.
> sudo a2enmod macro
> sudo a2enmod ssl

Restart apache
> sudo service apache2 restart

Configuring Let’s Encrypt

Let’s Encrypt needs to be configured to auto renew certs. Lets create a daily cron job
> sudo nano -w /etc/cron.daily/letsencrypt

#!/usr/bin/bash
# letsencrypt auto renew
/usr/bin/certbot renew --no-self-upgrade >> /var/log/le-renew.log

Adding a Default Website

Now we will create a default website.  This site will be used when no other website can be found.

Setup a DNS record for the new domain. I won’t cover this here.

Add a user. This user will be associated with the new domain name. Type the following.
> sudo useradd -m -U -s /bin/bash -c “default website” defaultweb
> sudo passwd defaultweb

Add the apache user to the new user’s group.
> sudo usermod -a -G defaultweb www-data

Update directory permissions.
> sudo chmod g+rwx /home/defaultweb
> sudo chown -R defaultweb:defaultweb /home/defaultweb

Create the virtual host file.  For the default server we will use port 80. Past the text below into the file.  Type:
> sudo nano -w /etc/apache2/sites-available/00-default.conf

# Virtual host config file
#
# MACRO FORMAT
# virtHost [type] [user] [host]
#  type = VHost80 or VHost443
#  user = the username of the website
#  host = domain name or virtual host name
#
# Use the line below to configure a site on port 80
use virtHost VHost80 defaultweb myserver.mydomain.tld

# Uncomment the line below once lets encrypt is setup
# use virtHost VHost443 defaultweb myserver.mydomain.tld

Disable the old default site and enable our default site.
> sudo a2dissite 000-default
> sudo a2ensite 00-default

Reload apache config
> sudo service apache2 reload

Test out the new website.  You should get a page that says ‘Hello World’.

Now we will setup lets encrypt for the default website.  The website must be reachable from the internet.  So lets get the cert:
> sudo certbot certonly –webroot -w /home/defaultweb/website/ -d <YOUR_DOMAIN> –email <YOUR_EMAIL_ADDRESS> –agree-tos

Edit /etc/httpd/virtualHosts.d/00-default.conf
Uncomment the last line to enable ssl connections for the virtual host.

Reload apache.
> sudo service apache2 reload

Test it out.  Connect to your default host via https.

Setup Additional Virtual Hosts

Adding a new virtual host is like adding the default virtual host.  Lets go through the steps.

Be sure DNS is configured for the new virtual host.

Setup a new user. This user will be associated with the new domain name. Type the following. Change ‘NEWUSER’ to the username you want.
> sudo useradd -m -U -s /bin/bash -c “Virtual Website User” NEWUSER
> sudo passwd NEWUSER
> sudo usermod -a -G NEWUSER www-data
> sudo chmod g+rwx /home/NEWUSER
> sudo chown -R NEWUSER:NEWUSER /home/NEWUSER

Create the virtual host file.  For the virtual server we will use port 80. Past the text below into the file.  Replace ‘NEWUSER’ with your user name.  Replace NEWVHOST with your hostname.
> sudo nano -w /etc/apache2/sites-available/NEWUSER.conf

# Virtual host config file
#
# MACRO FORMAT
# virtHost [type] [user] [host]
#  type = VHost80 or VHost443
#  user = the username of the website
#  host = domain name or virtual host name
#
# Use the line below to configure a site on port 80
use virtHost VHost80 NEWUSER NEWVHOST

# Uncomment the line below once lets encrypt is setup
# use virtHost VHost443 NEWUSER NEWVHOST

Enable the new site and reload apache config
> sudo a2ensite NEWUSER
> sudo service apache2 reload

Now we will setup lets encrypt for the new website.  The website must be reachable from the internet.  Replace NEWUSER and NEWVHOST with the info you have.  So lets get the cert.
> sudo certbot certonly –webroot -w /home/NEWUSER/website/ -d NEWHOST -d www.NEWHOST –email YOUR_EMAIL_ADDRESS –agree-tos

Edit /etc/httpd/virtualHosts.d/NEWUSER.conf
Uncomment the last line to enable ssl connections for the virtual host.

Reload apache.
> sudo service apache2 reload

Test it out.  Connect to your new host via https.

Conclusion

That’s the complete setup.

Ubuntu: Disable Floppy Drive

Introduction

I was creating a new virtual machine in my development environment and was getting a kernel error complaining about the floppy drive.  Well I use VMWare Fusion and I don’t configure the virtual machine to have a floppy.  This time I configured the VM to use UEFI.  Wouldn’t you know it, UEFI creates a floppy controller.  And guess what? You can’t disable it. Follow the steps below to take care of the problem.

Steps

    1. First we need to blacklist the floppy kernel module. So type the following
      sudo echo "blacklist floppy" > /etc/modprobe.d/blacklist-floppy.conf
    2. Next we need to update the initial ramdisk. Type the follosing:
      sudo update-initramfs -u
    3. Now update grub. Type:
      sudo update-grub
    4. Time to reboot the system. Type:
      sudo reboot

Conclusion

Just a few commands and your console won’t be plastered with floppy drive errors.

Opnsense Stuck at Booting on J1900 Motherboaard

Introduction

I have an Asrock motherboard with a J1900 CPU.  I was setting up a new Opnsense firewall.  Well FreeBSD hence Opnsense has a video bug.  The firewall boots and runs.  You just don’t get the console screen. Below is a quick guide on getting the video working.

Steps

  1. Power on the firewall.
  2. Hit the spacebar at the boot screen.
  3. Choose number 3 to set boot options.
  4. Type the following:
    set kern.vty=sc
  5. Then type:
    boot
  6. Once the firewall boots login as root.
  7. Select the option to exit to a shell.
  8. Type the following:
    echo 'kern.vty="sc"' > /boot/loader.conf.local
  9. Type:
    reboot

Conclusion

Sometimes those little bugs can be a pain.

HOWTO Ubuntu 20.04 Setup An APT Caching server

Introduction

When you are running a few Ubuntu servers you may want to think about setting up an APT caching server.  Installs and upgrades will go quicker.  You might save some bandwidth on your internet connection

Setting Up The Base Server (Optional

For a dedicated server start with the base server setup:

HOWTO Ubuntu 20.04 LTS Base Server Setup

Introduction All of our servers will start with this install. This base server is based on Ubuntu 20.04 LTS Server.  I don’t explain much in the howto so if you have a question leave a comment or use Google. Downloading … Continue reading

NOTE: You can choose an existing server to use.  I chose to have a dedicated server.

Install Software

Install apt-cacher-ng
> sudo apt install apt-cacher-ng

Configure and Test the server

Apt-cacher-ng has a web interface.  To test it visit http://<your-ip-address>:3142/acng-report.html

Create /etc/apt/apt.conf.d/00aptproxy with the following
> sudo nano -w /etc/apt/apt.conf.d/00aptproxy

Acquire::http::Proxy "http://<your-ip-address>:3142";

Do a software update to test it out.
> sudo apt update
> sudo apt dist-upgrade

Now reload the server web page.  It should now show that some items have been downloaded.

Configuring Clients

On each client create /etc/apt/apt.conf.d/00aptproxy with the following
> sudo nano -w /etc/apt/apt.conf.d/00aptproxy

Acquire::http::Proxy "http://<your-ip-address>:3142";

Do a software update to test it out.
> sudo apt update
> sudo apt dist-upgrade

Conclusion

Its a nice and easy setup.  The cache will work for several distros.

Howto Ubuntu 20.04 Setting up a DNS Server

Introduction

DNS is a big player on the internet.  It gives us a way to assign names to all those IP addresses out there.  This howto is going to cover installing DNS and 3 configuration examples.  Keep in mind that one server can encompass all three configurations at the same time.

Setup New Server (Optional)

I like to have dedicated DNS servers.  So you can start with a fresh server install.  Follow the HOWTO below to setup a new server.  Otherwise move on to install software.

HOWTO Ubuntu 20.04 LTS Base Server Setup

Introduction All of our servers will start with this install. This base server is based on Ubuntu 20.04 LTS Server.  I don’t explain much in the howto so if you have a question leave a comment or use Google. Downloading … Continue reading

Install Software

We will be using BIND for our DNS server.  Software is a quick install.  Type the following.
> sudo apt-get install bind9 bind9utils bind9-doc

Three DNS Configurations

I’m going to cover 3 common DNS configurations.  They are:

Caching DNS Server:
Usually a local server.  It helps speed up the DNS lookup process by storing a local cache of frequently looked up host names by clients.

Primary DNS Server:
This type of server provides authoritative answers for domains and sub domains.  Zone files contain information about the domain.

Secondary DNS Server:
This type of server is known as a slave server.  It provides redundancy to the primary DNS server.

Caching only DNS Server

Out of the box the Bind package for Ubuntu has been configured as a caching DNS server.  We can speed up lookups by forwarding them to your ISP’s DNS servers, Googles DNS server and / or other fast DNS server.  In this example I’m going to use Google’s DNS server.  We are also going to limit the clients that can use the server.

Make a backup of /etc/bind/named.conf.options
> sudo cp /etc/bind/named.conf.options /etc/bind/named.conf.options.save

Change /etc/bind/named.conf.options to look like the text below.
> sudo nano -w /etc/bind/named.conf.options

// caching only DNS server config
//
acl localclients {
  192.168.0.0/16;
  10.0.0.0/8;
  localhost;
  localnets;
};
options {
  directory "/var/cache/bind";
  recursion yes;
  allow-query { any; };
  allow-query-cache { any; };
  allow-recursion { localclients; };
  forwarders { 
    0.0.0.0;
    8.8.4.4;
  }; 
  dnssec-validation auto;
  auth-nxdomain no; # conform to RFC1035
  listen-on-v6 { any; };
};

Restart bind
> sudo service bind9 restart

Primary DNS Server

This configuration is for providing DNS for your domain name(s).  I’m only going to cover a basic domain setup.  There are a lot of configuration options for zone files.

Make a backup of /etc/bind/named.conf.options
> sudo cp /etc/bind/named.conf.options /etc/bind/named.conf.options.save

Change /etc/bind/named.conf.options to look like the text below.
> sudo nano -w /etc/bind/named.conf.options

// caching only DNS server config
//
acl localclients {
  192.168.0.0/16;
  10.0.0.0/8;
  localhost;
  localnets;
};
options {
  directory "/var/cache/bind";
  recursion yes;
  allow-query { any; };
  allow-query-cache { any; };
  allow-recursion { localclients; };
  forwarders { 
    0.0.0.0;
    8.8.4.4;
  }; 
  dnssec-validation auto;
  auth-nxdomain no; # conform to RFC1035
  listen-on-v6 { any; };
  allow-transfer { none; };
};

Edit /etc/bind/named.conf.local and add the text below.
> sudo nano -w /etc/bind/named.conf.local

zone "example.com" {
  type master;
  file "/etc/bind/db.example.com";
};

Now create /etc/bind/db.example.com and use the text below.
> sudo nano -w /etc/bind/db.example.com

$TTL 604800
@ IN SOA dns1.example.com. admin.example.com. (
          10   ; Serial
      604800   ; Refresh
       86400   ; Retry
     2419200   ; Expire
      604800 ) ; Negative Cache TTL
;

; Name servers
example.com.    IN   NS   dns1.example.com.

; A records for name servers
dns1            IN   A    192.168.1.1

; Other A records
@               IN   A    192.168.1.2
www             IN   A    192.168.1.2

Restart bind
> sudo service bind9 restart

Secondary DNS Server

This configuration is for providing DNS for your domain name(s).  I’m only going to cover a basic domain setup.  There are a lot of configuration options for zone files.

Make a backup of /etc/bind/named.conf.options
> sudo cp /etc/bind/named.conf.options /etc/bind/named.conf.options.save

Change /etc/bind/named.conf.options to look like the text below.
> sudo nano -w /etc/bind/named.conf.options

// caching only DNS server config
//
acl localclients {
  192.168.0.0/16;
  10.0.0.0/8;
  localhost;
  localnets;
};
options {
  directory "/var/cache/bind";
  recursion yes;
  allow-query { any; };
  allow-query-cache { any; };
  allow-recursion { localclients; };
  forwarders { 
    0.0.0.0;
    8.8.4.4;
  }; 
  dnssec-validation auto;
  auth-nxdomain no; # conform to RFC1035
  listen-on-v6 { any; };
  allow-transfer { none; };
};

Edit /etc/bind/named.conf.local and add the text below.
> sudo nano -w /etc/bind/named.conf.local

zone "example.com" {
  type slave;
  file "db.example.com";
  masters { 192.168.1.1; }
};

Restart bind
> sudo service bind9 restart

Conclusion

This howto was focused on configuring Bind on Ubuntu.  You will need to do research on all the options that Bind offers.

HOWTO Ubuntu 20.04 LTS Base Server Setup

Introduction

All of our servers will start with this install. This base server is based on Ubuntu 20.04 LTS Server.  I don’t explain much in the howto so if you have a question leave a comment or use Google.

Downloading the ISO

Visit the Ubuntu website and download the ubuntu 20.04 server ISO.

Initial Install

The install screens are straight forward.  I’m not going to cover them in much detail.  Unless you need to customize a setting, just choose the default settings.  Boot the install DVD.

Click ‘Reboot’ when it appears.

First boot

Reboot the machine when the install finishes.
The OS will boot. Log in. All the commands need to be run as root so lets start a shell with root privilleges.
> sudo bash

Get everything updated and install a couple of items.
> sudo apt update
> sudo apt dist-upgrade

Install and enable ssh.
> sudo apt install ssh
> sudo systemctl enable –now ssh

WARNING: My server isn’t directly connected to the internet. The firewall is disabled to help with installation, configuration and testing easier. Once everything is working, turn on the firewall and configure it. I wil remind you to secure your server at the end of this howto.

now reboot the server.

The Second Boot – Installing Additional Packages

We need quite a few other packages. In this howto I’m installing packages regardless if they were already installed by another dependency. This guards against package changes that could cause a package to not be installed. Once again log in to your server.

We need the webmin repo. Create webmin.repo with the text below.
> sudo nano -w /etc/apt/sources.list.d/webmin.list

deb http://download.webmin.com/download/repository sarge contrib

Install the webmin key.
> wget http://www.webmin.com/jcameron-key.asc
> sudo apt-key add jcameron-key.asc

Let’s add a 3rd party repo for Apache.
> add-apt-repository ppa:ondrej/apache2

Now bring everything up to date.
> sudo apt update

Install the following packages. Multiple lines to make cut and paste easier.
> sudo apt install make screen snmp composer libcurl4 unzip net-tools
> sudo apt install apache2 libapache2-mod-php7.4 mysql-server mysql-client
> sudo apt install libapache2-mod-fcgid php-opcache php-apcu

Install some extra PHP libraries.
> sudo apt install php7.4-gd php7.4-snmp php7.4-mbstring php7.4-mysql
> sudo apt install php7.4-odbc php7.4-imap
> sudo apt install php7.4-xmlrpc php7.4-dba
> sudo apt install php7.4-soap php7.4-zip php7.4-intl php7.4-curl

Now lets install webmin.
> sudo apt install webmin
> sudo systemctl enable webmin
> sudo service webmin start

Configure Apache and PHP

Enable the rewrite module.
> sudo a2enmod rewrite actions fcgid alias proxy_fcgi expires headers

Enable Apache.
> sudo systemctl enable apache2.service

Reload apache.
> sudo systemctl restart apache2.service

Configuring MySQL

Configure mysql.
> sudo mysql_secure_installation

Installing and Configuring phpMyAdmin

I prefer to phpMyAdmin to manage my MySQL databases.

Now install phpMyAdmin.
> sudo apt install phpmyadmin

Restart Apache.
> sudo systemctl restart apache2.service

Installing Postfix

Lets install postfix.
> sudo apt install postfix

When prompted select internet site. Next set the mail server name.

Installing cockpit

I’m trying cockpit as my server admin tool.  Do the following to set it up.
> sudo apt install cockpit
> sudo systemctl start cockpit
> sudo systemctl enable cockpit.socket

You can now login to https://yourserver.tld:9090 to administer your server.

Getting root’s and other’s mail

You need to get some local system user’s mail. We’ll use postfix’s virtual file to get the emails to the right place.

Add the following to /etc/postfix/virtual

root admin@yourdomain.tld
postmaster admin@yourdomain.tld
abuse admin@yourdomain.tld

Now add the configuration option to main.cf
> sudo postconf -e “virtual_alias_maps = hash:/etc/postfix/virtual”
Just a couple commands to wrap everything up.
> sudo postmap /etc/postfix/virtual
> sudo systemctl restart postfix
> sudo systemctl enable postfix

Remove Cloud Init

Our server won’t be using cloud-init.  To keep from causing you trouble in the future we will remove it now.

Type:
> sudo apt remove cloud-init cloud-initramfs-copymods cloud-initramfs-dyn-netconf

Final Settings

You may want to enable the linux firewall.
Set your timezone in /etc/php.ini

Conclusion

That’s it for the basic server setup. This is an example of a standard linux server setup. Be sure to use cockpit or webmin to set which services you want to start at boot time. See the other pages for info on configuring servers for virtual webhosting or virtual email hosting. Remember to configure the firewall on the server.

An Easy Way To Delete All Tables From A MySQL Database

Introduction

Sometimes you need to remove all the tables in a database.  For example, when you are installing or testing a web application.  There are GUI tools that can help but we are going to use the command line.

Solution

This is a two step process.

First we use mysqldump and grep to generate an sql file containing the tables to drop.  Change ‘MYDB’ to the name of the database to drop tables from.

mysqldump --add-drop-table --no-data -u root -p MYDB | grep 'DROP TABLE' > drop_tables.sql

Next use mysql CLI to execute the sql file.  Change ‘MYDB’ to the name of the database to drop tables from.

mysql -u root -p MYDB < drop_tables.sql

Conclusion

Thats it.  Straight forward and simple.

My Favorite WordPress Plugins

Introduction

This is a quick rundown of the plugins I like to use on my WordPress sites.  I do try my best not to install tons of plugins on my sites.  For the most part I use small lightweight plugins that do a specific task.

Plugins

They aren’t in any particular order.  So here’s the list.

Plugin:  404Page

You need a custom page not found.  This plugin helps take care of those 404 errors.

Plugin:  Amazon Associates Link Builder

Sorry to say my sites have ads.  This is the official plugin from Amazon.

Plugin:  Contact Form 7

I needed a few forms.  Its the plugin to use.  Seems like everyone uses it.

Plugin:  Display Posts Shortcode

I like to do easy custom posts pages.  This plugin gives me a shortcode I can use on any page.

Plugin:  Duplicator

My goto plugin for backing up and migrating my sites.

Plugin:  Easy WP Meta Description

An easy way to create meta descriptions for search engines.

Plugin:  Enhanced Media Library

Allows you to easily categorize and filter your media.

Plugin:  Flamingo

Adds storage capabilities to contact form 7.

Plugin:  Google Analytics Dashboard For WP

I don’t want to go to Google to see how my sites are doing.  This plugin puts the data I want to see in my wordpress dashboard.

Plugin:  Google XML Sitemaps

Creates sitemap for the search engines.

Plugin:  Insert Pages

This plugin provides shortcodes so I can insert posts into posts on my site.

Plugin:  Lazy Load XT

Got to load your web page fast.  This plugin loads images, youtube and iframes on your pages as they are needed.

Plugin:  Simple Cache

Well the name says it all.  A simple caching plugin for wordpress.

Plugin:  Smush

Its popular.  Optimize your images.

Plugin:  TinyMCE Advanced

Just adds some extra functionality to TinyMCE.

Plugin:  Wordfence Security

The most important plugin of them all.  Protect your site with this plugin.  There are a lot of settings to go through but protecting your site is very important.

Plugin:  wpDiscuz

Just a better comment plugin.

Plugin:  YouTube

Adds shortcodes with more options for embedding your youtube videos.

Conclusion

The above plugins have helped out my sites.  Give one a try.

HOWTO: Configure A UPS on Proxmox 5.x

Introduction

Each of my proxmox servers has its own dedicated UPS.  My servers are low power and the UPS will keep them up for at least 2 hours.  I’m using a Cyberpower UPS connected via USB.

This howto will use a Cyberpower UPS as the example.  Its very easy to make a couple changes to use another UPS.

We will be using NUT to do the heavy lifting.  When done the server will run and shutdown when the battery reaches 20%.  As a bonus notification emails will be sent as well.

Installation and configuration

SSH into your proxmox server with an account that has root privileges.

The only package to install is nut.
>sudo apt install nut

Plug in your UPS to a USB port.  We need to find the USB device information for your UPS.  So lets list our USB devices.
> lsusb

Here’s my list of USB devices.  In this example I’m interested in the Cyberpower.  Copy down the ID of your UPS.

Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID 05e3:0608 Genesys Logic, Inc. Hub
Bus 001 Device 002: ID 0764:0501 Cyber Power System, Inc. CP1500 AVR UPS
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

Create the following config file:  /etc/nut/ups.conf

maxretry = 3
[theUPS]
  driver = usbhid-ups
  port = auto
  desc = "the server UPS"

We need to create a udev rule to allow nut user access to the driver.  The ID you copied down earlier is used here so udev knows which device the rule applies to.  So create:  /etc/udev/rules.d/90-nut-ups.rules

# Rule for a Cyberpower UPS
ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="0764", ATTR{idProduct}=="0501", MODE="0660", GROUP="nut"

Now restart udev.
> sudo service udev restart

Next unplug the usb cable to the UPS and plug it back in for the rule to work.

Ok.  Its time to configure NUT to run in stand alone mode.  Replace /etc/nut/nut.conf with the following:

MODE=standalone

The ups daemon has 2 configuration files to deal with.  It needs to be configured for the ip and port to listen on.  We also create a user that can monitor the UPS.

Replace /etc/nut/upsd.conf with the following.

# LISTEN <address> [<port>]
LISTEN 127.0.0.1 3493
LISTEN ::1 3493

Replace /etc/nut/upsd.users with the following.

[upsmonitor]
password = YOUR_PASSWORD
upsmon master

The last file to configure is the UPS monitoring daemon. Replace /etc/nut/upsmon.conf with the following.

# Commands for shutdown on power loss
MONITOR theUPS@localhost 1 upsmonitor YOUR_PASSWORD master
POWERDOWNFLAG /etc/killpower
SHUTDOWNCMD "/sbin/shutdown -h now"

Enable the nut server and client services.
> sudo systemctl enable nut-server.service
> sudo systemctl enable nut-client.service

For the final step lets start the server and client services.
> service nut-server start
> service nut-client start

Conclusion

Nut is a pain to configure, but well worth it.

 

 

Creating a MySQL or MariaDB Database and User for WordPress

Introduction

These are just some quick notes on creating a mysql database and user.  This example shows how to set it up for WordPress.

The Steps

Just type the following lines.  Replace ‘dbname’, ‘username’ and ‘password’ with your values.

mysql -u root -p
CREATE DATABASE dbname;
CREATE USER 'username'@'localhost' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON dbname.* TO 'username'@'localhost';
FLUSH PRIVILEGES;
exit

 

Enable Opcache for PHP 7 and Up

Introduction

If you are running PHP 7+ on a production server then you want to enable PHP’s opcache.  Your PHP applications will receive a well deserved speed boost.

Configure PHP

This configuration example is being done on Ubuntu 18.04.  Only mod_php for Apache will have the opcache enabled.

The php.ini file has all the settings commented out.  So for Ubuntu copy the following and paste it at the end of /etc/php/7.2/apache2/php.ini

[opcache]
opcache.enable=1
opcache.validate_timestamps=1
opcache.revalidate_freq=60
opcache.memory_consumption=192
opcache.max_accelerated_files=20000
opcache.interned_strings_buffer=16
opcache.use_cwd=1
opcache.fast_shutdown=1

Now restart apache.
> systemctl restart apache2.service

Install an Opcache Status PHP Script (Optional)

If you want to see how your opcache is doing then this script will help you out.

Download the php file:
> wget https://raw.github.com/rlerdorf/opcache-status/master/opcache.php

Now copy the file into your web directory.  You can create an htaccess file limiting access to the script.

Conclusion

PHP 7’s opcache is a wonderful improvement.  Enable it.  You won’t be disappointed.

Ubuntu LTS 18.04 Base Server Setup Using Proxmox LXC Container

Introduction

All of our servers will start with this install. This base server is based on Ubuntu 18.04 LTS Server.  This setup starts with a Proxmox LXC container instead of installing from an ISO.  I don’t explain much in the howto so if you have a question leave a comment or use Google.

Downloading the Template

Login to your Proxmox server.  Navigate to the storage where you store container templates.  Click the ‘add template’ button and select and download the Ubuntu 18.04 standard template.

Create the Container

Creating an LXC container is easy.  Click the ‘Create CT’ button.  Follow the wizard entering the requested info.

First boot

Boot the container.
The container will boot. Log in. At this point there is only the root user.  So lets create a user with root privileges.  Replace MYUSER with the user name you wish to use.
> sudo useradd -m -U -s /bin/bash -c “Admin User” MYUSER
> sudo passwd MYUSER
> sudo usermod -a -G sudo MYUSER

Logout of the root account and log back in using the new user account you created.

Get everything updated and install a couple of items.
> sudo apt update
> sudo apt dist-upgrade

WARNING: My server isn’t directly connected to the internet. The firewall is disabled to help with installation, configuration and testing easier. My servers sit behind a firewall.  Once everything is working, turn on the firewall and configure it. I wil remind you to secure your server at the end of this howto.

now reboot the server.

The Second Boot – Installing Additional Packages

We need quite a few other packages. In this howto I’m installing packages regardless if they were already installed by another dependency. This guards against package changes that could cause a package to not be installed. Once again log in to your server.

Install the following packages. Multiple lines to make cut and paste easier.
> sudo apt install make screen snmp composer libcurl3 unzip
> sudo apt install apache2 php7.2-fpm libapache2-mod-php7.2 mysql-server mysql-client
> sudo apt install libapache2-mod-fcgid php7.2-opcache php-apcu

Install some extra PHP libraries.
> sudo apt install php7.2-gd php7.2-snmp php7.2-mbstring php7.2-mysql
> sudo apt install php7.2-odbc php7.2-imap
> sudo apt install php7.2-xmlrpc php7.2-dba
> sudo apt install php7.2-soap php7.2-zip php7.2-intl php7.2-curl

Configure Apache and PHP

Enable some needed modules.
> sudo a2enmod rewrite actions fcgid alias proxy_fcgi expires headers

Enable Apache.
> sudo systemctl enable apache2.service

Reload apache.
> sudo systemctl restart apache2.service

Configuring MySQL

Configure mysql.
> sudo mysql_secure_installation

Installing and Configuring phpMyAdmin

I prefer to phpMyAdmin to manage my MySQL databases.

Now install phpMyAdmin.
> sudo apt install phpmyadmin

Restart Apache.
> sudo systemctl restart apache2.service

Getting root’s and other’s mail

You need to get some local system user’s mail. We’ll use postfix’s virtual file to get the emails to the right place.

Add the following to /etc/postfix/virtual

root admin@yourdomain.tld
postmaster admin@yourdomain.tld
abuse admin@yourdomain.tld

Now add the configuration option to main.cf
> sudo postconf -e “virtual_alias_maps = hash:/etc/postfix/virtual”
Just a couple commands to wrap everything up.
> sudo postmap /etc/postfix/virtual
> sudo systemctl enable postfix
> sudo systemctl restart postfix

Final Settings

You may want to enable the linux firewall.  You can also use the Proxmox firewall.
Set your timezone in /etc/php.ini

Conclusion

That’s it for the basic server setup. This is an example of a standard linux server setup. See my other pages for info on configuring servers for virtual webhosting or virtual email hosting.

Fix phpMyAdmin and PHP 7.2 Issues on Ubuntu 18.04

Introduction

The version of phpmyadmin for ubuntu doesn’t play nice with php 7.2.  The problems were fixed in newer versions of phpmyadmin.

The Fix

Just a few steps and things will be fixed.

First visit www.phpmyadmin.net and download the latest version. My example is version 4.8.1.
> cd /tmp
> wget https://files.phpmyadmin.net/phpMyAdmin/4.8.1/phpMyAdmin-4.8.1-all-languages.zip

Unzip and rename the folder.
> unzip phpMyAdmin-4.8.1-all-languages.zip
> mv phpMyAdmin-4.8.1-all-languages phpmyadmin

Backup the old version of phpmyadmin and move over the new version.
> mv /usr/share/phpmyadmin /usr/share/phpmyadmin.save
> mv phpmyadmin /usr/share/

Edit /usr/share/phpmyadmin/libraries/vendor_config.php and make the following change.

Change

define('CONFIG_DIR', '');

to

define('CONFIG_DIR', '/etc/phpmyadmin/');

That’s it.

Conclusion

This is a bug that will eventually get fixed.

HOWTO Virtual Mail Hosting on CentOS 6.x – Postfix MySQL Dovecot PostfixAdmin Amavisd-new Spamassassin Clamav

Introduction

First things first. If you are a novice at linux I recommend that you should get help with setting this up. This is an advanced email server configuration. This configuration will allow you to serve multiple domains on one server. This howto will allow you to setup a server that is one of four mail server types:

  • Mail server with spam and virus checking (Most people. Do everything in the howto)
  • Mail server w/o spam and virus checking (Someone else is doing email filtering for you)
  • Backup MX / spam and virus filtering server (you want to divide things up)
  • Backup MX (You want to receive and hold mail while your main server is down)

You will get the following features:

  • Postfix: the workhorse behind the mail receiving and sending
  • smtp authentication
  • secure smtp using TLS
  • Dovecot: imap and pop3 mailbox service
  • secure imap and pop3
  • server side filtering of flagged spam to a spam folder
  • mysql: handle all the virtual domains and users
  • PostfixAdmin: GUI for domain administration
  • roundcube: web mail access
  • spam/virus filtering using amavisd-new, spamassassin and clamav

Installing CentOS

Start with my HOWTO: CentOS 6.x base server. That howto will get CentOS installed and ready for this howto.

WARNING: Not following the base server howto will cause you grief. Due to 6.4+ changes things will break.

Installing The Software

We’ll start with the yum installs.
> yum install roundcubemail dovecot dovecot-mysql dovecot-pigeonhole cyrus-sasl-devel cyrus-sasl-sql subversion
> yum install perl-MailTools perl-MIME-EncWords perl-MIME-Charset perl-Email-Valid perl-Test-Pod perl-TimeDate
> yum install perl-Mail-Sender perl-Log-Log4perl imapsync offlineimap
> yum install amavisd-new clamav clamd razor-agents perl-Convert-BinHex

Postfix.Admin doesn’t have an rpm so we need to download it and put it where we want it.
> wget http://sourceforge.net/projects/postfixadmin/files/latest/download
> tar -xzvf postfixadmin-2.3.5.tar.gz
> mv postfixadmin-2.3.5 /usr/share/postfixadmin

Configuring The Server

Setup SSL Certificate

Now generate an SSL certificate for postfix and dovecot to have TLS support. Replace mail.example.com with your server hostname.
> genkey –days 3650 mail.example.com

Setup the Virtual Mail User

Next we’ll configure the mail store directory. We put it in the /home directory to make backups and other item easy. So type the following.
> mkdir /home/vmail
> chmod 770 /home/vmail
> useradd -r -u 101 -g mail -d /home/vmail -s /sbin/nologin -c “Virtual mailbox” vmail
> chown vmail:mail /home/vmail

Configuring Postfix Admin

Create the apache config file for postfixadmin and restart apache.
/etc/httpd/conf.d/postfixadmin.conf

 
alias /mailadmin /usr/share/postfixadmin
<Directory "/usr/share/postfixadmin">
  AllowOverride AuthConfig
</Directory>

> service httpd restart

Now we need to setup the mysql database for postfixadmin. We only need to create the database and user. The setup file will create the rest.
> mysql -u root -p -e “CREATE DATABASE postfix;”
> mysql -u root -p -e “CREATE USER postfix@localhost IDENTIFIED BY ‘choose_a_password’;”
> mysql -u root -p -e “GRANT ALL PRIVILEGES ON postfix . * TO postfix@localhost;”

Now its time to setup the config file. Don’t forget to set your password. Paste the following into the file.
> cd /usr/share/postfixadmin
> nano -w config.local.php

 
<?php
/** 
 * Contains configuration options that override the default config file
 */

/*****************************************************************
 *  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
 * You have to set $CONF['configured'] = true; before the
 * application will run!
 * Doing this implies you have changed this file as required.
 * i.e. configuring database etc; specifying setup.php password etc.
 */
$CONF['configured'] = true;

// In order to setup Postfixadmin, you MUST specify a hashed password here.
// To create the hash, visit setup.php in a browser and type a password into the field,
// on submission it will be echoed out to you as a hashed value.
$CONF['setup_password'] = 'changeme';
$CONF['postfix_admin_url'] = '/mailadmin';
$CONF['database_type'] = 'mysql';
$CONF['database_host'] = 'localhost';
$CONF['database_user'] = 'postfix';
$CONF['database_password'] = 'changeme';
$CONF['database_name'] = 'postfix';
$CONF['admin_email'] = 'postmaster@change-this-to-your.domain.tld';
$CONF['encrypt'] = 'md5crypt';
$CONF['dovecotpw'] = "/usr/sbin/dovecotpw";
$CONF['min_password_length'] = 6;
$CONF['page_size'] = '20';
$CONF['domain_path'] = 'YES';
$CONF['domain_in_mailbox'] = 'NO';
$CONF['aliases'] = '50';
$CONF['mailboxes'] = '50';
$CONF['maxquota'] = '100';
$CONF['quota'] = 'YES';
$CONF['quota_multiplier'] = '1024000';
$CONF['transport'] = 'YES';
$CONF['transport_options'] = array (
    'virtual',  // for virtual accounts
    'local',    // for system accounts
    'relay'     // for backup mx
);
$CONF['transport_default'] = 'virtual';
$CONF['vacation'] = 'YES';
$CONF['vacation_domain'] = 'autoreply.change-this-to-your.domain.tld';
$CONF['vacation_control'] ='YES';
$CONF['vacation_control_admin'] = 'YES';
$CONF['special_alias_control'] = 'YES';
$CONF['user_footer_link'] = "http://change-this-to-your.domain.tld/main";
$CONF['show_footer_text'] = 'YES';
$CONF['footer_text'] = 'Return to change-this-to-your.domain.tld';
$CONF['footer_link'] = 'http://change-this-to-your.domain.tld';
$CONF['create_mailbox_subdirs']=array('Drafts','Spam','Sent','Trash');
$CONF['create_mailbox_subdirs_host']='localhost';
$CONF['create_mailbox_subdirs_prefix']='';
$CONF['used_quotas'] = 'YES';
$CONF['new_quota_table'] = 'YES';
// $CONF['create_mailbox_subdirs_hostoptions']=array('notls');
$CONF['create_mailbox_subdirs_hostoptions']=array('novalidate-cert','norsh');

//
// END OF CONFIG FILE
//

Next we need to run the setup.php script in a web browser. Enter the url in your browser. Ex.
http://yourdomain.tld/mailadmin/setup.php

If everything shows OK then create the admin user using the form displayed. Follow the instructions for setting the setup password.

Log into the web interface and follow the directions.
http://yourdomain.tld/mailadmin/

Configuring Postfix

Here we go with more config files. You’ll have to be sure to change some settings to match your host. The config files will have sections commented out. Don’t worry about it. These sections are for spam/virus/sympa configuration. Just copy and past to create the config files. What ever you see here replaces what already exists.

The main postfix config files.
/etc/postfix/main.cf

 
# postfix config file

# uncomment for debugging if needed
#soft_bounce=yes

# postfix main
mail_owner = postfix
setgid_group = postdrop
delay_warning_time = 4

# postfix paths
html_directory = no
command_directory = /usr/sbin
daemon_directory = /usr/libexec/postfix
queue_directory = /var/spool/postfix
sendmail_path = /usr/sbin/sendmail.postfix
newaliases_path = /usr/bin/newaliases.postfix
mailq_path = /usr/bin/mailq.postfix
manpage_directory = /usr/share/man

# network settings
inet_interfaces = all
mydomain = yourdomain.com
myhostname = host.yourdomain.com
mynetworks = $config_directory/mynetworks
mydestination = $myhostname, localhost.$mydomain, localhost 
relay_domains = proxy:mysql:/etc/postfix/mysql-relay_domains_maps.cf

# mail delivery
recipient_delimiter = + 

# mappings
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
transport_maps = hash:/etc/postfix/transport
#local_recipient_maps = 

# virtual setup
virtual_alias_maps = proxy:mysql:/etc/postfix/mysql-virtual_alias_maps.cf,
                     regexp:/etc/postfix/virtual_regexp
virtual_mailbox_base = /home/vmail
virtual_mailbox_domains = proxy:mysql:/etc/postfix/mysql-virtual_domains_maps.cf
virtual_mailbox_maps = proxy:mysql:/etc/postfix/mysql-virtual_mailbox_maps.cf
virtual_mailbox_limit_maps = proxy:mysql:/etc/postfix/mysql-virtual_mailbox_limit_maps.cf
virtual_minimum_uid = 101
virtual_uid_maps = static:101
virtual_gid_maps = static:12
virtual_transport = dovecot
dovecot_destination_recipient_limit = 1

# debugging
debug_peer_level = 2
debugger_command =
         PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin
         xxgdb $daemon_directory/$process_name $process_id & sleep 5

# authentication
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
smtpd_sasl_local_domain = $myhostname
broken_sasl_auth_clients = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth

# tls config
smtp_use_tls = yes
smtpd_use_tls = yes 
smtpd_tls_security_level = may
smtpd_tls_loglevel = 1
smtpd_tls_received_header = yes
smtpd_tls_session_cache_timeout = 3600s
tls_random_source = dev:/dev/urandom
smtp_tls_session_cache_database = btree:$data_directory/smtp_tls_session_cache
# Change mail.example.com.* to your host name 
smtpd_tls_key_file = /etc/pki/tls/private/mail.example.com.key
smtpd_tls_cert_file = /etc/pki/tls/certs/mail.example.com.crt
# smtpd_tls_CAfile = /etc/pki/tls/root.crt

# rules restrictions 
smtpd_client_restrictions = 
smtpd_helo_restrictions = 
smtpd_sender_restrictions = 
smtpd_recipient_restrictions = permit_sasl_authenticated, 
        permit_mynetworks, 
        reject_unauth_destination,
	reject_non_fqdn_sender,
        reject_non_fqdn_recipient, 
        reject_unknown_recipient_domain
# uncomment for realtime black list checks
#	,reject_rbl_client zen.spamhaus.org
#	,reject_rbl_client bl.spamcop.net
#	,reject_rbl_client dnsbl.sorbs.net

smtpd_helo_required = yes
unknown_local_recipient_reject_code = 550
disable_vrfy_command = yes
smtpd_data_restrictions = reject_unauth_pipelining

# Other	options
# email	size limit ~20Meg
message_size_limit = 204800000

/etc/postfix/master.cf

 
#
# Postfix master process configuration file.  For details on the format
# of the file, see the Postfix master(5) manual page.
#
# ***** Unused items removed *****
# ==========================================================================
# service type  private unpriv  chroot  wakeup  maxproc command + args
#               (yes)   (yes)   (yes)   (never) (100)
# ==========================================================================
smtp      inet  n       -       n       -       -       smtpd
#  -o content_filter=smtp-amavis:127.0.0.1:10024
#  -o receive_override_options=no_address_mappings
pickup    fifo  n       -       n       60      1       pickup
  -o content_filter= 
  -o receive_override_options=no_header_body_checks
cleanup   unix  n       -       n       -       0       cleanup
qmgr      fifo  n       -       n       300     1       qmgr
#qmgr     fifo  n       -       n       300     1       oqmgr
tlsmgr    unix  -       -       n       1000?   1       tlsmgr
rewrite   unix  -       -       n       -       -       trivial-rewrite
bounce    unix  -       -       n       -       0       bounce
defer     unix  -       -       n       -       0       bounce
trace     unix  -       -       n       -       0       bounce
verify    unix  -       -       n       -       1       verify
flush     unix  n       -       n       1000?   0       flush
proxymap  unix  -       -       n       -       -       proxymap
smtp      unix  -       -       n       -       -       smtp
# When relaying mail as backup MX, disable fallback_relay to avoid MX loops
relay     unix  -       -       n       -       -       smtp
        -o fallback_relay=
#       -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
showq     unix  n       -       n       -       -       showq
error     unix  -       -       n       -       -       error
discard   unix  -       -       n       -       -       discard
local     unix  -       n       n       -       -       local
virtual   unix  -       n       n       -       -       virtual
lmtp      unix  -       -       n       -       -       lmtp
anvil     unix  -       -       n       -       1       anvil
scache    unix  -       -       n       -       1       scache
#
# ====================================================================
# Interfaces to non-Postfix software. Be sure to examine the manual
# pages of the non-Postfix software to find out what options it wants.
# ====================================================================
maildrop  unix  -       n       n       -       -       pipe
  flags=DRhu user=vmail argv=/usr/local/bin/maildrop -d ${recipient}
uucp      unix  -       n       n       -       -       pipe
  flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
ifmail    unix  -       n       n       -       -       pipe
  flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
bsmtp     unix  -       n       n       -       -       pipe
  flags=Fq. user=foo argv=/usr/local/sbin/bsmtp -f $sender $nexthop $recipient
#
# spam/virus section
#
smtp-amavis  unix  -    -       y       -       2       smtp
  -o smtp_data_done_timeout=1200
  -o disable_dns_lookups=yes
  -o smtp_send_xforward_command=yes
127.0.0.1:10025 inet n  -       y       -       -       smtpd
  -o content_filter=
  -o smtpd_helo_restrictions=
  -o smtpd_sender_restrictions=
  -o smtpd_recipient_restrictions=permit_mynetworks,reject
  -o mynetworks=127.0.0.0/8
  -o smtpd_error_sleep_time=0
  -o smtpd_soft_error_limit=1001
  -o smtpd_hard_error_limit=1000
  -o receive_override_options=no_header_body_checks
  -o smtpd_bind_address=127.0.0.1
  -o smtpd_helo_required=no
  -o smtpd_client_restrictions=
  -o smtpd_restriction_classes=
  -o disable_vrfy_command=no
  -o strict_rfc821_envelopes=yes
#
# Dovecot LDA
dovecot   unix  -       n       n       -       -       pipe
  flags=DRhu user=vmail:mail argv=/usr/libexec/dovecot/deliver -d ${recipient}
#
# Vacation mail
vacation    unix  -       n       n       -       -       pipe
  flags=Rq user=vacation argv=/var/spool/vacation/vacation.pl -f ${sender} -- ${recipient}

/etc/postfix/mynetworks

 
# This specifies the list of subnets that Postfix considers as
# "trusted" SMTP clients that have more privileges than "strangers".
#
# In particular, "trusted" SMTP clients are allowed to relay mail
# through Postfix.
#
# Be sure to add your public ip address block if needed.
#
192.168.0.0/16
10.0.0.0/8
127.0.0.0/8

The postfix / mysql config files.
/etc/postfix/mysql-virtual_alias_maps.cf

 
hosts = localhost
user = postfix
password = postfix
dbname = postfix
query = SELECT goto FROM alias WHERE address='%s' AND active = '1'

/etc/postfix/mysql-virtual_domains_maps.cf

 
hosts = localhost
user = postfix
password = postfix
dbname = postfix
query = SELECT domain FROM domain WHERE domain='%s' AND backupmx = '0' AND active = '1'

/etc/postfix/mysql-relay_domains_maps.cf

 
hosts = localhost
user = postfix
password = postfix
dbname = postfix
query = SELECT domain FROM domain WHERE domain='%s' and backupmx = '1'

/etc/postfix/mysql-virtual_mailbox_maps.cf

 
hosts = localhost
user = postfix
password = postfix
dbname = postfix
query = SELECT maildir FROM mailbox WHERE username='%s' AND active = '1'

/etc/postfix/mysql-virtual_mailbox_limit_maps.cf

 
hosts = localhost
user = postfix
password = postfix
dbname = postfix
query = SELECT quota FROM mailbox WHERE username='%s' AND active = '1'

We need to touch a file. So type the follwoing.
> touch /etc/postfix/virtual_regexp

Configure Vacation Email Functionallity

Lets finish the postfix configuration with vacation mail. Don’t forget to fill in your domain name where needed. Type the following:
> useradd -r -d /var/spool/vacation -s /sbin/nologin -c “Virtual vacation” vacation
> mkdir /var/spool/vacation
> chmod 770 /var/spool/vacation
> cp /usr/share/postfixadmin/VIRTUAL_VACATION/vacation.pl /var/spool/vacation/
> echo “autoreply.yourdomain.com vacation:” > /etc/postfix/transport
> postmap /etc/postfix/transport
> chown -R vacation:vacation /var/spool/vacation
> echo “127.0.0.1 autoreply.yourdomain.com” >> /etc/hosts
> mkdir /etc/postfixadmin

Create /etc/postfixadmin/vacation.conf with the following:

 
# ========== begin configuration ==========
$db_type = 'mysql';
$db_username = 'user';
$db_password = 'password';    
$db_name     = 'postfix';    
$vacation_domain = 'autoreply.example.org';  

Configuring Dovecot

Now for the dovecot config file. Dovecot now uses multiple config files to break things up. We’re going to only use a couple config files. So cut and paste the following files.
> mv /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf.save
> nano -w /etc/dovecot/dovecot.conf

 
##
## Dovecot config file
##

protocols = imap pop3 lmtp sieve
auth_mechanisms = plain login
passdb {
  driver = sql
  args = /etc/dovecot/dovecot-mysql.conf
}
userdb {
  driver = prefetch
}
userdb {
  driver = sql
  args = /etc/dovecot/dovecot-mysql.conf
}
mail_location = maildir:/home/vmail/%d/%n
first_valid_uid = 101
#last_valid_uid = 0
first_valid_gid = 12
#last_valid_gid = 0
#mail_plugins =
mailbox_idle_check_interval = 30 secs
maildir_copy_with_hardlinks = yes
service imap-login {
  inet_listener imap {
    port = 143
  }
  inet_listener imaps {
    port = 993
    ssl = yes
  }
}
service pop3-login {
  inet_listener pop3 {
    port = 110
  }
  inet_listener pop3s {
    port = 995
    ssl = yes
  }
}
service lmtp {
  unix_listener lmtp {
    #mode = 0666
  }
}
service imap {
  vsz_limit = 256M
}
service pop3 {
}
service auth {
  unix_listener auth-userdb {
    mode = 0666
    user = vmail
    group = mail
  }

  # Postfix smtp-auth
  unix_listener /var/spool/postfix/private/auth {
    mode = 0666
    user = postfix
    group = postfix
  }
}
service auth-worker {
}
service dict {
  unix_listener dict {
    mode = 0666
    user = vmail
    group = mail
  }
}
service managesieve-login {
  inet_listener sieve {
    port = 4190
  }
  service_count = 1
  process_min_avail = 0
  vsz_limit = 64M
}
service managesieve {
}
ssl = yes
ssl_cert = </etc/pki/tls/certs/your-server.your-domain.tld.crt 
ssl_key = </etc/pki/tls/private/your-server.your-domain.tld.key
ssl_verify_client_cert = no
#ssl_ca =
lda_mailbox_autocreate = yes         
lda_mailbox_autosubscribe = yes
protocol lda {
  mail_plugins = quota sieve
  postmaster_address = postmaster@your-domain.tld
}  
protocol imap {
  mail_plugins = quota imap_quota trash
  imap_client_workarounds = delay-newmail
}
lmtp_save_to_detail_mailbox = yes
protocol lmtp {
  mail_plugins = sieve
}
protocol pop3 {
  mail_plugins = quota
  pop3_client_workarounds = outlook-no-nuls oe-ns-eoh
}
protocol sieve {
  managesieve_max_line_length = 65536
  managesieve_implementation_string = Dovecot Pigeonhole
  managesieve_max_compile_errors = 5
}
dict {
  quotadict = mysql:/etc/dovecot/dovecot-dict-quota.conf
}
plugin {
  quota = dict:user::proxy::quotadict
  acl = vfile:/etc/dovecot/acls
  trash = /etc/dovecot/trash.conf
  sieve_global_path = /home/sieve/globalfilter.sieve
  sieve = ~/dovecot.sieve
  sieve_dir = ~/sieve
  sieve_global_dir = /home/sieve/
  #sieve_extensions = +notify +imapflags
  sieve_max_script_size = 1M
  #sieve_max_actions = 32
  #sieve_max_redirects = 4
}


Now for trash.conf
> nano -w /etc/dovecot/trash.conf

 
1 Spam
# Uncomment if you want trash as well
# 2 Trash

Next we configure Dovecot to access mysql. Create the following file.
NOTE: password_query and user_query were formatted to fit on the webpage. Each one should only be one line in the file.
/etc/dovecot/dovecot-mysql.conf

 
driver = mysql
connect = host=localhost dbname=postfix user=postfix password=yourpassword
default_pass_scheme = MD5-CRYPT

# following should all be on one line.
password_query = SELECT username as user, password, concat('/home/vmail/', maildir) as userdb_home, 
concat('maildir:/home/vmail/', maildir) as userdb_mail, 101 as userdb_uid, 12 as userdb_gid FROM mailbox 
WHERE username = '%u' AND active = '1'

# following should all be on one line
user_query = SELECT concat('/home/vmail/', maildir) as home, concat('maildir:/home/vmail/', maildir) as mail, 
101 AS uid, 12 AS gid, CONCAT('*:messages=10000:bytes=', quota) as quota_rule FROM mailbox WHERE 
username = '%u' AND active = '1'

and /etc/dovecot/dovecot-dict-quota.conf

 
connect = host=localhost dbname=postfix user=postfix password=password
map {
  pattern = priv/quota/storage
  table = quota2
  username_field = username
  value_field = bytes
}
map {
  pattern = priv/quota/messages
  table = quota2
  username_field = username
  value_field = messages
}

Finally set Dovecot to boot at startup.

Now Create the sieve filter for SPAM filtering.
> mkdir /home/sieve
> nano -w /home/sieve/globalfilter.sieve
> chown -R vmail:mail /home/sieve

 
require "fileinto";
  if exists "X-Spam-Flag" {
          if header :contains "X-Spam-Flag" "NO" {
          } else {
          fileinto "Spam";      
          stop;
	  }
  }
  if header :contains "subject" ["***SPAM***"] {
    fileinto "Spam";      
    stop;
  }

Configuring Roundcube mail

Edit the roundcube apache config file to look like the following:
>nano -w /etc/httpd/conf.d/roundcubemail.conf

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

# Force https here instead of in Round Cube 
RewriteEngine On

# This checks to make sure the connection is not already HTTPS
RewriteCond %{HTTPS} !=on 

# These rules will redirect all users who are using any part of /secure/ to the same location but using HTTPS.
# i.e.  http://www.example.com/secure/ to https://www.example.com/secure/
RewriteRule ^/?roundcubemail/(.*) https://%{SERVER_NAME}/roundcubemail/$1 [R,L]
RewriteRule ^/?webmail/(.*) https://%{SERVER_NAME}/webmail/$1 [R,L]

Alias /roundcubemail /usr/share/roundcubemail
Alias /webmail /usr/share/roundcubemail

<Directory /usr/share/roundcubemail/>
        Order Deny,Allow
        Deny from all
        Allow from all
        php_value suhosin.session.encrypt Off 
</Directory>

Create the database for roundcube.
> mysql -u root -p -e “CREATE DATABASE roundcubemail;”
> mysql -u root -p -e “GRANT ALL PRIVILEGES ON roundcubemail.* TO roundcube@localhost IDENTIFIED BY ‘password’;”

Create the tables.
> mysql -u root -p roundcubemail < /usr/share/doc/roundcubemail-0.5.4/SQL/mysql.initial.sql

Edit /etc/roundcubemail/db.inc.php and find the line:

 
$rcmail_config['db_dsnw'] = 'mysql://roundcube:pass@localhost/roundcubemail';

Change ‘pass’ to your passowrd.

Edit /etc/roundcubemail/main.inc.php and find the lines and make the changes below:

find:

 
$rcmail_config['default_host'] = '';

change to:

 
$rcmail_config['default_host'] = 'localhost';

find:

 
$rcmail_config['smtp_server'] = '';

change to:

 
$rcmail_config['smtp_server'] = 'localhost';

find:

 
$rcmail_config['force_https'] = false;

change to:

 
$rcmail_config['force_https'] = true;

find:

 
$rcmail_config['plugins'] = array();

change to:

 
$rcmail_config['plugins'] = array('managesieve');

find:

 
$rcmail_config['quota_zero_as_unlimited'] = false;

change to:

 
$rcmail_config['quota_zero_as_unlimited'] = true;

Now lets configure the manage sieve plugin.
> cd /usr/share/roundcubemail/plugins/managesieve/
> cp config.inc.php.dist config.inc.php

Edit config.inc.php and change the following:

 
$rcmail_config['managesieve_port'] = 2000;

to:

 
$rcmail_config['managesieve_port'] = 4190;

Restart apache.
> service httpd restart

Configuring the Little Things That Drive You MAD

Be sure your /etc/hosts looks similar to the following.

 
# Do not remove the following line, or various programs
# that require network functionality will fail.
127.0.0.1       localhost
192.168.11.21   host.domain.com

Preparing and Testing the Postoffice

First things first. Reboot the system. If everything went well we all should be at the same point.

No errors? Lets keep going.

Setup a test domain and account. Setup your favorit mail client and send some test emails.

Setting up Spam and Virus Filtering (Optional)

Lets cover installing and configuring spam and virus filtering. Optional? Huh? Some people use a 3rd party or use a seperate server for filtering.

Here’s the clamav config file. Replace /etc/clamd.conf with the following:

##
## Cconfig file for the Clam AV daemon
## Please read the clamd.conf(5) manual before editing this file.
##

# Logfile
LogFile /var/log/clamav/clamd.log
LogFileMaxSize 20M
LogTime yes
LogSyslog yes

# Pid
PidFile /var/run/clamav/clamd.pid

# Paths
TemporaryDirectory /var/tmp
DatabaseDirectory /var/clamav
LocalSocket /var/run/clamav/clamd

# Sets the group ownership on the unix socket.
# Default: disabled (the primary group of the user running clamd)
#LocalSocketGroup virusgroup

# Misc
FixStaleSocket yes
TCPSocket 3310
TCPAddr 127.0.0.1
MaxConnectionQueueLength 50
MaxThreads 50
ReadTimeout 240
User clamav
AllowSupplementaryGroups yes

# Exe
ScanPE yes
ScanELF yes
DetectBrokenExecutables yes

# Docs
ScanOLE2 yes
ScanPDF yes

# Mail
ScanMail yes
PhishingSignatures yes
PhishingScanURLs yes

# Data Loss Prevention (DLP)

# Enable the DLP module
# Default: No
#StructuredDataDetection yes

# This option sets the lowest number of Credit Card numbers found in a file
# to generate a detect.
# Default: 3
#StructuredMinCreditCardCount 5

# This option sets the lowest number of Social Security Numbers found
# in a file to generate a detect.
# Default: 3
#StructuredMinSSNCount 5

# With this option enabled the DLP module will search for valid
# SSNs formatted as xxx-yy-zzzz
# Default: yes
#StructuredSSNFormatNormal yes

# With this option enabled the DLP module will search for valid
# SSNs formatted as xxxyyzzzz
# Default: no
#StructuredSSNFormatStripped yes

# Archives
ScanArchive yes
ArchiveBlockEncrypted no

Configure Razor. Type the following:
> razor-admin -register -user=some_user -pass=somepas

Update and restart clamav:
> freshclam
> service clamd restart

Configuring Amavisd-new

You need to edit /etc/amavisd.conf
Here is a list of items you should change. just scroll through the file to find each item.

  • $mydomain = ‘example.com’; # set to your domain name
  • $log_level = 1; # set the log leve to one
  • $sa_tag_level_deflt = -99; # i want to see the headers so change to -99
  • $sa_tag2_level_deflt = 5.0; # start with 5
  • $sa_kill_level_deflt = 9; # change to 9
  • $sa_dsn_cutoff_level = 9; # change to 9
  • $sa_quarantine_cutoff_level = 50; # remove the starting # and change to 50
  • $myhostname = ‘lightning.campworld.net’; # remove the starting # and enter your host name
  • $notify_method = ‘smtp:[127.0.0.1]:10025’; # uncomment the line
  • $forward_method = ‘smtp:[127.0.0.1]:10025’; # uncomment the line
  • $final_banned_destiny = D_DISCARD; # change to D_DISCARD

Now enable clamav:
Change the following:

# ### http://www.clamav.net/
# ['ClamAV-clamd',
#   \&ask_daemon, ["CONTSCAN {}\n", "/var/run/clamav/clamd"],
#   qr/\bOK$/m, qr/\bFOUND$/m,
#   qr/^.*?: (?!Infected Archive)(.*) FOUND$/m ],

to

 ### http://www.clamav.net/
 ['ClamAV-clamd',
   \&ask_daemon, ["CONTSCAN {}\n", "/var/run/clamav/clamd"],
   qr/\bOK$/m, qr/\bFOUND$/m,
   qr/^.*?: (?!Infected Archive)(.*) FOUND$/m ],

Now update spamassassin and start amavisd-new.
> sa-update
> service amavisd-new start

Be sure to set amavisd-new to start at boot.

Telling Postfix to Start Filtering SPAM

To get postfix going we need to un-comment a couple lines in /etc/postfix/master.cf
Find:

smtp      inet  n       -       n       -       -       smtpd
#  -o content_filter=smtp-amavis:127.0.0.1:10024
#  -o receive_override_options=no_address_mappings

Change to:

smtp      inet  n       -       n       -       -       smtpd
  -o content_filter=smtp-amavis:127.0.0.1:10024
  -o receive_override_options=no_address_mappings

Restart postfix and you’re done.

Using The Roundcubemail Password Plugin (Optional)

Let your users change their password using roundcubemail instead of postfixadmin.

Edit /etc/roundcubemail/main.inc.php and find the lines and make the changes below:

find:

$rcmail_config['plugins'] = array('managesieve');

change to:

$rcmail_config['plugins'] = array('managesieve','password');

Now lets configure the password plugin.
> cd /usr/share/roundcubemail/plugins/password/
> cp config.inc.php.dist config.inc.php

Edit config.inc.php

find:

$rcmail_config['password_db_dsn'] = '';

change to:

$rcmail_config['password_db_dsn'] = 'mysql://postfix:your-postfixadmin-password@localhost/postfix';

find:

$rcmail_config['password_query'] = 'SELECT update_passwd(%c, %u)';

change to:

$rcmail_config['password_query'] = 'UPDATE mailbox SET password=%c WHERE username=%u limit 1;';

Restart apache.
> service httpd restart

Notes About Security And Clear Text Passwords From Mail Clients

My howto has been written to allow clear text passwords. This can and does cause security problem of sending of clear text passwords through the internet. This covers sending of the password from the client to the server. Passwords are stored in the database encrypted.

The configuration doesn’t require clients to use SSL/TLS. If you use SSL/TLS then the passwords are encrypted in the SSL connection. POPS, IMAPS and SMTPS all use SSL/TLS connection. So as long as your client supports secure connections to the mail server your clear text passwords will be secure.

Conclusion

With a bit of work you come out with a robust server.