How to Host a Website in Oracle Cloud Free Tier

edited February 2022 in Technical

This post is originally published on yoursunny.com blog https://yoursunny.com/t/2020/OracleCloud-website/

Oracle Cloud is a cloud computing service offered by Oracle Corporation.
Oracle Cloud has a generous free tier that offers two "always free" Micro instances with the following specification:

  • KVM virtualization
  • 1/8 CPU cores (AMD EPYC 7551)
  • 1GB memory
  • 47GB disk storage
  • 1 IPv4 address
  • up to 32 IPv6 addresses
  • 50Mbps Internet bandwidth

I signed up for Oracle Cloud, so that I can have some more free computing resources to play with.
The sign-up procedure requires a credit card for identity confirmation purpose, but the credit card will not be charged.
During sign-up, there's a choice of home region, which determines the location of VM instances; once selected, it cannot be changed in the future.

A common use case for a virtual machine is to host a website.
Due to the firewalls, hosting a website on Oracle Cloud needs a few more steps.
Here's exactly how to deploy a website in a Oracle Cloud Free Tier VM instance.

UPDATED 2022-01-27:
Oracle Cloud now supports IPv6.
Instructions are updated to enable IPv6 on the web server.

Create a VM Instance

Each Oracle Cloud account is eligible for two Always Free Micro instances.
To create a VM, sign in to the Oracle Cloud console, in "Launch Resources" section click Create a VM instance.
This takes us to the "Create Compute Instance" page.

In "Image and shape" section, select VM.Standard.E2.1.Micro shape and Canonical Ubuntu 20.04 image.
Do not use the "Canonical Ubuntu 20.04 Minimal" image.

Create Compute Instance - Image and shape

In "Configure network" section, select Create new virtual cloud network, and keep other options at their default values.

In "Add SSH keys" section, select Paste public keys, and paste your SSH public key in the text box below.
If you do not have a SSH public key, follow this guide to generate one.

Finally, click the Create button to create the compute VM instance.
Within a few seconds, you should see the "Instance Details" page.

Instance Details

You can SSH into the VM instance using the public IP address and username displayed in the "Instance Access" section.

Enable IPv6

In this year, it is important for websites to support IPv6.
Today, most cellular networks are IPv6 only.
By enabling IPv6, it enables mobile users to access your website more efficiently, because their sessions do not need to go through IPv4 address translation proxies.

Oracle Cloud compute VM instances are initially assigned with only an IPv4 address.
There are 5 steps for enabling IPv6 on the VM:

  1. Assign IPv6 CIDR block to the Virtual Cloud Network.
  2. Assign IPv6 CIDR block to the Subnet.
  3. Configure IPv6 Route Rule.
  4. Assign IPv6 Address to the compute VM's VNIC.
  5. Configure firewall rules.

We will perform steps 1~4 now, and do step 5 a little later (in "Configure Ingress and Egress Rules" section).

Looking at the "Instance Details" page, click the link next to "Virtual cloud network".
This takes us to the "Virtual Cloud Network Details" page.

Select "CIDR Blocks" tab on the left side "Resources" menu, and then click Add IPv6 CIDR Block button.
You will be asked to confirm that you want to enable IPv6.
When you click Confirm, a /56 block of 4,722,366,482,869,645,213,696 IPv6 addresses are automatically allocated to your Virtual Cloud Network (IPv6 step 1).

CIDR Blocks

Select "Subnets" tab on the left side "Resources" menu.
You should see an existing Subnet.
It would have an IPv4 CIDR Block, but the "IPv6 CIDR Block" column is blank.
Click the button in the rightmost column, and select "Edit" in the dropdown menu.
Then, check Enable IPv6 CIDR Block box, enter two hexadecimal digits (such as 00) in the box just before "::/64", and click Save Changes (IPv6 step 2).

IPv6 CIDR Block

Select "Route Tables" tab on the left side "Resources" menu, and then click Default Route Table link.
This takes us to the "Route Table Details" pages.
In the "Route Rules" tables, we can see that there's a route rule for destination 0.0.0.0/0 that targets the Internet gateway, which allows IPv4 packets to reach the Internet.
We need a similar route rule for IPv6.
Click Add Route Rules button.
In the popup dialog, enter the following:

  • Protocol Version: IPv6
  • Target Type: Internet Gateway
  • Destination CIDR Block: ::/0
  • Target Internet Gateway: Internet gateway vcn-…

Then click Add Route Rules button (IPv6 step 3).

Finally, go back to the "Instance Details" page of the compute VM instance.
To find that page, you can type "Instances" into the search bar and select "Services - Instances (Compute)" in the results.

Select "Attached VNICs" tab on the left side "Resources" menu, and then click the link next to (Primary VNIC).
This opens the "VNIC Details".
Select "IPv6 Addresses" tab on the left side "Resources" menu, and click Assign IPv6 Address button.
In the popup dialog, click Assign button to get a random IPv6 address (IPv6 step 4).

DNS

Now that we have the IP addresses assigned, it is a good time to add DNS records to our compute VM instance, so that we can activate HTTPS later.
Two DNS records are required: an A record for the public IPv4 address and an AAAA record for the public IPv6 address.
You can find both addresses in the "VNIC Details" page, as described above.

DNS record

Configure Ingress and Egress Rules

Oracle Cloud has a strict firewall that, by default, only allows SSH access.
In order to host a website, it is necessary to configure the firewall so that it allows HTTP traffic.

To access the firewall configuration page, click the "subnet" name in "Primary VNIC" section of "Instance Details" page.
Then, on "Subnet Details" page, click "Default Security List for …" in "Security Lists" section.
Click Add Ingress Rules button, and enter these four rules in the popup dialog:

  • Allow HTTP/1.1 and HTTP/2 (IPv4)

    • stateless: no
    • source CIDR: 0.0.0.0/0
    • IP protocol: TCP
    • destination port range: 80,443
  • Allow HTTP/1.1 and HTTP/2 (IPv6)

    • stateless: no
    • source CIDR: ::/0
    • IP protocol: TCP
    • destination port range: 80,443
  • Allow HTTP/3 (IPv4)

    • stateless: no
    • source CIDR: 0.0.0.0/0
    • IP protocol: UDP
    • destination port range: 443
  • Allow HTTP/3 (IPv6)

    • stateless: no
    • source CIDR: ::/0
    • IP protocol: UDP
    • destination port range: 443

After that, you should see the following ingress rules in the table:

Virtual Cloud Networks - Ingress Rules

You should also add an IPv6 egress rule, so that the VM instance can reach Internet resources over IPv6.
To do that, select "Egress Rules" tab on the left side "Resources" menu.
Click Add Egress Rules button, and enter the following rule in the popup dialog (IPv6 step 5):

  • Allow IPv6 Internet access
    • stateless: no
    • destination CIDR: ::/0
    • IP protocol: All Protocols

Install HTTP Server

With the firewall rules in place, we are ready to install an HTTP server.
In this guide, I'm installing Caddy HTTP server along with PHP-FPM.
They can be installed from Caddy package repository and ondrej/php PPA respectively.

# see "Caddy package repository" link above for how to add Caddy APT repository
sudo add-apt-repository ppa:ondrej/php
sudo apt install caddy php8.1-fpm

Before we can start the HTTP server, there's one more firewall to configure: the local iptables.
Oracle Cloud not only has an external firewall at subnet level, but also blocks traffic in iptables INPUT chain.
We can setup a systemd service to insert iptables rules before Caddy starts:

sudoedit /etc/systemd/system/caddy-iptables.service
  (paste the caddy-iptables.service content)

sudo systemctl daemon-reload
sudo systemctl enable --now caddy-iptables

The systemd unit file caddy-iptables.service should have the following content:

[Unit]
Description=Firewall rules for Caddy
Before=caddy.service

[Service]
ExecStartPre=+/usr/sbin/iptables -I INPUT -p tcp --dport 80 -j ACCEPT
ExecStartPre=+/usr/sbin/iptables -I INPUT -p tcp --dport 443 -j ACCEPT
ExecStartPre=+/usr/sbin/iptables -I INPUT -p udp --dport 443 -j ACCEPT
ExecStartPre=+/usr/sbin/ip6tables -I INPUT -p tcp --dport 80 -j ACCEPT
ExecStartPre=+/usr/sbin/ip6tables -I INPUT -p tcp --dport 443 -j ACCEPT
ExecStartPre=+/usr/sbin/ip6tables -I INPUT -p udp --dport 443 -j ACCEPT
ExecStart=true
RemainAfterExit=yes
ExecStopPost=+/usr/sbin/iptables -D INPUT -p tcp --dport 80 -j ACCEPT
ExecStopPost=+/usr/sbin/iptables -D INPUT -p tcp --dport 443 -j ACCEPT
ExecStopPost=+/usr/sbin/iptables -D INPUT -p udp --dport 443 -j ACCEPT
ExecStopPost=+/usr/sbin/ip6tables -D INPUT -p tcp --dport 80 -j ACCEPT
ExecStopPost=+/usr/sbin/ip6tables -D INPUT -p tcp --dport 443 -j ACCEPT
ExecStopPost=+/usr/sbin/ip6tables -D INPUT -p udp --dport 443 -j ACCEPT

[Install]
RequiredBy=caddy.service

Upload your website content, and make sure the www-data group can access them.
In this example, I'll create two simple files:

sudo mkdir -p /var/www/html
echo '<h1>hello</h1>' | sudo tee /var/www/html/index.html
echo '<?php phpinfo(); ?>' | sudo tee /var/www/html/phpinfo.php
sudo chgrp -R www-data /var/www/html

Edit the Caddyfile (/etc/caddy/Caddyfile), paste the following:
(change the domain name and root directory as appropriate)

{
  servers {
    protocol {
      experimental_http3
    }
  }
}

https://demo.example.com {
  root * /var/www/html
  file_server
  php_fastcgi unix//run/php/php8.1-fpm.sock

  header {
    Strict-Transport-Security max-age=2592000
    X-Frame-Options SAMEORIGIN
    X-Content-Type-Options nosniff
    Referrer-Policy no-referrer-when-downgrade
  }
}

Finally, restart the webserver for the settings to take effect:

sudo systemctl restart caddy
sudo systemctl restart php8.1-fpm

Test the Website

To confirm everything is working, we can visit the index page https://demo.example.com/ and the PHP script https://demo.example.com/phpinfo.php in the browser.

Then, we use the curl command line tool (on a different machine) to check that:

  • HTTP-to-HTTPS redirect is working properly.
  • The website is served over HTTP/1.0, HTTP/1.1, HTTP/2, and HTTP/3.
  • The server is accessible over both IPv4 and IPv6.
$ curl -4 --http1.0 -I http://demo.example.com/
HTTP/1.0 308 Permanent Redirect
Connection: close
Location: https://demo.example.com/
Server: Caddy
Date: Fri, 28 Jan 2022 02:16:43 GMT

$ curl -6 --http1.0 -I http://demo.example.com/
HTTP/1.0 308 Permanent Redirect
Connection: close
Location: https://demo.example.com/
Server: Caddy
Date: Fri, 28 Jan 2022 02:16:43 GMT

$ curl -4 --http1.1 -I http://demo.example.com/
HTTP/1.1 308 Permanent Redirect
Connection: close
Location: https://demo.example.com/
Server: Caddy
Date: Fri, 28 Jan 2022 02:16:44 GMT

$ curl -6 --http1.1 -I http://demo.example.com/
HTTP/1.1 308 Permanent Redirect
Connection: close
Location: https://demo.example.com/
Server: Caddy
Date: Fri, 28 Jan 2022 02:16:44 GMT

$ curl -4 --http1.1 -I https://demo.example.com/
HTTP/1.1 200 OK
Accept-Ranges: bytes
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
Content-Length: 15
Content-Type: text/html; charset=utf-8
Etag: "r6edtff"
Last-Modified: Fri, 28 Jan 2022 02:05:39 GMT
Referrer-Policy: no-referrer-when-downgrade
Server: Caddy
Strict-Transport-Security: max-age=2592000
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Date: Fri, 28 Jan 2022 02:16:45 GMT

$ curl -6 --http1.1 -I https://demo.example.com/
HTTP/1.1 200 OK
Accept-Ranges: bytes
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
Content-Length: 15
Content-Type: text/html; charset=utf-8
Etag: "r6edtff"
Last-Modified: Fri, 28 Jan 2022 02:05:39 GMT
Referrer-Policy: no-referrer-when-downgrade
Server: Caddy
Strict-Transport-Security: max-age=2592000
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Date: Fri, 28 Jan 2022 02:16:45 GMT

$ curl -4 --http2 -I https://demo.example.com/
HTTP/2 200
accept-ranges: bytes
alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
content-type: text/html; charset=utf-8
etag: "r6edtff"
last-modified: Fri, 28 Jan 2022 02:05:39 GMT
referrer-policy: no-referrer-when-downgrade
server: Caddy
strict-transport-security: max-age=2592000
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
content-length: 15
date: Fri, 28 Jan 2022 02:16:46 GMT

$ curl -6 --http2 -I https://demo.example.com/
HTTP/2 200
accept-ranges: bytes
alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
content-type: text/html; charset=utf-8
etag: "r6edtff"
last-modified: Fri, 28 Jan 2022 02:05:39 GMT
referrer-policy: no-referrer-when-downgrade
server: Caddy
strict-transport-security: max-age=2592000
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
content-length: 15
date: Fri, 28 Jan 2022 02:16:46 GMT

$ docker run -t --rm --network host ymuski/curl-http3 curl -4 --http3 -I https://demo.example.com/
HTTP/3 200
server: Caddy
alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
x-content-type-options: nosniff
last-modified: Fri, 28 Jan 2022 02:05:39 GMT
content-type: text/html; charset=utf-8
accept-ranges: bytes
content-length: 15
referrer-policy: no-referrer-when-downgrade
strict-transport-security: max-age=2592000
x-frame-options: SAMEORIGIN
etag: "r6edtff"

$ docker run -t --rm --network host ymuski/curl-http3 curl -6 --http3 -I https://demo.example.com/
HTTP/3 200
x-frame-options: SAMEORIGIN
etag: "r6edtff"
accept-ranges: bytes
content-length: 15
server: Caddy
alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
referrer-policy: no-referrer-when-downgrade
strict-transport-security: max-age=2592000
x-content-type-options: nosniff
content-type: text/html; charset=utf-8
last-modified: Fri, 28 Jan 2022 02:05:39 GMT

Finally, we use SSL Server Test to verify that TLS certificates and crypto are configured securely, and use Security Headers to check that HTTP Strict Transport Security is setup correctly.

Conclusion

This article explains how to deploy a website in a VM instance on Oracle Cloud Free Tier.
It involves the following steps:

  1. Create an always free compute VM instance.
  2. Enable IPv6 in the Virtual Cloud Network, subnet, and VM instance.
  3. Add ingress and egress rules in the network Security List.
  4. Install Caddy HTTP server and PHP.
  5. Configure local iptables firewall.
  6. Test the website installation.

Comments

  • havochavoc OGContent Writer

    Just be sure to have a backup & plan B. They fucked over a bunch of people by killing trials unexpectedly

  • Nicely done.
    You should add the minimum amount of push-ups required to make everything work well

    Thanked by (1)Asim

    ———-
    blog | exploring visually |

  • A great article as always!

    Definitely will try to sign up for their free plan :smiley:

  • Quality content, thanks so much for this write-up.

  • @havoc said:
    Just be sure to have a backup & plan B. They fucked over a bunch of people by killing trials unexpectedly

    i received marketing calls from oracle regard the service and whatnot. sound nice enough and dont think they would really kills the trials without any notice...
    plus, one of my premium 32gb instance had not been reclaimed after 2 months overdue of trial...still running..of course i no longer do anything serious on it...
    and free instance works too, do have website on it
    the account come with 20gb free s3 compatible s3 storage, mounted it up with rclone and works like magic.

  • Not_OlesNot_Oles Hosting ProviderContent Writer

    @yoursunny Wow! Your tutorials are so well written! Always a pleasure to read because of how well written they are, regardless of whether I am relatively more or less interested in the content.

    @yoursunny said: 48Mbps Internet bandwidth

    The screenshot seems to say "Network Bandwidth (Gbps): 0.48"

    Are people using Oracle Cloud any better protected from "surprise billing" than people using, say, Amazon Web Services or Google Cloud Platform?

    I hope everyone gets the servers they want!

  • @yoursunny said: 48Mbps Internet bandwidth

    @Not_Oles said:
    The screenshot seems to say "Network Bandwidth (Gbps): 0.48"

    The port is 480Mbps, but you can only get to this speed within the data center.
    Internet bandwidth is 48Mbps.

    YABS in Tokyo

    iperf3 Network Speed Tests (IPv4):
    ---------------------------------
    Provider        | Location (Link)           | Send Speed      | Recv Speed     
                    |                           |                 |                
    Clouvider       | London, UK (10G)          | 44.8 Mbits/sec  | 44.9 Mbits/sec 
    Online.net      | Paris, FR (10G)           | 44.6 Mbits/sec  | 45.4 Mbits/sec 
    WorldStream     | The Netherlands (10G)     | 43.8 Mbits/sec  | 44.6 Mbits/sec 
    Wifx            | Zurich, CH (10G)          | 42.4 Mbits/sec  | 40.8 Mbits/sec 
    Biznet          | Jakarta, Indonesia (1G)   | 48.2 Mbits/sec  | 40.7 Mbits/sec 
    Clouvider       | NYC, NY, US (10G)         | 46.6 Mbits/sec  | 45.8 Mbits/sec 
    Velocity Online | Tallahassee, FL, US (10G) | 45.1 Mbits/sec  | 45.7 Mbits/sec 
    Clouvider       | Los Angeles, CA, US (10G) | busy            | busy           
    Iveloz Telecom  | Sao Paulo, BR (2G)        | busy            | busy    
    

    48Mbps is enough for small websites.
    If you have a large website, you can afford a larger instance with SR-IOV ports.

    Thanked by (3)Not_Oles ferri Asim
  • Oracle Cloud now supports IPv6.
    The article has been updated to enable IPv6 on the web server.

    Thanked by (2)Not_Oles Ganonk
  • @yoursunny said:
    Oracle Cloud now supports IPv6.
    The article has been updated to enable IPv6 on the web server.

    Even so, won't they still end up in your naughty list since it does not provide /128 + /64?

    Thanked by (1)yoursunny

    The all seeing eye sees everything...

  • @terrorgen said:

    @yoursunny said:
    Oracle Cloud now supports IPv6.
    The article has been updated to enable IPv6 on the web server.

    Even so, won't they still end up in your naughty list since it does not provide /128 + /64?

    You get /56

  • I stopped reading at

    up to 20 IPv6 addresses

    Jokes on me

    The all seeing eye sees everything...

  • @terrorgen said:
    I stopped reading at

    up to 20 IPv6 addresses

    Jokes on me

    That's mistaken and has been corrected.

    According to Oracle Cloud Infrastructure Documentation - IPv6 Addresses:

    You also choose whether a given VNIC in an IPv6-enabled subnet has IPv6 addresses (up to 32 maximum per VNIC).

  • bibblebibble OG
    edited February 2022

    Bumping this. Very good @yoursunny B) :+1:

    Seems so complicated without this write up :D

Sign In or Register to comment.