How to Host a Website in Oracle Cloud Free Tier

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

  • KVM virtualization
  • 1/8 CPU cores (AMD EPYC 7551)
  • 1GB memory
  • 45GB disk storage
  • 1 IPv4 address, no IPv6
  • 48Mbps 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.

Create a VM Instance

Each Oracle Cloud account is eligible for two Always Free VM instances. To create a VM, sign in to the Oracle Cloud console, in "Quick Actions" section click Create a VM instance.

Oracle Cloud console - Quick Actions

This takes us to the "Create Compute Instance" page.

In "Configure placement and hardware" section, change the "image" to Canonical Ubuntu 20.04. Do not select the "Canonical Ubuntu 20.04 Minimal" option.

Create Compute Instance - Configure placement and hardware

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

Create Compute Instance - Configure networking

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 now SSH into the VM instance using the public IP address and username displayed in the "Instance Access" section. This is also a good time to add a DNS record toward the public IP address, so that we can activate HTTPS later.

DNS record

Configure Ingress 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 two rules:

  • Allow HTTP/1.1 and HTTP/2
    • stateless: disabled
    • source CIDR:
    • IP protocol: TCP
    • destination port range: 80,443
  • Allow HTTP/3
    • stateless: disabled
    • source CIDR:
    • IP protocol: UDP
    • destination port range: 443

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

Virtual Cloud Networks - Ingress Rules

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.0-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 caddy-iptables
sudo systemctl start caddy-iptables

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

Description=Firewall rules for Caddy

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
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


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

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

} {
  root * /var/www/html
  php_fastcgi unix//run/php/php8.0-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.0-fpm

Test the Website

To confirm everything is working, we can visit the index page and the PHP script in the browser.

Then, we execute the curl command line tool (on a different machine) to confirm the HTTP-to-HTTPS redirect is working properly, and the website works over HTTP/1.0, HTTP/1.1, HTTP/2, and HTTP/3.

$ curl --http1.0 -I
HTTP/1.0 308 Permanent Redirect
Connection: close
Server: Caddy
Date: Fri, 25 Dec 2020 20:17:10 GMT

$ curl --http1.1 -I
HTTP/1.1 308 Permanent Redirect
Connection: close
Server: Caddy
Date: Fri, 25 Dec 2020 20:17:14 GMT

$ curl --http1.1 -I
HTTP/1.1 200 OK
Accept-Ranges: bytes
Alt-Svc: h3-29=":443"; ma=2592000
Content-Length: 15
Content-Type: text/html; charset=utf-8
Etag: "qlwrw5f"
Last-Modified: Fri, 25 Dec 2020 18:40:53 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, 25 Dec 2020 20:17:18 GMT

$ curl --http2 -I
HTTP/2 200
accept-ranges: bytes
alt-svc: h3-29=":443"; ma=2592000
content-type: text/html; charset=utf-8
etag: "qlwrw5f"
last-modified: Fri, 25 Dec 2020 18:40:53 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, 25 Dec 2020 20:17:23 GMT

$ docker run -it --rm ymuski/curl-http3 curl --http3 -I
HTTP/3 200
referrer-policy: no-referrer-when-downgrade
strict-transport-security: max-age=2592000
x-content-type-options: nosniff
etag: "qlwrw5f"
last-modified: Fri, 25 Dec 2020 18:40:53 GMT
accept-ranges: bytes
x-frame-options: SAMEORIGIN
alt-svc: h3-29=":443"; ma=2592000
content-type: text/html; charset=utf-8
content-length: 15
server: Caddy

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.


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. Add ingress rules in Virtual Cloud Network subnet.
  3. Install Caddy HTTP server and PHP.
  4. Configure local iptables firewall.
  5. Test the website installation.

Join the discussion: LowEndSpirit LowEndTalk DEV Community