Moving the default Bitnami AWS Lightsail document root

When you set up an Apache or LAMP Lightsail instance on Amazon Web Services, the default document root is /home/bitnami/htdocs/

If you are migrating to Lightsail already use something other than htdocs as your root folder, for example public_html, then you might want to update this.

Although you could creating a new app on the server to hand it, here is a simpler option which leaves the default folders and setup in place:

In /opt/bitnami/apache2/conf/bitnami/bitnami.conf add your own document root to the end of every location that htdocs is mentioned.

Then

sudo chown -R bitnami:daemon /home/bitnami/htdocs/*
sudo chmod -R g+w /home/bitnami/htdocs
sudo /opt/bitnami/ctlscript.sh restart apache

And you should be good to go.

Remote connection to AWS bitnami lightsail LAMP Mysql

I’m using Sequal Pro here, but this should work for almost any connection. I’m also going to lock to a single IP for security. You could us ‘%’ for any IP, but I wouldn’t recommend it if you are on a static ip at home of at work.

Log into ssh for the relevant LAMP instance using the browser tool on the Lightsail dashboard.

cat bitnami_application_password to get your application password. Copy it somewhere as you’ll need it shortly.

Run nano /opt/bitnami/mysql/my.cnf
Comment out the line that starts with bind-address. So #bind-address...
Exit and save the file.

For MySQL < 8 – update mysql permissions for root remote access with

/opt/bitnami/mysql/bin/mysql -u root -p -e "grant all privileges on *.* to 'root'@'1.2.3.4' identified by 'PASSWORD' with grant option"

Replace 1.2.3.4 with internet connection IP address. Replace PASSWORD with the password you copied above.

For MySQL 8 we have to create the user first

/opt/bitnami/mysql/bin/mysql -u root -p -e "CREATE USER 'root'@'1.2.3.4' IDENTIFIED BY 'PASSWORD';"

/opt/bitnami/mysql/bin/mysql -u root -p -e "grant all privileges on *.* to 'root'@'1.2.3.4' with grant option";

Restart mysql with sudo /opt/bitnami/ctlscript.sh restart mysql

Copy the IP address of your Lightsail instance. You may want to add a free static IP address, else the IP will change on restart and all this work will need doing again.

In Sequal Pro choose to add a new connection. Select the SSH tab. In both hosts, put the IP of your Lightsail server.

In mysql username put root and in password, put your password from above.

In ssh username put bitnami and in password, put your password from above.

Click to test your connection. All should connect as expected.

You’ll now need to add a database etc. Enjoy.

Android App URL Schemes

This is a functioning AndroidManifest.xml for linking via a local url scheme. In this case appname:// with any (*) following path

To test this you have to redirect to it. Chromium at this time does not understand or process app url schemes. So a 302 redirect from a trusted publicly available url is the best method for testing.

Note how the second intent-filter here is still inside the .MainActivity <activity>

Different categories and an additional <data> tag are used.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.appname">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

    <application
      android:name=".MainApplication"
      android:label="@string/app_name"
      android:icon="@mipmap/ic_launcher"
      android:allowBackup="false"
      android:theme="@style/AppTheme">
      <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
        android:windowSoftInputMode="adjustResize">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
          <intent-filter android:label="@string/app_name">
              <action android:name="android.intent.action.VIEW" />
              <category android:name="android.intent.category.DEFAULT" />
              <category android:name="android.intent.category.BROWSABLE" />
              <data android:scheme="appname" android:host="*" />
          </intent-filter>
      </activity>
      <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
    </application>

</manifest>

Security of WHM backups to an AWS S3 bucket

When you give your Web Hosting Manager (WHM) the ability to send a copy of your backup to Amazon’s AWS S3 service, you have to hand it a Key and Secret that give it that permission.

The worst option is to hand over a Secret and Key related to your own log in.

The best is to:

  1. Create a policy which
    • Only gives access to a single bucket
    • Only allows the least access required for the task
    • Only allows connections from trusted IP addresses
  2. Create a Group to connect the policy to
  3. Create a user (for the WHM) to connect to the group

For validation of connection to S3 WHM currently requires the ability to write objects, list all objects in a bucket, delete objects. Now for some this is frustratingly more than you want to hand over. In theory WHM could make do with just the ability to write to the bucket, but at the moment we have to make all those abilities available.

Luckily, the fact we’re also limiting by IP and then Secret and Key—which WHM encrypts when you submit them—should make it highly unlikely anybody else will be able to abuse the ability to delete objects.

Here is the example policy that I have in place. Feel free to copy, personalise and use:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "WHMBackupAccess",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:ListBucket",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::YOUR_BUCKET_NAME",
                "arn:aws:s3:::YOUR_BUCKET_NAME/*"
            ],
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": "YOUR_SERVER_IP/32"
                }
            }
        }    
    ]
}

If you’re in need of help putting this all together, let me know and I might expand this post to include how to do the setup inside WHM and the AWS console.

.htaccess redirects based on date and time

A useful trick for implementing maintenance windows and redirects without having to use a php or similar script is to check date and time in .htaccess files or use it to build a redirect url.

Date and time values in .htaccess come in the form %{TIME_XXXX} where XXXX is the type of date or time you want.

So if you want to redirect a generic url to one which contains today’s date, you might use:

RewriteRule ^posts/today$ /posts/%{TIME_YEAR}-%{TIME_MON}-%{TIME_DAY}

That would result in /posts/today being redirected to something like /posts/2015-08-27

If you wanted redirect a page after a date (and time) is passed you could use something like the following, where if the date and time is passed 9am on 27th August 2015 the redirect will happen. We use a simple number comparison of turning the date into an integer and then comparing it.

RewriteCond %{TIME_YEAR}%{TIME_MON}%{TIME_DAY}%{TIME_HOUR} >2015082709
RewriteRule ^$ /destination/url.html [R=301,L]

The following would only redirect until a specific time (10.22am on 27th August 2015)

RewriteCond %{TIME_YEAR}%{TIME_MON}%{TIME_DAY}%{TIME_HOUR}%{TIME_MIN} <201508271022
RewriteRule ^$ /destination/url.html [R=301,L]

The following would only redirect between two specific dates (20th July 2015 and 27th August 2015)

RewriteCond %{TIME_YEAR}%{TIME_MON}%{TIME_DAY} <20150828
RewriteCond %{TIME_YEAR}%{TIME_MON}%{TIME_DAY} >20150719
RewriteRule ^$ /destination/url.html [R=301,L]

The options you have for %{TIME_XXXX} values are:

TIME_YEAR // current four-digit year
TIME_MON // current month
TIME_DAY // current day of month
TIME_HOUR // current hour (24 hour clock) of day
TIME_MIN // current minute of hour
TIME_SEC // current second of minute
TIME_WDAY // current week-day
TIME // a formatted string representing the date and time down to seconds. e.g. 20150827112234