<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
    xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Oracle Cloud — LowEndSpirit</title>
        <link>https://staging.lowendspirit.com/index.php?p=/</link>
        <pubDate>Sat, 11 Apr 2026 19:08:26 +0000</pubDate>
        <language>en</language>
            <description>Oracle Cloud — LowEndSpirit</description>
    <atom:link href="https://staging.lowendspirit.com/index.php?p=/discussions/tagged/oracle-cloud/feed.rss" rel="self" type="application/rss+xml"/>
    <item>
        <title>[Fixed?] Tiny, But Heroic Oracle Free Tier VPS Runs Out Of Memory During DNF Upgrade!</title>
        <link>https://staging.lowendspirit.com/index.php?p=/discussion/5922/fixed-tiny-but-heroic-oracle-free-tier-vps-runs-out-of-memory-during-dnf-upgrade</link>
        <pubDate>Mon, 15 May 2023 18:51:26 +0000</pubDate>
        <category>Help</category>
        <dc:creator>Not_Oles</dc:creator>
        <guid isPermaLink="false">5922@/index.php?p=/discussions</guid>
        <description><![CDATA[<h2>Oracle Free Tier Powers The MetalVPS Website</h2>

<p>The <a rel="nofollow" href="https://metalvps.com">MetalVPS website</a> is served by a tiny, but heroic <a rel="nofollow" href="https://www.oracle.com/cloud/free/">Oracle Cloud Free Tier VPS</a> The specs are:</p>

<p>VM.Standard.E2.1.Micro.<br />
OCPU count: 1<br />
Memory (GB): 1<br />
Boot Volume Size: 47 GB <br />
Network bandwidth (Gbps): 0.48<br />
Launched: Sun, Jul 17, 2022, 23:25:22 UTC</p>

<p>The instance has been up the best part of a year:</p>

<pre><code>[opc@instance-20220717-1620 ~]$ uptime
 15:27:35 up 301 days, 16:01,  1 user,  load average: 0.06, 0.08, 0.02
[opc@instance-20220717-1620 ~]$ 
</code></pre>

<h2>Recent Downtime Alerts From Hetrix Tools</h2>

<p>Recently I started receiving alerts from <a rel="nofollow" href="https://hetrixtools.com/">Hetrix Tools</a> about the MetalVPS website being down briefly, just a few minutes at a time, but repeatedly. I confirmed that I couldn't access the website from my Chromebook during the periods when Hetrix said the site was down. Additionally, my ssh connection to the instance stopped working when Hetrix said the site was down. Luckily, I had redundant backups, so all the files were safe.</p>

<p>Checking the logs suggested that periodic DNF updates were causing the tiny, but valiant VPS to run out of memory. When there was no memory, the web server and the ssh server couldn't work. After the OOM killer decided it was time to kill the DNF update, then the web server and the ssh server could serve again.</p>

<p>Just for fun, I repeatedly ran <code>free -h</code> during a manually initiated <code>dnf upgrade</code> to see what happened. Watch the swap go all the way down to zero:</p>

<h2>Swap Drops To Zero During DNF Upgrade</h2>

<pre><code>chronos@penguin:~/servers/oracle/metalvps$ ssh m
Activate the web console with: systemctl enable --now cockpit.socket

Last login: Fri May  5 01:56:22 2023 from 187.189.238.1
[opc@instance-20220717-1620 ~]$ free -h
              total        used        free      shared  buff/cache   available
Mem:          680Mi       189Mi       364Mi       1.0Mi       126Mi       384Mi
Swap:         1.3Gi       463Mi       896Mi
[opc@instance-20220717-1620 ~]$ free -h
              total        used        free      shared  buff/cache   available
Mem:          680Mi       244Mi       236Mi       1.0Mi       199Mi       329Mi
Swap:         1.3Gi       460Mi       899Mi
[opc@instance-20220717-1620 ~]$ free -h
              total        used        free      shared  buff/cache   available
Mem:          680Mi       258Mi        50Mi       1.0Mi       371Mi       316Mi
Swap:         1.3Gi       460Mi       899Mi
[opc@instance-20220717-1620 ~]$ free -h
              total        used        free      shared  buff/cache   available
Mem:          680Mi       397Mi        50Mi       1.0Mi       231Mi       176Mi
Swap:         1.3Gi       460Mi       899Mi
[opc@instance-20220717-1620 ~]$ free -h
              total        used        free      shared  buff/cache   available
Mem:          680Mi       583Mi        47Mi       0.0Ki        49Mi        21Mi
Swap:         1.3Gi       546Mi       813Mi
[opc@instance-20220717-1620 ~]$ free -h
              total        used        free      shared  buff/cache   available
Mem:          680Mi       576Mi        46Mi       0.0Ki        56Mi        24Mi
Swap:         1.3Gi       719Mi       640Mi
[opc@instance-20220717-1620 ~]$ free -h
              total        used        free      shared  buff/cache   available
Mem:          680Mi       552Mi        57Mi       0.0Ki        70Mi        42Mi
Swap:         1.3Gi       870Mi       489Mi
[opc@instance-20220717-1620 ~]$ free -h
              total        used        free      shared  buff/cache   available
Mem:          680Mi       563Mi        42Mi       0.0Ki        74Mi        29Mi
Swap:         1.3Gi       1.0Gi       289Mi
[opc@instance-20220717-1620 ~]$ free -h
              total        used        free      shared  buff/cache   available
Mem:          680Mi       559Mi        58Mi       0.0Ki        62Mi        39Mi
Swap:         1.3Gi       1.2Gi       123Mi
[opc@instance-20220717-1620 ~]$ free -h
              total        used        free      shared  buff/cache   available
Mem:          680Mi       604Mi        31Mi       0.0Ki        43Mi       3.0Mi
Swap:         1.3Gi       1.3Gi       0.0Ki
</code></pre>

<h2>After OOM</h2>

<pre><code>[opc@instance-20220717-1620 ~]$ free -h
              total        used        free      shared  buff/cache   available
Mem:          680Mi       166Mi       433Mi       0.0Ki        80Mi       422Mi
Swap:         1.3Gi       484Mi       875Mi
[opc@instance-20220717-1620 ~]$ 
</code></pre>

<h2>Memory Issues Fixed By Adding Swap</h2>

<p>The memory issues seem to have been fixed by adding additional swap. Here's a link to a tutorial which I found helpful: <a href="https://www.cyberciti.biz/faq/linux-add-a-swap-file-howto/" rel="nofollow">https://www.cyberciti.biz/faq/linux-add-a-swap-file-howto/</a></p>

<p>The Oracle install already had a swap file, but I added a second, larger swap file. Note that these swap files are within the partition on which the OS is located, not on separate partitions as usually is the case for swap.</p>

<p>Back in the old days, I always could set up machines with plenty of swap. Nowadays, on the clouds, often the VMs come without swap. On HN, I read that swap might be less popular these days since swap could present a security issue. Swap could contain private data which needs protection.</p>

<p>But, by adding a swap file, some tiny VPSes can do big jobs! I seem to remember compiling a <em>ton</em> of software out of <a rel="nofollow" href="https://www.pkgsrc.org/">pkgsrc</a> on a different, but also tiny Oracle VPS running CentOS. Was it all just a matter of adding some swap and then eating dinner and sleeping while pkgsrc reliably finished its enormous workload on the tiny Oracle VPS?</p>

<p>Here's what the terminal output looked like during the addition of extra swap space followed by a successful <code>dnf upgrade</code>.</p>

<pre><code>[opc@instance-20220717-1620 ~]$ swapon -s
Filename                                Type            Size    Used    Priority
/.swapfile                              file            1392636 461880  -2
[opc@instance-20220717-1620 ~]$ ls -lh /.swapfile 
-rw-------. 1 root root 1.4G Jul 17  2022 /.swapfile
[opc@instance-20220717-1620 ~]$ sudo su -
Last login: Sat May 13 04:36:56 GMT 2023 on pts/0
[root@instance-20220717-1620 ~]# cd /
[root@instance-20220717-1620 /]# df -h .
Filesystem                  Size  Used Avail Use% Mounted on
/dev/mapper/ocivolume-root   36G   11G   25G  31% /
[root@instance-20220717-1620 /]# dd if=/dev/zero of=/.swapfile1 bs=1024 count=2093152
2093152+0 records in
2093152+0 records out
2143387648 bytes (2.1 GB, 2.0 GiB) copied, 39.7653 s, 53.9 MB/s
[root@instance-20220717-1620 /]# ls -l .swapfile*
-rw-------. 1 root root 1426063360 Jul 17  2022 .swapfile
-rw-r--r--. 1 root root 2143387648 May 13 21:22 .swapfile1
[root@instance-20220717-1620 /]# chmod 0600 .swapfile1
[root@instance-20220717-1620 /]# ls -l .swapfile*
-rw-------. 1 root root 1426063360 Jul 17  2022 .swapfile
-rw-------. 1 root root 2143387648 May 13 21:22 .swapfile1
[root@instance-20220717-1620 /]# mkswap /.swapfile1
Setting up swapspace version 1, size = 2 GiB (2143383552 bytes)
[ . . . ]
[root@instance-20220717-1620 /]# swapon /.swapfile1
[root@instance-20220717-1620 /]# swapon -s
Filename                                Type            Size    Used    Priority
/.swapfile                              file            1392636 461528  -2
/.swapfile1                             file            2093148 0       -3
[root@instance-20220717-1620 /]# date -u
Sat May 13 21:30:53 UTC 2023
[root@instance-20220717-1620 /]# dnf upgrade
Oracle Linux 8 BaseOS Latest (x86_64)                          4.9 kB/s | 3.6 kB     00:00    
Oracle Linux 8 Application Stream (x86_64)                     149 kB/s | 3.9 kB     00:00    
Oracle Linux 8 Addons (x86_64)                                  57 kB/s | 3.0 kB     00:00    
Latest Unbreakable Enterprise Kernel Release 6 for Oracle Linu  83 kB/s | 3.0 kB     00:00    
Last metadata expiration check: 0:00:01 ago on Sat 13 May 2023 08:17:46 PM GMT.
Dependencies resolved.
===============================================================================================
 Package                Architecture Version                            Repository        Size
===============================================================================================
Installing:
 kernel-uek             x86_64       5.4.17-2136.318.7.2.el8uek         ol8_UEKR6        112 M
 kernel-uek-devel       x86_64       5.4.17-2136.318.7.2.el8uek         ol8_UEKR6         19 M
Removing:
 kernel-uek             x86_64       5.4.17-2136.317.5.5.el8uek         @ol8_UEKR6       136 M
 kernel-uek-devel       x86_64       5.4.17-2136.317.5.5.el8uek         @ol8_UEKR6        75 M

Transaction Summary
===============================================================================================
Install  2 Packages
Remove   2 Packages

Total download size: 131 M
Is this ok [y/N]: y
Downloading Packages:
(1/2): kernel-uek-devel-5.4.17-2136.318.7.2.el8uek.x86_64.rpm   19 MB/s |  19 MB     00:01    
(2/2): kernel-uek-5.4.17-2136.318.7.2.el8uek.x86_64.rpm         30 MB/s | 112 MB     00:03    
-----------------------------------------------------------------------------------------------
Total                                                           35 MB/s | 131 MB     00:03     
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Preparing        :                                                                       1/1 
  Installing       : kernel-uek-devel-5.4.17-2136.318.7.2.el8uek.x86_64                    1/4 
  Running scriptlet: kernel-uek-devel-5.4.17-2136.318.7.2.el8uek.x86_64                    1/4 
  Running scriptlet: kernel-uek-5.4.17-2136.318.7.2.el8uek.x86_64                          2/4 
  Installing       : kernel-uek-5.4.17-2136.318.7.2.el8uek.x86_64                          2/4 
  Running scriptlet: kernel-uek-5.4.17-2136.318.7.2.el8uek.x86_64                          2/4 
  Erasing          : kernel-uek-devel-5.4.17-2136.317.5.5.el8uek.x86_64                    3/4 
  Running scriptlet: kernel-uek-5.4.17-2136.317.5.5.el8uek.x86_64                          4/4 
  Erasing          : kernel-uek-5.4.17-2136.317.5.5.el8uek.x86_64                          4/4 
  Running scriptlet: kernel-uek-5.4.17-2136.317.5.5.el8uek.x86_64                          4/4 
  Running scriptlet: kernel-uek-5.4.17-2136.318.7.2.el8uek.x86_64                          4/4 
  Running scriptlet: kernel-uek-5.4.17-2136.317.5.5.el8uek.x86_64                          4/4 
  Verifying        : kernel-uek-5.4.17-2136.318.7.2.el8uek.x86_64                          1/4 
  Verifying        : kernel-uek-devel-5.4.17-2136.318.7.2.el8uek.x86_64                    2/4 
  Verifying        : kernel-uek-5.4.17-2136.317.5.5.el8uek.x86_64                          3/4 
  Verifying        : kernel-uek-devel-5.4.17-2136.317.5.5.el8uek.x86_64                    4/4 

Installed:
  kernel-uek-5.4.17-2136.318.7.2.el8uek.x86_64                                                 
  kernel-uek-devel-5.4.17-2136.318.7.2.el8uek.x86_64                                           
Removed:
  kernel-uek-5.4.17-2136.317.5.5.el8uek.x86_64                                                 
  kernel-uek-devel-5.4.17-2136.317.5.5.el8uek.x86_64                                           

Complete!
[root@instance-20220717-1620 /]# date
Sat May 13 21:44:31 GMT 2023
[root@instance-20220717-1620 /]# uname -r
5.4.17-2136.308.9.el8uek.x86_64
[root@instance-20220717-1620 /]# cat /etc/os-release 
NAME="Oracle Linux Server"
VERSION="8.7"
ID="ol"
ID_LIKE="fedora"
VARIANT="Server"
VARIANT_ID="server"
VERSION_ID="8.7"
PLATFORM_ID="platform:el8"
PRETTY_NAME="Oracle Linux Server 8.7"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:oracle:linux:8:7:server"
HOME_URL="https://linux.oracle.com/"
BUG_REPORT_URL="https://bugzilla.oracle.com/"

ORACLE_BUGZILLA_PRODUCT="Oracle Linux 8"
ORACLE_BUGZILLA_PRODUCT_VERSION=8.7
ORACLE_SUPPORT_PRODUCT="Oracle Linux"
ORACLE_SUPPORT_PRODUCT_VERSION=8.7
[root@instance-20220717-1620 /]# 
</code></pre>

<p>There have been no more downtime alerts from Hetrix since the extra swap was added.</p>

<h2>Additional Steps</h2>

<p>At least a couple more things might need to be done.</p>

<ul>
<li><p>First, to persist past reboots, the extra swap needs to be added to /etc/fstab and/or synced with whatever systemd might contribute.</p></li>
<li><p>Second, the running kernel (5.4.17-2136.308.9.el8uek.x86_64) doesn't seem to be quite the same as the most recently installed kernel (5.4.17-2136.318.7.2.el8uek.x86_64). So maybe a reboot is needed?</p></li>
</ul>

<h2>The Bigger Picture</h2>

<p>I don't understand why this problem happened. Also, I don't understand why this problem happened at the time it happened, rather than sooner or later.</p>

<ul>
<li><p>Could it be that the tiny but heroic VM specs are too small to expect <code>dnf</code> to work?</p></li>
<li><p>Did I misconfigure something or make some other mistake which caused <code>dnf</code> to run out of space?</p></li>
<li><p>Was the current <code>dnf</code> upgrade unusually big, such that it required more space than expected.</p></li>
<li><p>Was the problem caused by something else other than <code>dnf</code>?</p></li>
<li><p>Was it correct to add a second swap file? Should there be only one? I could have replaced the existing swap file with another, larger swap file, thus keeping only one swap file.</p></li>
<li><p>Maybe /etc/fstab still is meaningful in systemd distros?</p></li>
<li><p>Maybe the VPS will survive a reboot?</p></li>
<li><p>How applicable is all this to other guys running tiny, but heroic Oracle Free Tier VPSes? Are they all fated to run out of memory after a while?</p></li>
<li><p>What about other tiny VPSes on providers other than Oracle and running OSes other than Oracle Linux?</p></li>
</ul>

<p>Over the next days, maybe I will get to understand more. <img src="https://staging.lowendspirit.com/plugins/emojiextender/emoji/twitter/smile.png" title=":)" alt=":)" height="18" /> Thanks again to Oracle for the nifty, heroic free VPS!</p>

<p>Best wishes! <img src="https://staging.lowendspirit.com/plugins/emojiextender/emoji/twitter/heart.png" title="&lt;3" alt="&lt;3" height="18" /> I hope everyone gets the server he wants! 🤩</p>
]]>
        </description>
    </item>
    <item>
        <title>Unable to update WordPress due to incorrect file permission</title>
        <link>https://staging.lowendspirit.com/index.php?p=/discussion/4474/unable-to-update-wordpress-due-to-incorrect-file-permission</link>
        <pubDate>Fri, 19 Aug 2022 05:54:44 +0000</pubDate>
        <category>Help</category>
        <dc:creator>lesuser</dc:creator>
        <guid isPermaLink="false">4474@/index.php?p=/discussions</guid>
        <description><![CDATA[<p>I am getting error while updating plugin. This is Oracle Linux Arm Ampere instance.</p>

<blockquote><div>
  <p>An error occurred while updating Akismet Anti-Spam: Could not create directory.</p>
</div></blockquote>

<p>I have applied following permission on files and folders.</p>

<pre><code>sudo chown -R nginx:nginx /var/www/mysite/html
sudo find /var/www/mysite/html -type d -exec chmod 755 {} \;
sudo find /var/www/mysite/html -type f -exec chmod 644 {} \;
</code></pre>

<p>I have another WordPress site on VirMach VPS with same permission and there it updates fine. Here's result of <code>ls -l</code></p>

<pre><code>[opc@arm html]$ ls -l
total 212
-rw-r--r--  1 nginx nginx   405 Feb  6  2020 index.php
-rw-r--r--  1 nginx nginx 19915 Jan  1  2022 license.txt
-rw-r--r--  1 nginx nginx  7401 Mar 22 21:11 readme.html
-rw-r--r--  1 nginx nginx  7165 Jan 21  2021 wp-activate.php
drwxr-xr-x  9 nginx nginx  4096 Jul 12 16:16 wp-admin
-rw-r--r--  1 nginx nginx   351 Feb  6  2020 wp-blog-header.php
-rw-r--r--  1 nginx nginx  2338 Nov  9  2021 wp-comments-post.php
-rw-r--r--  1 nginx nginx  3230 Aug 18 17:53 wp-config.php
drwxr-xr-x  4 nginx nginx    52 Jul 12 16:16 wp-content
-rw-r--r--  1 nginx nginx  3943 Apr 28 09:49 wp-cron.php
drwxr-xr-x 26 nginx nginx 12288 Jul 12 16:16 wp-includes
-rw-r--r--  1 nginx nginx  2494 Mar 19 20:31 wp-links-opml.php
-rw-r--r--  1 nginx nginx  3973 Apr 12 01:47 wp-load.php
-rw-r--r--  1 nginx nginx 48498 Apr 29 14:36 wp-login.php
-rw-r--r--  1 nginx nginx  8577 Mar 22 16:25 wp-mail.php
-rw-r--r--  1 nginx nginx 23706 Apr 12 09:26 wp-settings.php
-rw-r--r--  1 nginx nginx 32051 Apr 11 11:42 wp-signup.php
-rw-r--r--  1 nginx nginx  4748 Apr 11 11:42 wp-trackback.php
-rw-r--r--  1 nginx nginx  3236 Jun  8  2020 xmlrpc.php
</code></pre>

<p>Site Health in WordPress says:</p>

<pre><code>Shows whether WordPress is able to write to the directories it needs access to.

The main WordPress directory    Not writable
The wp-content directory    Not writable
The uploads directory   Not writable
The plugins directory   Not writable
The themes directory    Not writable
</code></pre>

<p>But the other site on VirMach VPS says these folders are writeable.</p>

<p>SELinux is disabled.</p>
]]>
        </description>
    </item>
    <item>
        <title>How to Host a Website in Oracle Cloud Free Tier</title>
        <link>https://staging.lowendspirit.com/index.php?p=/discussion/2339/how-to-host-a-website-in-oracle-cloud-free-tier</link>
        <pubDate>Tue, 29 Dec 2020 14:46:26 +0000</pubDate>
        <category>Technical</category>
        <dc:creator>yoursunny</dc:creator>
        <guid isPermaLink="false">2339@/index.php?p=/discussions</guid>
        <description><![CDATA[<blockquote><div>
  <p>This post is originally published on yoursunny.com blog <a href="https://yoursunny.com/t/2020/OracleCloud-website/" rel="nofollow">https://yoursunny.com/t/2020/OracleCloud-website/</a></p>
</div></blockquote>

<p><strong>Oracle Cloud</strong> is a cloud computing service offered by Oracle Corporation.<br />
Oracle Cloud has a generous <a rel="nofollow" href="https://www.oracle.com/cloud/free/">free tier</a> that offers two "always free" Micro instances with the following <a rel="nofollow" href="https://docs.oracle.com/en-us/iaas/Content/FreeTier/freetier_topic-Always_Free_Resources.htm">specification</a>:</p>

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

<p>I <a rel="nofollow" href="https://www.oracle.com/cloud/free/">signed up</a> for Oracle Cloud, so that I can have some more free computing resources to play with.<br />
The sign-up procedure requires a credit card for identity confirmation purpose, but the credit card will not be charged.<br />
During sign-up, there's a choice of <em>home region</em>, which determines the location of VM instances; once selected, it cannot be changed in the future.</p>

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

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

<h2>Create a VM Instance</h2>

<p>Each Oracle Cloud account is eligible for two <em>Always Free</em> Micro instances.<br />
To create a VM, <a rel="nofollow" href="https://cloud.oracle.com/">sign in to the Oracle Cloud console</a>, in "Launch Resources" section click <strong>Create a VM instance</strong>.<br />
This takes us to the "Create Compute Instance" page.</p>

<p>In "Image and shape" section, select <strong>VM.Standard.E2.1.Micro</strong> shape and <strong>Canonical Ubuntu 20.04</strong> image.<br />
Do not use the "Canonical Ubuntu 20.04 Minimal" image.</p>

<p><img src="https://yoursunny.com/t/2020/OracleCloud-website/ImageShape.png" alt="Create Compute Instance - Image and shape" /></p>

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

<p>In "Add SSH keys" section, select <strong>Paste public keys</strong>, and paste your SSH public key in the text box below.<br />
If you do not have a SSH public key, <a rel="nofollow" href="https://git-scm.com/book/en/v2/Git-on-the-Server-Generating-Your-SSH-Public-Key">follow this guide</a> to generate one.</p>

<p>Finally, click the <strong>Create</strong> button to create the compute VM instance.<br />
Within a few seconds, you should see the "Instance Details" page.</p>

<p><img src="https://yoursunny.com/t/2020/OracleCloud-website/InstanceDetails.png" alt="Instance Details" /></p>

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

<h2>Enable IPv6</h2>

<p>In this year, it is important for websites to support IPv6.<br />
Today, most cellular networks are IPv6 only.<br />
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.</p>

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

<ol>
<li>Assign IPv6 CIDR block to the <em>Virtual Cloud Network</em>.</li>
<li>Assign IPv6 CIDR block to the <em>Subnet</em>.</li>
<li>Configure IPv6 <em>Route Rule</em>.</li>
<li>Assign IPv6 Address to the compute VM's <em>VNIC</em>.</li>
<li>Configure firewall rules.</li>
</ol>

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

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

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

<p><img src="https://yoursunny.com/t/2020/OracleCloud-website/CIDR.png" alt="CIDR Blocks" /></p>

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

<p><img src="https://yoursunny.com/t/2020/OracleCloud-website/IPv6CIDR.png" alt="IPv6 CIDR Block" /></p>

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

<ul>
<li>Protocol Version: IPv6</li>
<li>Target Type: Internet Gateway</li>
<li>Destination CIDR Block: <code>::/0</code></li>
<li>Target Internet Gateway: Internet gateway vcn-…</li>
</ul>

<p>Then click <strong>Add Route Rules</strong> button (IPv6 step 3).</p>

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

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

<h2>DNS</h2>

<p>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.<br />
Two DNS records are required: an <em>A record</em> for the public IPv4 address and an <em>AAAA record</em> for the public IPv6 address.<br />
You can find both addresses in the "VNIC Details" page, as described above.</p>

<p><img src="https://yoursunny.com/t/2020/OracleCloud-website/DNS.png" alt="DNS record" /></p>

<h2>Configure Ingress and Egress Rules</h2>

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

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

<ul>
<li><p>Allow HTTP/1.1 and HTTP/2 (IPv4)</p>

<ul>
<li>stateless: no</li>
<li>source CIDR: <code>0.0.0.0/0</code></li>
<li>IP protocol: <code>TCP</code></li>
<li>destination port range: <code>80,443</code></li>
</ul></li>
<li><p>Allow HTTP/1.1 and HTTP/2 (IPv6)</p>

<ul>
<li>stateless: no</li>
<li>source CIDR: <code>::/0</code></li>
<li>IP protocol: <code>TCP</code></li>
<li>destination port range: <code>80,443</code></li>
</ul></li>
<li><p>Allow HTTP/3 (IPv4)</p>

<ul>
<li>stateless: no</li>
<li>source CIDR: <code>0.0.0.0/0</code></li>
<li>IP protocol: <code>UDP</code></li>
<li>destination port range: <code>443</code></li>
</ul></li>
<li><p>Allow HTTP/3 (IPv6)</p>

<ul>
<li>stateless: no</li>
<li>source CIDR: <code>::/0</code></li>
<li>IP protocol: <code>UDP</code></li>
<li>destination port range: <code>443</code></li>
</ul></li>
</ul>

<p>After that, you should see the following ingress rules in the table:</p>

<p><img src="https://yoursunny.com/t/2020/OracleCloud-website/IngressRules.png" alt="Virtual Cloud Networks - Ingress Rules" /></p>

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

<ul>
<li>Allow IPv6 Internet access

<ul>
<li>stateless: no</li>
<li>destination CIDR: <code>::/0</code></li>
<li>IP protocol: <code>All Protocols</code></li>
</ul></li>
</ul>

<h2>Install HTTP Server</h2>

<p>With the firewall rules in place, we are ready to install an HTTP server.<br />
In this guide, I'm installing <a rel="nofollow" href="https://caddyserver.com/">Caddy HTTP server</a> along with PHP-FPM.<br />
They can be installed from <a rel="nofollow" href="https://caddyserver.com/docs/download#debian-ubuntu-raspbian">Caddy package repository</a> and <a rel="nofollow" href="https://launchpad.net/~ondrej/+archive/ubuntu/php">ondrej/php PPA</a> respectively.</p>

<pre><code># 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
</code></pre>

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

<pre><code>sudoedit /etc/systemd/system/caddy-iptables.service
  (paste the caddy-iptables.service content)

sudo systemctl daemon-reload
sudo systemctl enable --now caddy-iptables
</code></pre>

<p>The systemd unit file <code>caddy-iptables.service</code> should have the following content:</p>

<pre><code>[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
</code></pre>

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

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

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

<pre><code>{
  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
  }
}
</code></pre>

<p>Finally, restart the webserver for the settings to take effect:</p>

<pre><code>sudo systemctl restart caddy
sudo systemctl restart php8.1-fpm
</code></pre>

<h2>Test the Website</h2>

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

<p>Then, we use the <a rel="nofollow" href="https://curl.se/">curl</a> command line tool (on a different machine) to check that:</p>

<ul>
<li>HTTP-to-HTTPS redirect is working properly.</li>
<li>The website is served over HTTP/1.0, HTTP/1.1, HTTP/2, and HTTP/3.</li>
<li>The server is accessible over both IPv4 and IPv6.</li>
</ul>

<pre><code>$ 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
</code></pre>

<p>Finally, we use <a rel="nofollow" href="https://www.ssllabs.com/ssltest/index.html">SSL Server Test</a> to verify that TLS certificates and crypto are configured securely, and use <a rel="nofollow" href="https://securityheaders.com/">Security Headers</a> to check that <a rel="nofollow" href="https://scotthelme.co.uk/hsts-the-missing-link-in-tls/">HTTP Strict Transport Security</a> is setup correctly.</p>

<h2>Conclusion</h2>

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

<ol>
<li>Create an always free compute VM instance.</li>
<li>Enable IPv6 in the Virtual Cloud Network, subnet, and VM instance.</li>
<li>Add ingress and egress rules in the network Security List.</li>
<li>Install Caddy HTTP server and PHP.</li>
<li>Configure local iptables firewall.</li>
<li>Test the website installation.</li>
</ol>
]]>
        </description>
    </item>
   </channel>
</rss>
