Author Topic: How-To: Script for WebServer vhost modification and custom SSL certificates  (Read 2792 times)

BrandonSk

  • Zen Apprentice
  • *
  • Posts: 12
  • Karma: +3/-0
    • View Profile
[Admins, please feel to move the elsewhere, if appropriate]

Dear all,

after a lot of reading and experimenting, I decided to create my own hook script for webserver module. This script will take care of pretty much any custom directives you want to do with your virtual host, but main purpose of the script remains to allow for custom SSL certificates to be used with your virtual hosts.

If something like this already exists, I apologise, but I haven’t found it. And until we get a decent webserver module in the GUI, this is for me the ultimate solution.

Legal: Use at your own risk :) It works fine for me. And although I tried to prevent errors caused by spaces in filenames, etc., you would be best of to follow “proper” naming conventions for linux and nothing crazy.

Quality: I am no shell script programmer. I did few small scripts and what is included below is often bits and pieces I gather from forums, just to get the specific task done (especially the SED magics, which some of I still do not understand, but they work :D )
I also perhaps use too many variables, but I tried to make the code easy to follow through but most of all, if some path changes, to allow modification of just 1 variable at the beginning without updating the entire script.

Feel free to modify the script, if you find errors. I only ask you not to keep it for yourself, but share with others.

Enough of talking, here comes read me:
Installation:
  • Place the script in /etc/zentyal/hooks directory
  • Adjust permissions, so that it matches the other examples in that directory.
  • Script must be named webserver.postsetconf

Usage:
Define your input directory for your custom configurations (default /etc/apache2/custom-configs)
You must create sub-directory for each virtualhost where you want to use custom config, The sub-directory must have exactly the same name as your vhost in WebServer GUI.
(e.g. if your vhost is www.example.com, you create directory /etc/apache2/custom-configs/www.example.com)

In this directory this gets processed:
  • If file common.conf (name can be modified in script) exists, this file will be copied to /etc/apache2/sites-availbale/user-ebox-www.example.com/custom.conf and thus directives in this file will be used for both http and https. Good thing to place in such file is ServerAlias directive.
  • If file ssl.conf (name can be modified in script) exists, this file will be copied to /etc/apache2/sites-availbale/user-ebox-ssl-www.example.com/custom-ssl.conf and directives in this file will be used only for https. Good thing to place in such file is SSLEngine on directive.
  • Next the input vhost directory is scanned for files with extensions *.crt, *.key, *.ca.pem If found, the particular file is copied to /etc/apache2/ssl/www.example.com/ directory and permissions fixed to 400. Also corresponding directives are added to the custom-ssl.conf file from step #2.
    *.CRT - it is expected it is the custom SSL certificate you want to use
    *.KEY - the private key file to the certificate
    *.CA.PEM - chain file to your certificate authority
    IMPORTANT! Script only processes first file it founds with given extension, so make sure you only place 1 of each type in the folder.
    Note: The above three files are required for SSL certificates from Startssl.com. I saw somewhere that people were adding also the ca.pem file. Script does not support it at the moment, but if needed, it can be quickly added. Just let me know.
  • Finally script checks and fixes the missing “Include …” directive for VirtualHost *:80 (if ForceSSL is used) and adds another “Include…” directive to VirtualHost *:443 to load custom SSL file.
So what else to say… Enjoy. I hope it will work for you just as well as it does for me!

Cheers,
B.

Script (also attached as file):
Code: [Select]
#!/bin/bash

# You can change these (please observe and keep trailing / where it is by default!):
cust_conf="/etc/apache2/custom-configs/"        # Where the directories per vhost with custom conf and ssl files will be
f_input_common="common.conf"            # Filename which contains options for both - http and https (e.g. ServerAlias)
f_input_ssl="ssl.conf"                  # File which contains directives specific to https part of config (e.g. SSLProtocol)
# If you want to use SSL, you must have 'SSLEngine on' in this file!
# in the input dir, you should also have *.crt, *.key and *.ca.pem files if you have a custom SSL certificate

# INPUTS (some are populated later in the code)
d_input_dir="" # Input directory which contains input files

# OUTPUTS
sites_path="/etc/apache2/sites-available"
d_custom_ssl_conf="" # (in code) something like $sites_path/user-ebox-ssl-www.example.com
f_custom_ssl_filename="custom-ssl.conf" # Output File which will contain the SSL configuration (in above direcotry)
d_custom_conf="" # (in code) points to custom config dir e.g. $sites_path/user-ebox-www.example.com
f_custom_conf="custom.conf" # Output file that will contain custom conf for common for http and https
d_cert_path="/etc/apache2/ssl" # Where the ssl files will be copied

# Other variables / constants
f_first="" # This variable will hold the first file found by ls command
f_site_conf="" # File that has vhost configuration generated by zentyal
sitename=""
a_OPT=('SSLCertificateFile' 'SSLCertificateKeyFile' 'SSLCertificateChainFile')
a_EXT=('crt' 'key' 'ca.pem')
s_VHOST_SSL="<VirtualHost *:443>"
i_line_num=""

# Loop through available directories
cd "$cust_conf"
for DR in */; do
if [ -d $DR ]; then
# Initialize paths/filenames
f_ext=${DR%/}   #Just a temp for below 2 lines (removes trailing slash / )
f_site_conf="$sites_path/ebox-$f_ext"
d_custom_ssl_conf="$sites_path/user-ebox-ssl-$f_ext"
f_custom_ssl_conf="$d_custom_ssl_conf/$f_custom_ssl_filename"
d_custom_conf="$sites_path/user-ebox-$f_ext"
f_custom_ssl_text="$cust_conf$DR/$f_input_ssl"
f_ext=""

                # Change into the current directory
                cd "$cust_conf$DR"

                # First check if we have common options for http and https, and if yes, copy it
                if [ -f "$f_input_common" ]; then
\cp "$f_input_common" "$d_custom_conf/$f_custom_conf"
                fi


# We will do the SSL section only if file $f_input_sll (default ssl.conf) exists
# and SSL is enabled for this virtual host
i_line_num=$(cat "$f_site_conf" | grep -Fxn "$s_VHOST_SSL" | grep -o '^[0-9]*')
if [ -f "$f_input_ssl" ] && [ $i_line_num ]; then

# If you use ForceSSL, Zentyal removes the Include directive from *:80 virtual host definition
# Let's check if it is there, and if not, we will add it
s_tmp=""
s_IncludeS="Include $d_custom_conf/*"
s_tmp=$(sed -e '/^<VirtualHost[ ]\*:80>/,/<\/VirtualHost>/ { /<\/VirtualHost>/ q' -e '}' "$f_site_conf" | grep "$s_IncludeS")
if [ ! -n "$s_tmp" ]; then
sed -i -e "/^<VirtualHost[ ]\*:80>/,/<\/VirtualHost>/ { /<\/VirtualHost>/ i\ $s_IncludeS" -e '}' "$f_site_conf"
fi
# GENERAL PART
# Now we add a directory to be included only for 443 host
# Check if SSL custom directory exists and if not, create it
if [ ! -d "$d_custom_ssl_conf" ]; then
mkdir -p "$d_custom_ssl_conf"
fi
# Copy custom ssl file and add an empty trailing line (just a safeguard)
\cp "$f_custom_ssl_text" "$f_custom_ssl_conf"

# CERTIFICATE SECTION
# Loop through the 3 directives and if file with correct extentions exists,
# insert its path into custom-ssl file
i=0
for s_EXT in "${a_EXT[@]}"; do
f_first=`ls *.$s_EXT | head -1`
if [ -n "$f_first" ]; then
mkdir -p "$d_cert_path/$DR"
\cp "$f_first" "$d_cert_path/$DR"
chmod 400 "$d_cert_path/$DR$f_first"
echo "${a_OPT[i]} $d_cert_path/$DR$f_first" >> "$f_custom_ssl_conf"
fi
((i++))
done

                        # Modify Zentyal's vhost config file, to include configuration from cusom-ssl directory
                        # but only in the HTTPS part of the config!
                        # Also disable the default SSL options in that file.
sed -i '/SSLEngine*/d' "$f_site_conf"
sed -i '/SSLCertificate*/d' "$f_site_conf"

s_tmp="Include $d_custom_ssl_conf/*"
sed -i "\|$s_tmp|d" "$f_site_conf"

i_line_num=$(cat "$f_site_conf" | grep -Fn "# SSL" | grep -o '^[0-9]*')
sed -i "$i_line_num""a Include $d_custom_ssl_conf/*" "$f_site_conf"

else
echo "No file $f_input_ssl exists in $DR" > /dev/null
fi # there is a custom ssl input file
else
echo "$DR is not a directory" > /dev/null
fi # the directory test

cd "$cust_conf" # Restore path for loop

done # the for loop
exit 0
« Last Edit: February 14, 2014, 03:12:39 pm by BrandonSk »

gzen

  • Zen Apprentice
  • *
  • Posts: 14
  • Karma: +2/-0
    • View Profile
Brandon, thank you for the contribution.

thk

  • Zen Apprentice
  • *
  • Posts: 20
  • Karma: +1/-0
    • View Profile
Thanks man! ;)