Few Optimizations for my Blog

It’s been a while I touched any of configurations. But few days ago I was reading DZone article about web application performance and tried one of the tool described there – Google’s PageSpeed Insights. And I was slightly disappointed to see that my WordPress is not 100% optimal! While nothing I can really do with recommendations about JavaScript, CSS or even images (unless I hack into WordPress), I found that enabling compression is doable. StackOverflow is the winner again. So I created /etc/httpd/conf.d/deflate.conf with this content:

SetOutputFilter DEFLATE
# mod_deflate configuration
<IfModule mod_deflate.c>
# Restrict compression to these MIME types
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xml+rss
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE text/css
<IfModule mod_headers.c>
# Make sure proxies don't deliver the wrong content
Header append Vary User-Agent env=!dont-vary
</IfModule>
</IfModule>

After restarting Apache and running PageSpeed again I got 93/100 for Desktop Optimization!

After updating Sucuri plugin I also noticed one new security recommendation: Disable Server Banners. Essentially they recommend to turn off any information exposing your server version and modules. For that I just added two lines to /etc/httpd/conf/httpd.conf:

ServerSignature Off
ServerTokens Prod

And the last minor note that I had no issues with upgrading my AWS instance to Amazon Linux 2018.3. And they actually help you to do that in motd:

sudo yum clean all
sudo yum update

And you will get latest Linux 4.14 kernel and bunch of updates. I encountered no issues with my WordPress after restarting my box.

Let’s Encrypt on Amazon Linux

More then a year ago I installed SSL/TLS support for this blog using Amazon’s guide. Now that certificate has expired and I need a new one. This time I decided to use Let’s Encrypt because I have successfully used it for my other projects. And it was actually very easy:

wget https://dl.eff.org/certbot-auto
chmod +x certbot-auto
./certbot-auto run --apache -d blog.apalagin.net

This tool will complain that Amazon Linux is experimental. But I had no issues with that and it did all the work for me! Then only caveat is that Let’s Encrypt certificates expire in 2 month, so you should add a cron job to renew it regularly. For example, something like this in your /etc/crontab:

39 1,13 * * * root /home/ec2-user/certbot-auto renew

I also should mention that there is a next version of Amazon Linux – 2.2 – and you can install Cerbot there from EPEL repository.

 

Upgrading WordPress to PHP7 on Amazon Linux

Major of instructions were taken from StackOverflow. Though I didn’t follow all steps plus I also had to deal with SSL module. Anyway the migration was fast and flawless. Just don’t forget to backup you website πŸ™‚

Here are my instructions if you followed AWS tutorial to setup WordPress on Apache with SSL. Note that following these instructions is relatively safe and doesn’t corrupt any WordPress files (if you on Amazon Linux).

  1. Stop Apache and remove httpd 2.2 and PHP 5:
     sudo service httpd stop
     sudo yum remove httpd* php*
  2. Install Apache 2.4 and mod_ssl
    sudo yum install http24
    sudo yum install mod24_ssl
    
  3. Install PHP 7 and required modules
    sudo yum install php70
    sudo yum install php70-mysqlnd
    sudo yum install php70-gd
    
  4. Update Apache configuration to react on index.php files:
    sudo nano /etc/httpd/conf/httpd.conf

    Find dir_module section and update it to:

    <IfModule dir_module>
      DirectoryIndex index.html index.php
    </IfModule>
    

    Find <Directory "/var/www/html"> and update it to:

    <Directory "/var/www/html">
      Options Indexes FollowSymLinks
      AllowOverride All
      Require all granted
    </Directory>
    
  5. Now it’s time to copy back your SSL configuration:
    sudo mv /etc/httpd/conf.d/ssl.conf.rpmsave /etc/httpd/conf.d/ssl.conf
    
  6. Final steps: adding httpd to boot sequence and launching it:
    sudo chkconfig httpd on
    sudo service httpd start
    

Voila! Your WordPress should be back online running on PHP 7! Many thanks to WordPress, PHP, Apache and Amazon people who surely worked hard to make such transitions so simple and burden-free.

TensorFlow on Amazon Linux

This time I had to install Google’s TensorFlow for my wife’s study projects. Unfortunately TensorFlow officially supports only Ubuntu Linux and I didn’t find any tutorial for Amazon Linux. But I was able to find something for Cent OS which is very close, thanks to Tim Hoolihan!

First of all I had to install prerequisites. Note that I didn’t use Python’s virtual env. We use Jupyter Notebook front-end for study projects and I don’t know if virtualenv would be handy there.

sudo yum -y install epel-release
sudo yum -y install gcc gcc-c++ python-pip python-devel atlas atlas-devel gcc-gfortran openssl-devel libffi-devel
pip install --upgrade numpy scipy wheel cryptography

Then we have to install TensorFlow package from URL we can find on TensorFlow.org. I choose Python 2.7 package with CPU-only support. GPU support requires much more “dancing” and is not recommended for newbies.

sudo pip install https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.0.1-cp27-none-linux_x86_64.whl

Secured Jupyter Notebook on Amazon Linux

My last post was about running Jupyter remotely and using SSH tunnel for connections. That appeared to be inconvenient: too many steps for launching Jupyter and then connecting to it. I read through documentation of Notebook website and they have pretty detailed instructions how to run a public server.

I’m using AWS EC2 c4 instance with Amazon Linux. In general there are two steps: making server public and then securing it.

First you have to generate a configuration file:

jupyter notebook --generate-config

Then generate SHA1 password hash for your login by running Python command prompt:

python
 >> from notebook.auth import passwd
 >> passwd()

Then update your configuration file /home/user/.jupyter/jupyter_notebook_config.py by adding these settings to the end:

c.NotebookApp.ip='*'
c.NotebookApp.password=u'sha1:<your hashed password here>
c.NotebookApp.open_browser=False
c.NotebookApp.port=9999

Now you can run jupyter notebook and access your server using public IP or DNS name. But it’s better to secure your connection with SSL/TLS. And for that you have to generate SSL certificate and key. I will describe my case where I registered a DNS record A for my hostname and then used Let’s Encrypt to generate a valid HTTPS certificate.

The first step is obviously registering your DNS hostname which is out of scope. (With AWS Route 53 it is super easy though)

Then you have to configure your firewall to accept connections on port 443 (you can remove that later). In AWS you need to update security group for your instance and create a rule for port HTTPS.

Next step is downloading a tool from Lets’Encrypt:

wget https://dl.eff.org/certbot-auto
chmod a+x certbot-auto

That tool does all the job for creating keys, certificate and then signing it. That’s why it requires to have port 443 open: it’s going to check that you actually own the domain. by connecting to it from outside server. Don’t be scared by the amount of packages it’s going to install during the first run.
So the command is:

sudo ./certbot-auto certonly --standalone --debug -d <your domain>

When it finishes you will get bunch of files in /etc/letsencrypt directory. But you need files from /etc/letsencrypt/live/<you domain> folder. My problem was that these files are symlinks to ../archive and ec2-user can’t read them. So I had to change permissions:

sudo chmod +x /etc/letsencrypt/archive/
sudo chmod +r /etc/letsencrypt/archive/*

After that we can specify our key and certificate in Notebook config file:

c.NotebookApp.certfile=u'/etc/letsencrypt/live/<domain>/fullchain.pem'
c.NotebookApp.keyfile=u'/etc/letsencrypt/live/<domain>/privkey.pem'

Now your Notebook can be re-started and you must use HTTPS protocol for your connection: https://<domain>:9999/

My Jupyter Notebook also starts during the boot sequence. In Amazon Linux you can use /etc/rc.d/rc.local file for that by adding these command there:

jupyter notebook --config path_to_your_config > /var/log/jupyter-notebook.log &2>1 &

Jupyter Notebook on Amazon Linux

Jupyter Notebook is an app for data analysis. The idea is to combine documentation and the code! My wife uses it for her data science courses from Coursera. Once she complained that some tasks took whole night to complete on her laptop. Her Sony Vaio is pretty powerful, but definitely not a mainframe. When I noticed that Notebook is actually a web application I immediately suggested to run it in Amazon AWS! This is a short instruction how to setup Jupyter Notebook there.

First you have to provision EC2 instance with Amazon Linux. I recommend so called “compute-optimized” instance types (cX) as they provide max CPU power. Amazon Linux already comes with Python 2.7.12 which is enough for Jupyter. Installing Jupyter is pretty simple:

sudo pip install jupyter

Then you need to start it. Here is what I do:

ssh -i <rsa-key> ec2-user@<ec2-machine-public-dns>
screen
jupyter notebook --no-browser

First I login to the EC2 instance. Then I start screen session so I can easily logout/disconnect and let jupyter run in background. Third line is launching Jupyter Notebook. Note “no-browser” that’s because by default Notebook would try launching browser and we don’t want that. Jupyter will print out login URL similar toΒ http://localhost:8888/?token=a917d6207a4726774e2fd4d6053d12e24b0326628e2d7350. Copy it to you clipboard.

Next step is to create an SSH tunnel to access our Jupyter instance:

ssh -i <rsa-key> -fNL 8888:localhost:8888 ec2-user@<ec2-machine-public-dns>

Now you can open you browser and pasted saved URL:

The last thing you can do (if you want to try data science staff) is installing popular Python packages. But before that you need to install GCC and its prerequisites. In Amazon Linux (and Red Hat) it’s super easy:

sudo yum groupinstall "Development Tools"

Then you can install actual packages using pip:

sudo pip install numpy
sudo pip install pandas
sudo pip install xgboost
sudo pip install sklearn

And so on…

WordPress and XML RPC attack

Yesterday I checked my blog and got “Request timed out”. As you can guess from the title I become a victim of XML RPC exploit. There a lot of info on Internet describing what XML RPC exploit is and how to defend your blog. I will describe how I fought that attack myself. Well, with the help from mighty Google search πŸ™‚

So when I loggedΒ  into my AWS instance the first symptom was high CPU load from httpd. Which is not very surprising for t2.micro instance type πŸ™‚ Then I checked /var/log/httpd/access_log and found tons of events like this:

191.96.249.80 - - [14/Oct/2016:20:03:56 +0000] "POST /xmlrpc.php HTTP/1.0" 500 251 "-" "Mozilla/4.0 (compatible: MSIE 7.0; Windows NT 6.0)"

The first mitigation is to disable access to /xmlrpc.php in .htaccess:

Redirect 301 /xmlrpc.php http://127.0.0.1

That reflects the attacker and unloads your server so you can log in to WordPress admin console. The next thing is to shield your WordPress from similar attacks.

For that I installed WP Fail2Ban Redux plugin which logs all malicious events (including xmlrpc) to system log so they can be analyzed by Fail2ban service. Then I installed actual fail2ban service using yum and copied configurations from plugin’s folder. Note that you have to specify correct path to system log file plus default configuration does not actually ban (in Amazon Linux at least). Here is my local.jail for WordPress:

[wordpress-hard]
enabled = true
filter = wordpress-hard
logpath = /var/log/messages
maxretry = 2
action = iptables-multiport[name=WordPress, port="http,https", blocktype=DROP]

[wordpress-soft]
enabled = true
filter = wordpress-soft
logpath = /var/log/messages
maxretry = 5
action = hostsdeny

Basically these rules will block furious attacker using firewall (by dropping tcp packets). The wordpress-soft rule is about password attack and it just adds host to the hosts.deny for 10 minutes (default ban time). After that you can remove redirect rule from .htaccess if you need xmlrpc feature. I will keep it disabled…

AWS, WordPress and MySQL

I haven’t visited my blog for a while, so was very surprised to see “Error Establishing a Database Connection” page. At first I thought someone had hacked my box πŸ™‚ Instead MySQL server was down. I checked server logs and found fatal errors from mysql:

InnoDB: Fatal error: cannot allocate memory for the buffer pool

I googled that issue immediately and according to StackExchange my database couldn’t allocate more system memory and process died. Hm, 1G of RAM is not enough for a tiny blog???

Anyway, I have moved WordPress database to Amazon RDS. I went with t2.micro so it shouldn’t cost much. For the safety reason my instance does not have public IP and allows only connections from WordPress host.

Stranger things…

I installed my WordPress blog only 7 days ago. I never shared the link cause it’s kinda my private experiment for fun. But it’s been a second day someone is atacking my website. It’s a simple attack – password guessing– and there is no chance for attacker to succeed as I’m not there old granny and use randomly generated passwords. Anyway it’s exciting to be part of this cruel world!

Sucuri plugin logs failed logins, so I’m able to see there IP-address (well, gateway). According toΒ ip-www.net it’s Russian Federation. Saint Petersburg City if to be precise. Wow! Rumors don’t lie that russian hackers are everywhere πŸ˜€

The easiest thing would be to block there access to my IP. But AWS security groups are always permissive. So the only cheap way is to drop there packets using iptables:

sudo iptables -I INPUT -s 188.68.186.250 -j DROP

I googled help on StackOverflow πŸ™‚

If you want to restore your firewall rules during reboot, then don’t forget to call iptables-save!

Securing my WordPress

I am not a security guru nor a hacker. But I listen to what people say about security, vulnerabilities, exploits etc. And I am aware that default installation of anything (including whole LAMP stack) is not secured.

Amazon’s guides about LAMP and WordPress contain some security topics. So your installation will not be completely ridiculous πŸ™‚ But Amazon also has a nice guide for setting up SSL/TLS. And it worked perfectly for me! I followed everything step by step, got free SSL certificate from startssl.com and even tested my server using Qualys SSL Lab! Whoa!

I’ve also applied security guide from WPBeginner and installed security plugin to monitor my blog and alert me if something goes wrong! Interesting stuff!