Skip to content

Instantly share code, notes, and snippets.

@rmpel
Created November 30, 2016 10:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rmpel/dda9f0286e1de426dfde62921570d081 to your computer and use it in GitHub Desktop.
Save rmpel/dda9f0286e1de426dfde62921570d081 to your computer and use it in GitHub Desktop.
Apache Config File builder - generates an Apache2 config file based on a Development directory with virtual hosts with custom TLD.
#!/bin/bash
# this file is related to a series of posts on my website, see
# https://remonpel.nl/2012/10/semi-automatically-rebuild-apache-vhost-configuration/
# this script is ANYTHING BUT optimal
# it works as it is very well on macOS, Ubuntu and "Bash on Ubuntu on Windows with WSL"
# WSL is a seriously crippled way to use anything linux related, but if you are brave enough, you should try it.
# If you have better ways of doing things, send me a note :)
# USE AT YOUR OWN RISK
# Although this script writes just ONE file (development.conf) and does not alter your Apache config file, you should still
# keep backup copies just to be sure.
# INSTALLATION
# place this file in a PATH directory and make it executable.
# If your development sites are not in /Development, change the path accordingly
# this file will be placed in the other folder of apache config. In case it's not loaded, check httpd.conf to make sure
# the other/* conf files are included
# SUPPORT
# You can ask, but I cannot promise anything.
while [ "$1" != "" ]; do
[ "--php-version" == "$1" ] && shift && PHPVERSION="$1" && shift
[ "--dpath" == "$1" ] && shift && DEVELOPMENTPATH="$1" && shift
[ "-v" == "$1" ] && shift && PHPVERSION="$1" && shift
[ "-p" == "$1" ] && shift && DEVELOPMENTPATH="$1" && shift
shift
done
# Working directory
# CHANGE THIS IF YOU USE A DIFFERENT LOCATION
# You can export the variable DEVELOPMENTPATH in your .bashrc or .bash_profile if you want and set it to
# the correct folder
export DPATH="$DEVELOPMENTPATH"
if [ "" == "$DPATH" ]; then
DPATH=/Development
[ -d /Volumes/Development/Websites ] && DPATH=/Volumes/Development/Websites
fi
# To avoid working with symlinks, do not edit.
DPATH=$(cd "$DPATH" && pwd -P)
# verify PHP version
if [ "$PHPVERSION" == "" ]; then
PHPVERSION=$(ls -la $(which php) | egrep -o 'php[57][450]')
[ "" = "$PHPVERSION" ] && [ -f "/usr/bin/php" ] && PHPVERSION=php$(php --version | egrep -o 'PHP [57]\.[0-9]' | egrep -o '[57]\.[0-9]' | sed 's/\.//')
echo 'php:' $(which php) '-> version' $PHPVERSION
fi
# root cannot brew, so do this before elevation
if [ "$(id -u)" != "0" ]; then
if [ "" != "$(which brew)" ]; then
V=$(echo $PHPVERSION | sed 's/php//')
[ "$V" != "" ] && [ ! -d /usr/local/Cellar/php$V ] && echo "PHP $V not installed" && brew install homebrew/php/php$V homebrew/php/php$V-mongo homebrew/php/php$V-xdebug
CURRENTPHPVERSION=$(ls -la $(which php) | egrep -o 'php[57][450]' | egrep -o '[57][450]')
if [ "$PHPVERSION" != "" ]; then
if [ "$CURRENTPHPVERSION" != "$V" ]; then
echo "Switching from PHP $CURRENTPHPVERSION to PHP $V"
for V in 53 54 55 56 70; do
[ -d /usr/local/Cellar/php$V ] && brew unlink php$V
done
shift;
brew link php$PHPVERSION
fi
fi
fi
fi
# Make sure only root can run this script
if [ "$(id -u)" != "0" ]; then
sudo "$0" --php-version $PHPVERSION --dpath "$DPATH" "$@"
exit 0
fi
# from here, we are root.
# make sure PHPVERSION is just the number 54, 55, 56 or 70
PHPVERSION=php$(echo $PHPVERSION | egrep -o '[57][450]')
# Set to no if you don't want to use SSL, set to auto to auto detect, set to yes to force
USE_SSL=auto
SSL_LOG_SUFFIX=_ssl
SSL_LOG_SUFFIX=
# FORCENEWCERTS=YES
PERDOMAINCERTS=NO
# TLDs
# CHANGE THESE IF YOU USE A TLD OTHER THAN .local
# You can enter more, using a space-separated list.
# Eample: TLDS="local dev dv"
TLDS="dev dv home cs"
# Your details
SSLC=NL ; # country
SSLST=Utrecht ; # state
SSLL=Nieuwegein ; # locality
SSLO="Clearsite Webdesigners" ; # organisation
SSLOU=Development ; # organisational unit
MYEMAIL=ik@remonpel.nl
# LOG path
LPATH="$DPATH/logs"
# APACHE SSL CERTIFICATE PATH
SPATH=/etc/apache2/ssl.crt
# Virtual host config file or directory, for example: /etc/apache2/extra/httpd-vhost.conf or /etc/apache2/other/
# /etc/apache2/conf-enabled is for ubuntu/debian based distsributions
# /etc/apache2/other is the usual place on OS X/macOS
[ -d /etc/apache2/conf-enabled ] && VHOST=/etc/apache2/conf-enabled/ || VHOST=/etc/apache2/other/
# subdirectory for the web-files
PHDIR=public_html
# Evaluate the actual path (following symlinks all the way)? YES or NO
PHDIR_EVAL=YES
# can be IPv4, IPv6, BOTH or NONE. if NONE, hosts file will not be touched
# when using a local DNS server for serving your TLD's, set this to NONE.
NETMODE=IPv4
# CGI-BIN for FastCGI PHP - in case a different version of PHP is needed.
# example structure
# /Development/cgi-bin/ base folder. this is ofcourse your own choice and is a subfolder of $DPATH
CGI_SUB=cgi-bin
# /Development/cgi-bin/5.3.8 version folder. you download the package, so you know which version it is.
# /Development/cgi-bin/5.3.8/PHP5 the downloaded package. in this folder you find bin lib etc and include
# copy lib/php.ini to ../ see below
# /Development/cgi-bin/5.3.8/php-cgi cgi-bin alias script. contains: #!/bin/bash
# D=` dirname "$0" `; [ "$D" == "." ] && D=` pwd -P `
# exec "$D"/PHP5/bin/php-cgi \"$@\"
# /Development/cgi-bin/5.3.8/php.ini this is the ini file copied from the package/lib/ folder
# no more configuration after this
# editing below this line is for advanced users only
# make sure log path exists
[ ! -d "$LPATH" ] && mkdir $LPATH
# migrate the path we created ourselves to the path ubuntu/debian uses, but only if the path is in use
[ "$SPATH" = "/etc/apache2/ssl.crt" ] && [ -d /etc/apache2/ssl.key ] && [ ! -d /etc/apache2/ssl.crt ] && mv /etc/apache2/ssl.{key,crt}
# module path
[ -d /usr/lib/apache2/modules ] && MODPATH=/usr/lib/apache2/modules || MODPATH=libexec/apache2
#autodetect SSL
[ -f "$SPATH"/server.crt ] && [ "$USE_SSL" != "no" ] && USE_SSL=yes
# function for easy stderr
a_message () {
echo $1 >&2
}
RBATOKEN="#rba_line_do_not_edit"
# for the domain list in hosts file
a_host () {
LOCAL=YES
IP="127.0.0.1"
IP6="::1"
NM=$NETMODE
# a bit redundant here, but it's readable
while [ "$1" != "" ]; do
[ "--ip" == "$1" ] && shift && IP="$1" && shift && LOCAL=NO
[ "--ip6" == "$1" ] && shift && IP6="$1" && shift && LOCAL=NO
[ "$LOCAL" == "NO" ] && [ "$IP6" == "::1" ] && [ "$NETMODE" == "BOTH" ] && NETMODE=IPv4
[ "$NETMODE" == "IPv4" ] && echo "$IP $1 $RBATOKEN" >> /tmp/hosts$$
[ "$NETMODE" == "IPv6" ] && echo "$IP6 $1 $RBATOKEN" >> /tmp/hosts$$
[ "$NETMODE" == "BOTH" ] && echo "$IP $1 $RBATOKEN" >> /tmp/hosts$$
[ "$NETMODE" == "BOTH" ] && echo "$IP6 $1 $RBATOKEN" >> /tmp/hosts$$
shift
done
NETMODE=$NM
}
read_hosts () {
[ "$NETMODE" != "NONE" ] && cat /etc/hosts | grep -v "$RBATOKEN" > /tmp/hosts$$
}
write_hosts () {
[ "$NETMODE" != "NONE" ] && cat /tmp/hosts$$ > /etc/hosts
[ "$NETMODE" != "NONE" ] && rm /tmp/hosts$$
}
getVagrantIp () {
cat "$1" | grep 'private_network' | egrep -o '([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'
}
generate_openssl_ca_config () {
echo '[ ca ]'
echo 'default_ca = CA_own'
echo '[ CA_own ]'
echo 'dir = '$SPATH
echo 'certs = $dir'
echo 'new_certs_dir = $dir/ca.db.certs'
echo 'database = $dir/ca.db.index'
echo 'serial = $dir/ca.db.serial'
echo 'RANDFILE = $dir/ca.db.rand'
echo 'certificate = $dir/ca.crt'
echo 'private_key = $dir/ca.key'
echo 'default_days = 3650'
echo 'default_crl_days = 30'
echo 'default_md = md5'
echo 'preserve = no'
echo 'policy = policy_anything'
echo 'unique_subject = no'
echo '[ policy_anything ]'
echo 'countryName = optional'
echo 'stateOrProvinceName = optional'
echo 'localityName = optional'
echo 'organizationName = optional'
echo 'organizationalUnitName = optional'
echo 'commonName = supplied'
echo 'emailAddress = optional'
}
generate_openssl_req_config () {
echo '[ req ]'
echo 'default_bits = 2048'
echo 'default_keyfile = privkey.pem'
echo 'distinguished_name = req_distinguished_name'
echo 'req_extensions = req_ext # The extentions to add to the self signed cert'
echo ''
echo '[ req_distinguished_name ]'
echo 'countryName = Country Name (2 letter code)'
echo 'countryName_default = US'
echo 'stateOrProvinceName = State or Province Name (full name)'
echo 'stateOrProvinceName_default = Illinois'
echo 'localityName = Locality Name (eg, city)'
echo 'localityName_default = Chicago'
echo 'organizationName = Organization Name (eg, company)'
echo 'organizationName_default = Example, Co.'
echo 'commonName = Common Name (eg, YOUR name)'
echo 'commonName_max = 64'
echo ''
echo '[ req_ext ]'
echo 'subjectAltName = @alt_names'
echo ''
echo '[alt_names]'
generate_openssl_req_config_j=0;
for generate_openssl_req_config_i in $aliases; do
generate_openssl_req_config_j=` expr $generate_openssl_req_config_j + 1 `
echo 'DNS.'$generate_openssl_req_config_j' = '$generate_openssl_req_config_i
done;
}
# VirtualHost Template. Change this if you must
a_virtual_host () {
CGI=no;
aCGI=` ls -1 "$DPATH/$1"/*.cgi 2>/dev/null | head -n 1 `
[ "$aCGI" != "" ] && CGI=yes && VER=` basename $aCGI | sed 's/.cgi//' `;
[ "$CGI" == "yes" ] && [ ! -d "$DPATH/$CGI_SUB/$VER/" ] && CGI=no;
a_message "Writing VHOST config for domain $1 on $2 with aliases $3"
[ "$CGI" == "yes" ] && a_message " Use FastCGI version $VER"
echo " "
echo "# $1 "
echo " "
echo "<VirtualHost *:80>"
echo " SetEnv APP_ENV \"development\" "
if [ "$CGI" == "yes" ]; then
echo "ScriptAlias /cgi-bin/ $DPATH/$CGI_SUB/$VER/"
echo "AddHandler php-fcgi .php"
echo "Action php-fcgi /cgi-bin/php-cgi"
fi
echo " ServerAdmin $MYEMAIL"
echo " ServerName $1"
echo " ServerAlias $3"
echo " DocumentRoot \"$2\""
echo " Options +FollowSymlinks"
echo " ErrorLog \"$LPATH/` echo $i | sed 's/\./_/g' `_error_log\""
echo " CustomLog \"$LPATH/` echo $i | sed 's/\./_/g' `_access_log\" common"
echo " php_value html_errors On"
echo " KeepAlive On"
echo " KeepAliveTimeout 5"
echo " php_value error_reporting 22517"
echo " php_value display_errors On"
[ -f "$DPATH/global.php" ] && [ ! -f "$DPATH/$i/noglobal" ] && echo " php_value auto_prepend_file $DPATH/global.php"
echo "</VirtualHost>"
if [ "$USE_SSL" == "yes" ]; then
# individual certificates
if [ "$PERDOMAINCERTS" == "YES" ]; then
if [ -d "$DPATH"/"$1" ]; then
[ "$FORCENEWCERTS" == "YES" ] && [ -f "$DPATH"/"$1"/ssl.key ] && rm "$DPATH"/"$1"/ssl.key
[ "$FORCENEWCERTS" == "YES" ] && [ -f "$DPATH"/"$1"/ssl.cnf ] && rm "$DPATH"/"$1"/ssl.cnf
[ ! -f "$SPATH"/openssl.cnf ] && generate_openssl_ca_config > "$SPATH"/openssl.cnf
[ ! -f "$DPATH"/"$1"/ssl.cnf ] && generate_openssl_req_config > "$DPATH"/"$1"/ssl.cnf
pushd "$SPATH" >/dev/null 2>&1
if [ ! -f "$DPATH"/"$1"/ssl.key ]; then
# generate key
openssl genrsa -des3 -passout pass:nopasswordhere -out "$DPATH"/"$1"/ssl.key 2048 -noout
# Remove passphrase from the key. Comment the line out to keep the passphrase
openssl rsa -in "$DPATH"/"$1"/ssl.key -passin pass:nopasswordhere -out "$DPATH"/"$1"/ssl.key
# remove the csr, it's no longer valid
[ -f "$DPATH"/"$1"/ssl.csr ] && rm "$DPATH"/"$1"/ssl.csr
fi
# generate CSR
if [ ! -f "$DPATH"/"$1"/ssl.csr ]; then
openssl req -new -key "$DPATH"/"$1"/ssl.key -out "$DPATH"/"$1"/ssl.csr -config "$DPATH"/"$1"/ssl.cnf \
-subj "/C=$SSLC/ST=$SSLST/L=SSSLL/O=$SSLO/OU=$SSLOU/CN=$1/emailAddress=$MYEMAIL"
# openssl req -new -key $domain.key -out $domain.csr -passin pass:$password \
# -subj "/C=$country/ST=$state/L=$locality/O=$organization/OU=$organizationalunit/CN=$commonname/emailAddress=$email"
# remove the certificate, it's no longer valid
[ -f "$DPATH"/"$1"/ssl.crt ] && rm "$DPATH"/"$1"/ssl.crt
fi
# sign the certificate
if [ ! -f "$DPATH"/"$1"/ssl.crt ]; then
openssl ca -batch -config "$SPATH"/openssl.cnf -out "$DPATH"/"$1"/ssl.crt -infiles "$DPATH"/"$1"/ssl.csr
fi
chown `logname` "$DPATH"/"$1"/ssl.*
popd >/dev/null 2>&1
fi
else
[ -f "$DPATH"/"$1"/ssl.crt ] && rm "$DPATH"/"$1"/ssl.*
fi
echo "<VirtualHost *:443>"
echo " SetEnv APP_ENV \"development\" "
if [ "$CGI" == "yes" ]; then
echo "ScriptAlias /cgi-bin/ $DPATH/$CGI_SUB/$VER/"
echo "AddHandler php-fcgi .php"
echo "Action php-fcgi /cgi-bin/php-cgi"
fi
echo " ServerAdmin $MYEMAIL"
echo " ServerName $1"
echo " ServerAlias $3"
echo " DocumentRoot \"$2\""
echo " Options +FollowSymlinks"
echo " ErrorLog \"$LPATH/` echo $i | sed 's/\./_/g' `${SSL_LOG_SUFFIX}_error_log\""
echo " CustomLog \"$LPATH/` echo $i | sed 's/\./_/g' `${SSL_LOG_SUFFIX}_access_log\" common"
echo " php_value html_errors On"
echo " KeepAlive On"
echo " KeepAliveTimeout 5"
echo " php_value error_reporting 22517"
echo " php_value display_errors On"
[ -f "$DPATH/global.php" ] && [ ! -f "$DPATH/$i/noglobal" ] && echo " php_value auto_prepend_file $DPATH/global.php"
echo " SSLEngine On"
# site key or server key
[ -f "$DPATH"/"$1"/ssl.key ] && echo " SSLCertificateKeyFile $DPATH/$1/ssl.key"
[ ! -f "$DPATH"/"$1"/ssl.key ] && echo " SSLCertificateKeyFile $SPATH/server.key"
# site sert or server cert
[ -f "$DPATH"/"$1"/ssl.crt ] && echo " SSLCertificateFile $DPATH/$1/ssl.crt"
[ ! -f "$DPATH"/"$1"/ssl.crt ] && echo " SSLCertificateFile $SPATH/server.crt"
echo "</VirtualHost>"
else
[ -f "$DPATH"/"$1"/ssl.crt ] && rm "$DPATH"/"$1"/ssl.*
fi
}
a_message "Rebuilding Apache2 VirtualHost list"
[ -d "$VHOST" ] && VHOSTFILE="$VHOST/development.conf"
[ -f "$VHOST" ] && VHOSTFILE="$VHOST"
# TODO: Switch from single config file to multiple config files;
# ONLY in case the VHOST variable holds a FOLDER
#
# outside TLD loop:
# write a development.conf for the directory configuration
#
# inside TLD loop:
# write a development.$tld.conf for every tld with the fallback
# write a development.$tld.$projectFolderBasename.conf for every project.
# list all development.$tld.*.conf and check if conf is still needed. remove if not
touch /tmp/conf$$
read_hosts
echo "" > /tmp/conf$$
echo "LoadModule ${PHPVERSION:0:4}_module /usr/local/opt/${PHPVERSION}/${MODPATH}/lib${PHPVERSION:0:4}.so" >> /tmp/conf$$
echo "AddType application/x-httpd-php .php" >> /tmp/conf$$
echo "DirectoryIndex index.php" >> /tmp/conf$$
echo "LoadModule rewrite_module ${MODPATH}/mod_rewrite.so" >> /tmp/conf$$
echo "LoadModule socache_shmcb_module ${MODPATH}/mod_socache_shmcb.so" >> /tmp/conf$$
echo "<IfVersion >= 2.4>" >> /tmp/conf$$
echo "LoadModule access_compat_module ${MODPATH}/mod_access_compat.so" >> /tmp/conf$$
echo "</IfVersion>" >> /tmp/conf$$
[ "$USE_SSL" == "yes" ] && echo "LoadModule ssl_module ${MODPATH}/mod_ssl.so" >> /tmp/conf$$
[ "$USE_SSL" == "yes" ] && echo "Include /private/etc/apache2/extra/httpd-ssl.conf" >> /tmp/conf$$
[ "$USE_SSL" == "yes" ] && echo "SSLVerifyClient none" >> /tmp/conf$$
echo "<Directory \"$DPATH\">" >> /tmp/conf$$
echo " Options Indexes FollowSymLinks MultiViews" >> /tmp/conf$$
echo " AllowOverride All" >> /tmp/conf$$
echo " <IfVersion >= 2.4>" >> /tmp/conf$$
echo " Require all granted" >> /tmp/conf$$
echo " </IfVersion>" >> /tmp/conf$$
echo " <IfVersion < 2.4>" >> /tmp/conf$$
echo " Order allow,deny" >> /tmp/conf$$
echo " Allow from all" >> /tmp/conf$$
echo " </IfVersion>" >> /tmp/conf$$
echo "</Directory>" >> /tmp/conf$$
echo "" >> /tmp/conf$$
echo " <IfVersion < 2.4>" >> /tmp/conf$$
echo "NameVirtualHost *:80" >> /tmp/conf$$
echo "NameVirtualHost *:443" >> /tmp/conf$$
echo "</IfVersion>" >> /tmp/conf$$
DEFPATH=no
[ -d "$DPATH/default" ] && DEFPATH=$DPATH/default
for tld in $TLDS; do
if [ "no" != "$DEFPATH" ]; then
a_message "Writing fallback for $tld to $DEFPATH"
a_virtual_host "development.$tld" "$DEFPATH" "www.development.$tld" >> /tmp/conf$$
a_host "development.$tld"
fi
for i in ` ls -1 "$DPATH" | egrep "\.$tld$" `; do
aliases="www.$i"
[ -f "$DPATH/$i/aliases" ] && aliases=` cat "$DPATH/$i/aliases" `
if [ -f "$DPATH/$i/Vagrantfile" ]; then
VAGRIP=` getVagrantIp "$DPATH/$i/Vagrantfile"`
a_message "Writing Vagrant VM IP to host file for domain $i on $VAGRIP with aliases $aliases"
a_host --ip $VAGRIP $i $aliases
elif [ -f "$DPATH/$i/remoteip" ]; then
a_message "Writing Remote IP to host file for domain $i on $(cat "$DPATH/$i/remoteip") with aliases $aliases"
a_host --ip $(cat "$DPATH/$i/remoteip") $i $aliases
else
if [ "$PHDIR_EVAL" == "YES" ] && [ -L "$DPATH/$i/$PHDIR" ]; then
ABSPATH=` cd "$DPATH/$i/$PHDIR" && pwd -P `
a_virtual_host "$i" "$ABSPATH" "$aliases" >> /tmp/conf$$
elif [ -d "$DPATH/$i/$PHDIR" ]; then
a_virtual_host "$i" "$DPATH/$i/$PHDIR" "$aliases" >> /tmp/conf$$
else
a_virtual_host "$i" "$DPATH/$i" "$aliases" >> /tmp/conf$$
fi
a_host $i $aliases
fi
done
done
cat /tmp/conf$$ > $VHOSTFILE
rm /tmp/conf$$
write_hosts
echo Restarting Apache && apachectl restart
[ ` apachectl configtest 2>&1 | grep 'Syntax OK' | wc -l ` -gt 0 ] && echo "All ok. Get crackin'!" && exit 0
[ ` apachectl configtest 2>&1 | grep 'Syntax OK' | wc -l ` -eq 0 ] && echo "HELP! Something went wrong. Please review the config files" && apachectl configtest && exit 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment