Front Man: Using NGINX to proxy requests to APEX on ADB

As I reboot this blog, I'd like to create working examples of what I discuss. That's how I learn best - by doing. I'd also like this site to have the same domain name as my new blog, allowing for a more seamless transition as readers jump between the two. Lastly, I don’t want to spend a lot of money to do all of this.

Given these requirements, there's a couple of different choices that I can pick from.

Oracle's Public Instance of APEX

Like over 100,000 other active developers, I could choose to use Oracle's free hosted instance of APEX - apex.oracle.com. All I would have to do is visit https://apex.oracle.com/pls/apex/f?p=4800:1, fill out the form and wait a couple of minutes and I'd have my own workspace.

However, I want to have more control over the environment than what is provided on apex.oracle.com. Thus, I can use Oracle Cloud Infrastructure's "free tier". While you will need a valid credit card to sign up for it, as long as you stick with the always free services, you won't be charged anything. I've had an active account since 2019 and have paid a grand total of $0.00.

OCI Free Tier

OCI's free tier allows you to use a subset of services for free for as long as you'd like. You can see the full list here: https://www.oracle.com/cloud/free/#always-free. To get started, all I really need is an Autonomous Database, as APEX is pre-installed there and there's no need to create and manage ORDS, since that's also provided.

There's many blog posts out there that walk you through this process. The one that I find myself returning to time and time again is Dimitri Gielis's series Best and Cheapest Oracle APEX Hosting: Free Oracle Cloud. While some of the steps are a bit outdated, it's fairly easy to get started.

Note: Keep in mind that there is an entirely new section called Database Actions. This is the new name for SQL Developer Web, and contains so many more features than referenced in Dimitri's blog.

Vanity URL as a Feature

One thing just doesn't sit well with me - the URL used to access APEX. It's an ugly string that is just screaming to be entered incorrectly and create confusion. There's no way my aging brain can remember that, either.

One way to solve this would be to use the new Vanity URL feature that's part of OCI. Essentially, you can configure a load balancer with a domain name and certificate and have that point at your instance of APEX.

Unfortunately, to use this, you need to create your ADB with a private endpoint, which is not supported in the Free Tier. You'll also need to procure a certificate to run on port 443, which is also not typically free.

Vanity URL via NGINX + Let's Encrypt

Instead of using the Vanity URL Feature, we can resort back to Dimitri's blog series - particularly Step 7 in Dimitri's guide and create a compute instance that will proxy requests to APEX on ADB. Most of the steps in Step 7 are still accurate; however, when it comes to installing a certificate via Let's Encrypt, there are some issues. We'll address how to navigate those here.

Before starting, be sure to run through steps 1 through 6 on Dimitri's guide before trying anything here. If you're comfortable with OCI, you'll need to create an ADB and a compute node in the same compartment for this to work. Both are supported in the Free Tier.

Note: Be sure to check to ensure that the compute node that you create is, in fact, in the free tier. I have created a couple of compute nodes that seemed to not have the "Always Free" tag associated with them.

Now that you have the basic infrastructure in place and you've ssh'ed to the new compute instance, follow Dimitri's steps until you get to the section that discusses using Lets Encrypt which looks like this:

Screen Shot 2022-11-25 at 11.11.02 AM.png

Changes for Let's Encrypt

There are issues with the components he referenced and Oracle Linux 8. Thus, the steps simply won't work, and you cannot generate a certificate with Let's Encrypt. Fortunately, there's a more up-to-date set of steps on Oracle Base that do work. The complete steps can be found here: https://oracle-base.com/articles/linux/letsencrypt-free-certificates-on-oracle-linux,but

I'll summarize what's needed below.

First, we need to enable the EPEL repository with the following three commands, which should be run individually.

cd /tmp
wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
rpm -Uvh /tmp/epel-release-latest-8.noarch.rpm

Next, we need to install snap. Snap is a "App Store" for Linux; this is where we will get CertBot from. As before, each of the following commands should be run individually.

dnf install -y snapd
systemctl enable --now snapd.socket
systemctl start snapd
ln -s /var/lib/snapd/snap /snap
snap install core
snap refresh core

Now that snap is installed, we can install CertBot:

snap install --classic certbot
ln -s /snap/bin/certbot /usr/bin/certbot

At this point, you can return to Dimitri's blog and continue by running certbot --nginx and following the prompts. The rest of his blog will also walk you through how to configure NGINX to proxy your APEX instance from ADB via NGINX.

Resolving the 502 Bad Gateway Error

However, when you get to the last step, and try to view APEX form your vanity URL, you're likely going to see this:

Screen Shot 2022-11-25 at 12.42.34 PM.png

If we inspect the audit.log file, there's a number of errors thrown by NGINX:

[root@apex conf.d]# cat /var/log/audit/audit.log | grep nginx | grep denied
type=AVC msg=audit(1669401423.565:1522): avc:  denied  { name_connect } for  pid=158791 comm="nginx" dest=443 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:http_port_t:s0 tclass=tcp_socket permissive=0
type=AVC msg=audit(1669401423.567:1523): avc:  denied  { name_connect } for  pid=158791 comm="nginx" dest=443 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:http_port_t:s0 tclass=tcp_socket permissive=0
type=AVC msg=audit(1669401423.569:1524): avc:  denied  { name_connect } for  pid=158791 comm="nginx" dest=443 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:http_port_t:s0 tclass=tcp_socket permissive=0

Thus, need to open up one more thing using the audit2allow command. If we bounce the errors off this command, Linux will create exceptions and allow those calls to proceed rather than blocking them. We can do that by running these two commands:

cat /var/log/audit/audit.log | grep nginx | grep denied | audit2allow -M apex_proxy
semodule -i apex_proxy.pp

Finally, we should be able to see the APEX home page from our custom URL:

Screen Shot 2022-11-25 at 12.51.20 PM.png

Domain Redirect

There's likey one more thing that you should consider - pointing the top-level domain at either an APEX application or some more meaningful URL. Right now, I just have a placeholder index.html file that offers little value when viewed.

Again, Dimitri has you covered with this post: https://dgielis.blogspot.com/2019/12/free-oracle-cloud-17-configure-domain.html

It's a small fix, but does the job.

Conclusion

At this point, I now have my Always Free APEX instance on ADB mapped to a custom domain. Let’s Encrypt has generated & provided a free certificate, and will renew this every three months, so the traffic to & from the site is secured. I’m still able to make use of the shared ORDS instance from ADB, given me one less thing to maintain. My only cost thus far has been the domain name, making this one heck of a deal!