Production ready WordPress install under linux

A secured production ready WordPress install.


  • Debian Ubuntu 12.04 LTS

  • WordPress 3.6, 3.7, 3.8

Update server, check time, check locale:

sudo apt-get update

sudo apt-get dist-upgrade

dpkg-reconfigure locales

sudo nano /etc/default/locale




sudo dpkg-reconfigure tzdata

###Set time zone and check id date/time is right



Activate firewall:

sudo ufw allow ssh

sudo ufw allow http

sudo ufw allow https

sudo ufw enable


Enforce SSH Protocol:

sudo nano /etc/ssh/sshd_config


PermitRootLogin no
DebianBanner no

ClientAliveInterval 600

ClientAliveCountMax 0


sudo service ssh restart

Protect “su” by limiting access only to admin group:

sudo adduser damien

sudo usermod -a -G admin damien

sudo dpkg-statoverride –update –add root admin 4750 /bin/su

Harden network with sysctl settings.

sudo nano /etc/sysctl.conf


net.ipv4.ip_forward = 0

# IP Spoofing protection

net.ipv4.conf.all.rp_filter = 1

net.ipv4.conf.default.rp_filter = 1

# Ignore ICMP broadcast requests

net.ipv4.icmp_echo_ignore_broadcasts = 1

# Disable source packet routing

net.ipv4.conf.all.accept_source_route = 0

net.ipv6.conf.all.accept_source_route = 0

net.ipv4.conf.default.accept_source_route = 0

net.ipv6.conf.default.accept_source_route = 0

# Ignore send redirects

net.ipv4.conf.all.send_redirects = 0

net.ipv4.conf.default.send_redirects = 0

# Block SYN attacks

net.ipv4.tcp_syncookies = 1

net.ipv4.tcp_max_syn_backlog = 2048

net.ipv4.tcp_synack_retries = 2

net.ipv4.tcp_syn_retries = 5

# Log Martians

net.ipv4.conf.all.log_martians = 1

net.ipv4.icmp_ignore_bogus_error_responses = 1

# Ignore ICMP redirects

net.ipv4.conf.all.accept_redirects = 0

net.ipv6.conf.all.accept_redirects = 0

net.ipv4.conf.default.accept_redirects = 0

net.ipv6.conf.default.accept_redirects = 0

# Ignore droadcast pings

net.ipv4.icmp_echo_ignore_broadcasts = 1

#Enable ExecShield protection

kernel.randomize_va_space = 1

# Disables the magic-sysrq key

kernel.sysrq = 0

#Disable Time Stamp

net.ipv4.tcp_timestamps = 0


sudo sysctl -p


Harden AppArmor:


sudo apt-get install apparmor apparmor-profiles


Install Apache2, MySQL and PHP:

sudo apt-get install apache2 mysql-server libapache2-mod-auth-mysql php5-mysql

sudo mysql_install_db

sudo /usr/bin/mysql_secure_installation

sudo apt-get install php5 libapache2-mod-php5 php5-mcrypt php5-gd


Add PHP index as default file:

sudo nano /etc/apache2/mods-enabled/dir.conf


Harden PHP for security:

sudo nano /etc/php5/apache2/php.ini


disable_functions = exec,system,shell_exec,passthru
register_globals = Off
expose_php = Off
display_errors = Off
track_errors = Off
html_errors = Off
magic_quotes_gpc = Off

upload_max_filesize = 100M

post_max_size = 100M


Restrict Apache information leakage:

sudo nano /etc/apache2/conf.d/security


ServerTokens Prod
ServerSignature Off
TraceEnable Off
Header unset ETag
FileETag None



Enable Apache2 modules:

sudo a2enmod ssl

sudo a2enmod rewrite

sudo a2enmod deflate

sudo a2enmod headers

sudo a2enmod expires

sudo service apache2 restart

Configure Virtualhost 80:

***Remember to remove cached files from browser while in development.

sudo nano /etc/apache2/sites-available/domainDefault

<VirtualHost *:80>




    DocumentRoot /var/www/

       <Directory /var/www/>

               Options Indexes FollowSymLinks MultiViews

               AllowOverride None

               Order allow,deny

               allow from all


    ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/

       <Directory “/usr/lib/cgi-bin”>

               AllowOverride None

               Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch

               Order allow,deny

               Allow from all


           # BEGIN Error reporting

    ErrorLog ${APACHE_LOG_DIR}/error.log

    # Possible values include: debug, info, notice, warn, error, crit,

    # alert, emerg.

   LogLevel warn

    CustomLog ${APACHE_LOG_DIR}/access.log combined

          # END Error reporting

           # BEGIN Eroor Documents

   ErrorDocument 404 /?error=404

           # END Eroor Documents

        # BEGIN Gzip compression

       SetOutputFilter DEFLATE

       SetEnvIfNoCase Request_URI .(?:gif|jpe?g|ico|png)$ no-gzip dont-vary

       SetEnvIfNoCase Request_URI .(?:exe|t?gz|zip|bz2|sit|rar)$ no-gzip dont-vary

       SetEnvIfNoCase Request_URI .pdf$ no-gzip dont-vary

    BrowserMatch ^Mozilla/4 gzip-only-text/html

    BrowserMatch ^Mozilla/4.0[678] no-gzip

    BrowserMatch bMSIE !no-gzip !gzip-only-text/html

       # END Gzip compression

       # BEGIN Expire headers

       ExpiresActive On

       ExpiresDefault “access plus 5 seconds”

       ExpiresByType image/x-icon “access plus 2592000 seconds”

       ExpiresByType image/jpeg “access plus 2592000 seconds”

       ExpiresByType image/png “access plus 2592000 seconds”

       ExpiresByType image/gif “access plus 2592000 seconds”

       ExpiresByType application/x-shockwave-flash “access plus 2592000 seconds”

       ExpiresByType text/css “access plus 604800 seconds”

       ExpiresByType text/javascript “access plus 216000 seconds”

       ExpiresByType application/javascript “access plus 216000 seconds”

       ExpiresByType application/x-javascript “access plus 216000 seconds”

       ExpiresByType text/html “access plus 600 seconds”

       ExpiresByType application/xhtml+xml “access plus 600 seconds”

       # END Expire headers

       #BEGIN FileETag

    FileETag none

       # END FileETag


sudo a2ensite domainDefault


Configure Virtualhost SSL:

sudo mkdir /etc/apache2/ssl

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/apache2/ssl/apache.key -out /etc/apache2/ssl/apache.crt

sudo nano /etc/apache2/sites-available/domainSecured

###Same as the other virtualhost only change to port 443 and add:

      #BEGIN SSL

       SSLEngine on

       SSLCertificateFile /etc/apache2/ssl/apache.crt

       SSLCertificateKeyFile /etc/apache2/ssl/apache.key

      #END SSL

sudo a2ensite domainSecured


Check for opened ports:

sudo apt-get install nmap

sudo nmap -v -sT localhost

sudo nmap -v -sS localhost


Audit your system security:

sudo apt-get install tiger

sudo tiger

sudo less /var/log/tiger/*


Create MySQL database for wordpress:

sudo mysql -u root -p


CREATE USER wordpressuser@localhost;

SET PASSWORD FOR wordpressuser@localhost= PASSWORD(“password”);

GRANT ALL PRIVILEGES ON wordpress.* TO wordpressuser@localhost IDENTIFIED BY ‘password’;




WordPress: Download, check MD5, uncompress and move to web directory with the right permissions:


###Check SHA with

sha1sum latest.tar.gz

tar -xzvf latest.tar.gz

cp wordpress/wp-config-sample.php wordpress/wp-config.php

rm wordpress/wp-config-sample.php

sudo nano wordpress/wp-config.php


define(‘DB_NAME’, ‘wordpress’);

define(‘DB_USER’, ‘wordpressuser’);

define(‘DB_PASSWORD’, ‘password’);

define( ‘WP_MEMORY_LIMIT’, ‘256M’ );

define( ‘FORCE_SSL_LOGIN’, true );

define( ‘FORCE_SSL_ADMIN’, true );

$table_prefix  = ‘wp_’;

## Replace Security tockens API with


sudo mv wordpress/* /var/www

cd /var/www

sudo rm index.html

sudo chown www-data:www-data -R *

sudo useradd webuser

sudo usermod -a -G www-data webuser


Leave a Reply

Your email address will not be published. Required fields are marked *