Save Money by Connecting Your Local Database to the Public Cloud

Burton Rheutan
6 min readFeb 27, 2020

--

Cloud computing allows you to use compute resources at a dollar-per-hour cost basis. This model works really well for a lot of applications. You’re able to scale down, or remove resources when they aren’t being used in order to save money. One place where this isn’t exactly cost-effective are databases. Running a database in the cloud can quickly become expensive and cost-prohibitive for small companies, freelancers, or hobbyists.

Here are the estimated costs for one month of a managed PostgreSQL database (~30GB storage) on some of the popular cloud platforms:

Amazon RDS: ~$731.79/mo

Azure SQL Database: ~$736.38/mo

Google Cloud SQL: ~$32.80/mo (using the db-pg-f1-micro default size)

DigitalOcean: ~$60/mo (using 4GB memory 2vCPU and 38GB storage)

It’s obvious there is a large price gap here. This is because AWS and Azure default to a much larger VM size (memory and CPU)

These prices do not include the data ingress and egress, which can quickly exaggerate the costs with no easy way to estimate or plan for.

What if you could just run a database within your own local network, but still be able to access it from your cloud-deployed applications?

This would mean that you wouldn’t need to pay the excessive costs of running a managed database in the cloud, but still be able to store and access your data as if it were.

Of course, you could just open your local network to the internet, but that would open you up to potential troubles if the wrong person gained access, and in turn, access to your entire internal network.

Instead, we should use a secure tunnel to give access to only that local database instance without opening the entire network. Enter Inlets-Pro, a cloud-native Layer 4 TCP tunnel.

Inlets-Pro: A cloud-native L4 TCP Tunnel

Inlets-Pro is the licensed version of Inlets that tunnels traffic at the Transport layer of the OSI model. This means that we’ll be able to tunnel the database TCP connections securely as Inlets-Pro automatically configures TLS for all traffic through the tunnel.

Setting up and configuring a PostgreSQL database is outside the scope, or purpose of this post. Try out the official Docker image for PostgreSQL for running the database in a container.

Inlets-Pro provides TLS for the connection through the tunnel, but you will still need to setup TLS for the connection to the database (via the exit node). For PostgreSQL, you can follow the official documentation to generate a self-signed certificate.

Get an Inlets-Pro License

Inlets-Pro is a licensed product available for purchase on the OpenFaaS store. There is also a 14-day free trial available to try it out.

Once you purchase, or sign up for the trial, you will receive a license key over email within 1–2 working days.

Setting up the Tunnel — Part 1: Get an exit-node

In order to have a public IP address, and in turn, allow access to our local database, we first need a publicly available host. This the smallest instance available (often in a free pricing tier) as it is only being used to route traffic from the internet through the tunnel.

This full step is also available as an automatic process via the inletsctl tool:

inletsctl create --access-token-file ./do-access-token --region="nyc1"

First, select the instance type, name it, then modify the firewall rules to allow the two inlets ports ingress and egress. The ports can be whatever you choose however, the defaults are:

  • 8123 inletspro “control” port (this is for inlets to create and manage the tunnel connection)
  • 5432 inletspro “data” port (this is the default port for PostgreSQL)

You will also need to allow ports 80 and 443 for the automatic TLS that comes included with Inlets-Pro.

Finally, run the Inlets-Pro server by either executing the command with a terminal multiplexer like tmux, or setting up a systemd service.

You will need your exit node’s public IP address:

export IP=$(curl -sfSL https://ifconfig.co)

We’ll need this again to setup the client side of the tunnel, so be sure to copy this somewhere for later

You will also need an access token in order to link this server with the client we will be setting up in the next step:

export TOKEN=$(head -c 16 /dev/urandom | shasum | cut -d" " -f1)

Be sure to save this somewhere safe, as we’ll need this again when we setup the client side of the tunnel.

You’re also going to need the IP address of the local network machine that is running the database. This is in relation to the machine that will be running the client side of the tunnel. If you decide to run inlets-pro on the same machine as the database, you could enter the local IP 127.0.0.1 otherwise, it would be the local IP of the database such as 192.168.0.2 as an example.

export LOCAL_IP=<the ip address of your database machine>

Now, we can start the inlets-pro server:

./inlets-pro server --common-name="${IP}" \
--remote-tcp="${LOCAL_IP}" \
--token="${TOKEN}"

Now, to setup the client on your local network.

Setting up the Tunnel — Part 2: Configure the client

In this step, we’re going to setup the listening side of the tunnel inside our private local network. This could be your office network, home lab, or a different private cloud network. To begin, login or ssh into the machine you’re going to install the client on. It could be the same machine that is running the database, or another machine that has access to the database within the network.

If you used inletsctl to setup the exit node, you can also use it to setup the client as a systemd process:

inletsctl client --generate=systemd

First, let’s export the variables from the server so we can use them again on the client side to complete the tunnel:

export EXIT_IP=<ip address of the server in the previous step>
export TOKEN=<token from the previous step>

Now, grab the license from your email and save it to a file to access by the inlets-pro binary (in this case, the file name is inlets.jwt)

export LICENSE=$(cat inlets.jwt)

Lastly, set the TCP port(s) to receive the data through the tunnel. This should be the port that the database is listening on. By default, PostgreSQL uses 5432

export TCP_PORTS="5432"

Now, we can start the inlets-pro client:

./inlets-pro client --connect "wss://${EXIT_IP}:8123/connect" \
--token "${TOKEN}" \
--license "${LICENSE}" \
--tcp-ports "${TCP_PORTS}"

You should see inlets-pro making the connection to the public exit node

2020/02/26 04:50:59 Welcome to inlets-pro!
2020/02/26 04:50:59 Starting client - version 0.5.6
2020/02/26 04:50:59 Licensed to: rheutan7@gmail.com, expires: 14 day(s)
2020/02/26 04:50:59 TCP Ports: [5432]
inlets-pro client. Copyright Alex Ellis 2019
INFO[0000] Connecting to proxy url="wss://<your_exit_node_ip>:8123/connect"

Also, if you’re still logged in to the exit node, you can see the traffic being routed into the tunnel on the public side:

020/02/26 04:50:59 Ports updated to: [5432]
INFO[0215] Handling backend connection request [inlets-client]
2020/02/26 04:50:59 TCP listen :5432

Now that the tunnel is connected, we can verify that we are now able to connect to our privately hosted database through a publicly accessible address

Adding the PostgreSQL with the public IP
Connected in pgAdmin to the public IP address

Conclusion

We now have a self-hosted database that is also available to our applications running in the cloud. You will still be paying for data ingress and egress through the exit node, but you won’t be paying for the managed database instance, or the storage in the cloud.

This can be valuable for small businesses and hobbyists who don’t need a lot of storage, and don’t want to be paying out constantly for a lightly used database.

Inlets-Pro allowed us to use the cloud to host our entry point and create a secure tunnel into our private network so that we can safely operate an otherwise expensive process on our own hardware. At least until the profits come in and the cost of a managed solution is more reasonable!

Start your 14-day free trial today on the OpenFaaS store

Sign up for the OpenFaaS Slack workspace and be sure to join the #inlets channel

--

--