WordPress nginx config

server {
listen 80;
listen [::]:80;
root "/var/www/vHOST";
server_name vHOST;
index index.html index.php;
client_max_body_size 2G;

rewrite ^/wp-json/.*$ index.php$uri last;

location ~ ^/.*/$ {
try_files $uri $uri/ /index.php?$uri;
# pass the PHP scripts to FastCGI server listening on
location ~ \.php(/|$) {
include fastcgi.conf;
fastcgi_param SCRIPT_FILENAME "/var/www/vHOST/$fastcgi_script_name";
# With php7.0-cgi alone:
# fastcgi_pass;
# With php7.0-fpm:
fastcgi_pass unix:/run/php/php7.0-fpm.sock;

Bypass chrome tls security checks

Normally things like invalid certificates throw an error within google chrome, and if the page has hsts in place, there is no way to bypass that.
For normal users this is a good thing, but if you’re the developer/admin and have logged out yourself because of a miss configured server or you’re a pentester and want to access the contents of a wrongly configured web server, this can be frustrating.

And there is a way to access the pages, even though it is not available in the normal google chrome version.
You need to use the selenium driver. Therefore in turn you need the WebDriver library and the chromedriver.

1. Download the latest WebDriver https://www.nuget.org/api/v2/package/Selenium.WebDriver/
2. Download the latest ChromeDriver https://chromedriver.storage.googleapis.com/index.html (Keep in mind, that Version 2.10 is higher than 2.9)
3. Open PowerShell and import the WebDriver using “Import-Module” (or more specifically the correct dll for your installed .net version)
4. Unzip the chromedriver and place it inside of “./bin/selenium.chromedriver/”
5. Use PowerShell or C# to launch a new browser instance

$options = [OpenQA.Selenium.Chrome.ChromeOptions]::new()

Or use this script to install it inside of your current directory:

function Install-PSArchive {
    $null = Install-PackageProvider -Name PowerShellGet -Force -Scope CurrentUser
    Install-Module -Name 'Microsoft.PowerShell.Archive' -Force -Repository PSGallery -Scope CurrentUser -WarningAction SilentlyContinue

function Install-Selenium {
    param($ChromeSeleniumVersion = '2.45')
    Invoke-WebRequest -Uri 'https://www.nuget.org/api/v2/package/Selenium.WebDriver/' -UseBasicParsing -OutFile './selenium.webDriver.nupkg.zip'
    Expand-Archive -Path ./selenium.webDriver.nupkg.zip -Force
    $null = New-Item -Name './lib/selenium.webDriver' -ItemType Directory -Force
    Copy-Item -Path ./selenium.webDriver.nupkg/lib/netstandard2.0/WebDriver.dll -Destination ./lib/selenium.webDriver -Force
    Copy-Item -Path ./selenium.webDriver.nupkg/lib/netstandard2.0/WebDriver.xml -Destination ./lib/selenium.webDriver -Force
    Remove-Item -Recurse -Force -Path './selenium.webDriver.nupkg'
    Remove-Item -Recurse -Force -Path './selenium.webDriver.nupkg.zip'

    $ChromeSeleniumURLLinux = 'https://chromedriver.storage.googleapis.com/{0}/chromedriver_linux64.zip' -f $ChromeSeleniumVersion
    $ChromeSeleniumURLMacOS = 'https://chromedriver.storage.googleapis.com/{0}/chromedriver_mac64.zip' -f $ChromeSeleniumVersion
    $ChromeSeleniumURLWindows = 'https://chromedriver.storage.googleapis.com/{0}/chromedriver_win32.zip' -f $ChromeSeleniumVersion
    If ($IsWindows) {
        Invoke-WebRequest -Uri $ChromeSeleniumURLWindows -OutFile 'chromedriver.zip'
    elseif ($IsLinux) {
        Invoke-WebRequest -Uri $ChromeSeleniumURLLinux -OutFile 'chromedriver.zip'
    elseif ($IsMacOS) {
        Invoke-WebRequest -Uri $ChromeSeleniumURLMacOS -OutFile 'chromedriver.zip'
    else {
        Write-Error -Message 'Platform not supported.'
    $null = New-Item -Name './bin/selenium.chromedriver' -Force -ItemType Directory
    Expand-Archive -Path 'chromedriver.zip' -Force -DestinationPath ./bin/selenium.chromedriver
    Remove-Item -Recurse -Force -Path './chromedriver.zip'
    If ($IsLinux -or $IsMacOS) {
        chmod a+x ./bin/selenium.chromedriver/chromedriver

function Install-HtmlAgilityPack {
    Invoke-WebRequest -Uri 'https://www.nuget.org/api/v2/package/HtmlAgilityPack/' -OutFile ./HtmlAgilityPack.zip
    Expand-Archive -Path './HtmlAgilityPack.zip' -Force
    $null = New-Item -Name './lib/HtmlAgilityPack' -ItemType Directory -Force
    Copy-Item -Path ./HtmlAgilityPack/lib/netstandard2.0/HtmlAgilityPack.dll -Destination ./lib/HtmlAgilityPack -Force
    Copy-Item -Path ./HtmlAgilityPack/lib/netstandard2.0/HtmlAgilityPack.xml -Destination ./lib/HtmlAgilityPack -Force
    Remove-Item -Force -Recurse -Path './HtmlAgilityPack'
    Remove-Item -Force -Recurse -Path './HtmlAgilityPack.zip'

Import-Module -Name 'Microsoft.PowerShell.Archive'
Import-Module './lib/selenium.webDriver/WebDriver.dll'

## If you need to parse some html inside of your scripts and want to have cross platform functionality (or if internet explorer is not enabled), you also need to install HtmlAgilityPack, as powershell on windows relies upon it for parsing html into objects.
Import-Module './lib/HtmlAgilityPack/HtmlAgilityPack.dll'

Apache2 optimizations

To gain a faster page loading, you can enable the client side caching. That means that the browser of the connecting clients is storing the contents of your page until it expires.
Therefore you have to add the following under your virtual host entry (right before </VirtualHost>)

<IfModule mod_expires.c>
        ExpiresActive On
        ExpiresDefault "access plus 10 seconds"
        ExpiresByType text/html "access plus 60 seconds"
        ExpiresByType image/gif "access plus 120 minutes"
        ExpiresByType image/jpeg "access plus 120 minutes"
        ExpiresByType image/png "access plus 120 minutes"
        ExpiresByType text/css "access plus 60 minutes"
        ExpiresByType text/javascript "access plus 60 minutes"
        ExpiresByType application/javascript "access plus 60 minutes"
        ExpiresByType application/x-javascript "access plus 60 minutes"
        ExpiresByType text/xml "access plus 60 minutes"

After that run the following as root:

cd /etc/apache2/mods-enabled
ln -s ../mods-available/expires.load expires.load
ln -s ../mods-available/headers.load headers.load
service apache2 restart

Also if you want to redirect all http traffic to https you should use HTTP Response code 301 instead of 302. This is something that is nearly everywhere you look for http to https redirects missing (“R=301”).
To accomplish this you simply have to replace “<VirtualHost *>” at the beginning of your website configuration file (replace server names 😉 ) with:

<VirtualHost example.org:80>
        ServerName www.example.org
        # Redirect http://(www.)example.org/* to https://www.example.org/*
        RewriteEngine On
        RewriteCond %{HTTP_HOST}   ^(?:.*)example\.org$ [NC]
        RewriteCond %{SERVER_PORT}   !^443$
        RewriteRule  (.*)  https://www.example.org$1   [R=301,L]
<VirtualHost example.org:443>

Also you should use the ServerName attribute and avoid using “<VirtualHost *>” for convenience and later usage.

Configuring https is as simple. First you have to get your certificate use startssl or lets encrypt.
After you have managed to get your certificate for (www.example.org; don’t miss typing the www subdomain 😉 ) place the files in the following directory:
The Private key: /etc/ssl/private/example.org.key
The Certificate File: /etc/ssl/certs/example.org.crt
The Intermediate Certificates File (e.g. lets encrypt or sub.class1.server.ca.pem): /etc/ssl/certs/letsencryptauthorityx1.pem or /etc/ssl/certs/sub.class1.server.ca.pem

After the files are there you have to add some text to your VirtualHost configuration section

<VirtualHost example.org:443>
        ServerAdmin webmaster@example.org
        ServerName www.example.org

        SSLEngine on
        SSLCertificateFile /etc/ssl/certs/example.org.crt
        SSLCertificateKeyFile /etc/ssl/private/example.org.key
        SSLCertificateChainFile /etc/ssl/certs/sub.class1.server.ca.pem
        SSLProtocol ALL -SSLv2 -SSLv3
        SSLHonorCipherOrder on
        # SSLCipherSuite ALL:!ADH:!RC4:+HIGH:!MEDIUM:!LOW:!SSLv2:!SSLv3!EXPORT
        # Replace Certificate Hashes below
        Header always add Public-Key-Pins "pin-sha256=\"Vjs8r4z+80wjNcr1YKepWQboSIRi63WsWXhIMN+eWys=\"; pin-sha256=\"YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg=\"; max-age=2592000; includeSubdomains"
        Header always add Strict-Transport-Security "max-age=15768000"
        Header always add Content-Security-Policy "default-src 'self';frame-ancestors 'self';style-src 'self' 'unsafe-inline';script-src 'self' 'unsafe-inline' 'unsafe-eval';font-src 'self' data:;img-src 'self' data:"
        Header always add X-Content-Type-Options "nosniff"
        Header always add X-Frame-Options "sameorigin"
        Header always add X-XSS-Protection "1;mode=block"

As soon as WordPress stops using inline scripts, inline styles, fonts as “data:” urls and also images as “data:” urls, the line:

Header always add Content-Security-Policy "default-src 'self';frame-ancestors 'self';style-src 'self' 'unsafe-inline';script-src 'self' 'unsafe-inline' 'unsafe-eval';font-src 'self' data:;img-src 'self' data:"

can be changed to the more secure

Header always add Content-Security-Policy "default-src 'self';frame-ancestors 'self'"