This will install LAMP (Linux, Apache, MySQL, PHP) in Lightsail. I’m assuming you already setup SSH access.

Install LAMP

To speed up things with the rest of the software below, run this:

sudo apt update
sudo apt upgrade
sudo apt-get install apache2 imagemagick php-cli libapache2-mod-php mysql-server php php-apcu php-mysql php-intl php-mbstring php-xml python-certbot-apache

This is around 300Mb of software, but takes only four minutes to install.

Apache

Here I’m using the domain jano.com.es. You can use your own domain, static IP, or made-up domain if you add it to /etc/hosts.

Install Apache

sudo apt-get install apache2

Edit Apache configuration

sudo nano /etc/apache2/apache2.conf

Add this at the bottom

ServerName jano.com.es

Restart Apache

sudo apache2ctl configtest
sudo systemctl restart apache2

At this point your IP should be serving the default Apache page.

Lightsail firewall

Each Lightsail instance has a firewall outside the operative system. Click on the instance name and go to Networking. The only ports enabled by default are 22 and 80. If you intend to serve pages using the HTTPS protocol you have to create a rule allowing traffic on port 443.

If you don’t do this, connection attempts will fail without reaching the instance. Apache and the Ubuntu firewall won’t even log a hit.

UFW

UFW is the Uncomplicated Firewall of Ubuntu. As the name suggests, it is easy to use.

Check that the UFW firewall has an “Apache Full” profile that enables ports 80 and 443, and activate that profile:

sudo ufw app info "Apache Full"
sudo ufw allow "Apache Full"

Only if you want to change the port from 80 to 90, you have to change the number in /etc/apache2/ports.conf, and /etc/apache2/sites-enabled/000-default.conf. Then you have to change the port to :90

sudo ufw allow 90/tcp

Enable the firewall:

sudo ufw enable

Other commands:

# enumerate rules
sudo ufw status numbered

# delete rule enumerated as 2
sudo ufw delete 2

# Delete rule labeled 443
sudo ufw delete 443

# See status
sudo ufw status verbose

UFW should contain rules for at least ports 22, 80, and 443. Here is my status:

$ sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
80,443/tcp (Apache Full)   ALLOW IN    Anywhere                  
22/tcp (OpenSSH)           ALLOW IN    Anywhere                  
80,443/tcp (Apache Full (v6)) ALLOW IN    Anywhere (v6)             
22/tcp (OpenSSH (v6))      ALLOW IN    Anywhere (v6)    

Check that the Apache2 Ubuntu default page is accessible through your firewall at your server IP: http://jano.com.es (use your domain or IP).

This should show the public machine IP but doesn’t. I guess the instance is in a container with its own gateway and network. Instead, it shows the private IP.

ip addr show eth0 | grep inet | awk '{ print $2; }' | sed 's/\/.*$//'

Of course, we can check the public IP on the cosole, or just run:

curl http://icanhazip.com

Custom resource record

If you have a domain you wish to point to your static IP you’ll need to add an A record. Otherwise skip this section.

This will point the base domain (jano.com.es) to the static IP address. The server will reload the configuration every 3600 seconds (one hour).

@ 3600 IN A 35.176.148.21

This is the same but associates any subdomain (*.jano.com.es):

* 3600 IN A 35.176.148.21

If you wish to redirect just a specific subdomain, replace the asterisk with that subdomain. For instance,

blog 3600 IN A 35.176.148.21

These changes are done in your DNS provider, which is usually the company that sold you the domain. The interface is usually a custom HTML page. If you bought the domain to Google, this is done at DNS > Custom resource records.

Once the change is done it typically takes from one to ten hours to propagate through the DNS network, with a guaranteed maximum of 36 hours. Until then, the change may not take effect.

If the DNS of your computer (System Preferences > Network > Advanced > DNS) is the IP of the DNS provider where you changed the record, you can query the DNS immediately to see the changes. Just run any of these:

dig jano.com.es
host jano.com.es
nslookup jano.com.es
curl jano.com.es

If the browser doesn’t pick the change restart it, or flush your DNS cache:

# macos
sudo dscacheutil -flushcache 

# windows
ipconfig /flushdns

My browser was still not picking up the changes and I don’t know why. I saw it on curl, propagated through the world, all records seem OK but my browser didn’t pick the change until hours later.

Setup virtual hosts

If you have several websites and enough CPU/memory, you may want to serve several domains from the same server. This is the case for webs made of static files, or those that don’t use much memory (PHP files).

In Ubuntu Apache serves the documents at /var/www/html. Let’s create a directory for each server:

sudo mkdir -p /var/www/jano.com.es
sudo mkdir -p /var/www/jano.dev
sudo chmod -R 755 /var/www

echo "At jano.com.es" | sudo tee /var/www/jano.com.es/index.html
echo "At jano.dev" | sudo tee /var/www/jano.dev/index.html

Create the configuration files

sudo cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/jano.com.es.conf
sudo cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/jano.dev.conf

Edit /etc/apache2/sites-available/jano.com.es.conf

<VirtualHost *:80>
    ServerAdmin admin@jano.dev
    ServerName jano.com.es
    ServerAlias www.jano.com.es
    DocumentRoot /var/www/jano.com.es
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Edit /etc/apache2/sites-available/jano.dev.conf

<VirtualHost *:80>
    ServerAdmin admin@jano.dev
    ServerName jano.dev
    ServerAlias www.jano.dev
    DocumentRoot /var/www/jano.dev
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

There is a tool called a2ensite specifically created to enable virtual hosts creating symlinks in /etc/apache2/sites-enabled. We’ll use it now.

Enable the virtual hosts using a2ensite. This is just a tool that enables sites by name, without having to manually create symlinks in /etc/apache2/sites-enabled for us.

sudo a2ensite jano.com.es.conf
sudo a2ensite jano.dev.conf

Disable the default 000-default.conf site.

sudo a2dissite 000-default.conf

Restart and check that everything is fine

sudo systemctl restart apache2
sudo systemctl status

Some Apache2 files in case something goes wrong:

/etc/apache2/sites-available/jano.dev-le-ssl.conf
/etc/apache2/sites-available/jano.dev.conf
/etc/apache2/sites-enabled/jano.dev-le-ssl.conf
/etc/apache2/sites-enabled/jano.dev.conf
/etc/letsencrypt/live/jano.dev/fullchain.pem
/etc/letsencrypt/live/jano.dev/privkey.pem
/etc/letsencrypt/options-ssl-apache.conf
/var/log/apache2
/var/www/jano.dev

Let’s Encrypt

Note: This section may not work if you just changed your DNS recently. Check that the domain works in curl, otherwise skip this section and come back later.

If you have a domain and want to install a SSL certificate, Let’s Encrypt offers certificates for free. This will need port 80 access.

sudo add-apt-repository ppa:certbot/certbot
sudo apt-get install python-certbot-apache
sudo certbot --apache -d jano.com.es
sudo certbot --apache -d jano.dev

This will edit the following files

VirtualHost: /etc/apache2/sites-available/jano.dev-le-ssl.conf
Certificate and chain: /etc/letsencrypt/live/jano.dev/fullchain.pem
Private key: /etc/letsencrypt/live/jano.dev/privkey.pem
Account credentials: /etc/letsencrypt/

certbot automatically renews certificates thanks to a renew script in /etc/cron.d. However we may need to restart Apache to pickup the changes. Edit the conf file for each domain:

sudo nano /etc/letsencrypt/renewal/jano.dev.conf

and add this line at the end:

renew_hook = systemctl restart apache2

You can check that everything looks fine doing a simulated renewal for all certificates:

sudo certbot renew --dry-run

Again, if you are using Lightsail, remember to add a rule for port 443 in the web Lightsail interface. Otherwise, even when you are able to configure Let’s Encrypt, you won’t be able to access the HTTPS port.

MySQL

Install MySQL:

sudo apt-get install mysql-server

Optionally run a script to secure MySQL. If you do, just follow the prompts.

sudo mysql_secure_installation

PHP

Now installing PHP in Apache:

sudo apt-get install php libapache2-mod-php php-mysql

Tell Apache to serve index.php before the default index.html. Edit the /etc/apache2/mods-enabled/dir.conf file and put the index.php first.

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

It will look like this:

<IfModule mod_dir.c>
    DirectoryIndex index.php index.html index.cgi index.pl index.php index.xhtml index.htm
</IfModule>

Restart Apache:

sudo systemctl restart apache2

Check the status of Apache. If you don’t see any errors it’s fine.

sudo systemctl status apache2

Check that PHP works. Create a php page:

sudo nano /var/www/html/info.php

with this content:

<?php
phpinfo();
?>

Load the page: http://jano.com.es/info.php

Now remove it to prevent intruders from gaining info about the server:

sudo rm /var/www/html/info.php

We are done. Now you can install LAMP applications in your server.