On Self-hosting, OpenTofu, and Formerly OSS Licensed Software
Self hosting is a wonderful hobby, but for me, it's still just a hobby. If start to feel like I'm become a full time SRE or Infra Engineer then I lost my way somewhere. So a large part of self-hosting for me is balancing the automation to avoid drudgery while not going crazy trying to be enterprise ready. [^ Good ol #1205 and #1319. ]
However on the flip-side, sometimes when I want to spin up another service there are certain kinds of friction make me procrastinate. One of those is provisioning a new DB for a new service. The task is not particularly hard, but also not shiny and new. We love to chase the shiny and new.
So anyways, I wanted to spin up Endurain one weekend to try it out and that meant setting up Postgres for it. To make the experience shiny and new enough for me I decided to give Terraform OpenTofu a whirl.
I Got Really Distracted In the Process
I had not looked at Terraform for a couple years and didn't realized they changed their license in 2023. The re-license was very similar to ones I had heard of in the past and that got me in a mood to survey some history...
Soapbox time: there is a trend for successful open-source projects to spawn for profit companies behind their development. OSS is hard to monetize by design. Sometimes the for profit side of a project will start providing paid cloud options for funding.
The problem is that the large cloud providers Microsoft, Amazon, and Google can easily offer their version of the project as a paid service. Even when a project is AGPLv3 licensed. [^ I'd like to be clear to: I'm not throwing my support behind these companies.]
So then the temptation sets in: the for profit company could re-license the project to try and prevent the cloud providers from offering their version. They need to strike a balance though: they still want people to run the project in private cloud so they can sell consulting services and they also want to accept code contributions for the project. So the project becomes source-available under a custom license. You could view the code and offer a change, but the project is not Free and Open Source Software.
"There's a reason that old FLOSS hands react with instant derision whenever someone proposes making up a new software license. It's the same reason cryptographers are so hostile to the idea of people rolling their own ciphers: no matter how smart and well-intentioned you are, there's a high likelihood that you will screw up and irrevocably place innocent people at risk."
~ Cory Doctorow, Semantic drift versus ethical drift
A High Likelihood That You Screw Up
MongoDB is the first example of this that I recall. In 2018 they created their own Server Side Public License as a reaction to cloud providers hosting MongoDB as a service. I'll defer to the OSI's explaination for why the SSPL is Not an Open Source License. There were attempts to fork the project and continue under an open license but it looks like none of those projects survived. Ironically the re-license didn't stop Amazon since they created a protocol compatible service called DocumentDB.
Elastic was the next time I heard about this happening. The company started putting important features for security and operations under their non-open source paid component which was called the "X-pack". Then in 2021 Elasticsearch re-licensed using SSPL and their Elastic License 2.0. So AWS forked the project OpenSearch. One upside of this fork is that the paid only features like SSO and RBAC were implemented under the core project and available to everyone. Thankfully in 2024 Elastic switched back to an open source license again under AGPL.
In 2024 Redis re-licensed [^ With really spicy pr comments.] under SSPL and their Redis Source Available License. The Linux Foundation forked Valkey and Redis attempted to set a narrative with a blog post about "What is Valkey". Despite that a year later Redis attempted to reverse course and dual-license under AGPL again. as people and distributions were jumping ship to Valkey.
Somehow I missed that in 2023 Terraform had re-licensed from the Mozilla Public License v2.0 to the Business Source License. The Linux Foundation explains the license well:
It’s important to note that many or all of these BUSL relicensed projects have OSI-approved license projects in their dependency trees. Many of the relicensed projects rely on thousands of packages and modules under OSI-approved open source licenses. The companies relicensing often cite the motivation as the need to prevent tech companies from taking all their business. However, there doesn’t seem to be a problem building their BUSL products on Linux and thousands of open source projects they depend on in their codebase.
Then the community forked OpenTofu and applied to become part of the Linux Foundation. So after a good couple hours of reading about the past I remembered what I originally set out to do.
Back to the Self-hosting Stuff
Terraform OpenTofu is appealing because it helps me declaratively write out my DB config in case I need to migrate later. [^ Also I appreciate not having to run all the commands by hand against the DB.] Especially since Unraid keeps upping its pricing and TrueNAS finally landed RAIDZ expansion last year. At work my infra team handles Terraform so this is basically all net new for me.
The first part I looked into were Providers, which are "plugins... to interact with cloud providers, SaaS providers, and other APIs". You must declare which providers you are using. Then OpenTofu will handle installing them for you. I used the cyrilgdn/postgresql provider to handle configuring Postgres. Note that this does not handle installing Postgres itself.
Here is a minimal example. Define a .tf file:
terraform {
required_providers {
postgresql = {
source = "cyrilgdn/postgresql"
version = "1.25.0"
}
}
}
provider "postgresql" {
host = "postgres"
port = 5432
database = "postgres"
username = "postgres"
password = var.postgres_password
sslmode = "disable"
}
resource "postgresql_database" "endurain" {
name = "endurain"
owner = postgresql_role.endurain.name
}
resource "postgresql_role" "endurain" {
name = "endurain"
login = true
password = var.endurain_password
}
resource "postgresql_grant" "endurain_database" {
database = postgresql_database.endurain.name
role = postgresql_role.endurain.name
schema = "public"
object_type = "database"
privileges = ["ALL"]
}
The terraform
block is where we declare that we are using the Postgres provider. Then in the provider
block we provide connection information. Note the var.postgres_password
. I defined another file variables.tf
:
variable "postgres_password" {
description = "Password for PostgreSQL admin user"
type = string
sensitive = true
}
variable "endurain_password" {
description = "Password for endurain database user"
type = string
sensitive = true
}
This uses a Variable block to define an input variable for the database password.
The remaining blocks are Resource blocks. These are really the core of a Terraform OpenTofu configuration. They define something that we want to have configured someway. More on how resources are used in a bit. For now the example defines three resources:
- A
postgresql_database
named "endurain" which will create the database on the connection we configured. - A
postgresql_role
that handles creating a role on the database using the input variable. - A
postgresql_grant
which provides the role all privileges on the database.
With these resources defined you can run tofu plan
. This is where the something will happen to the resources. You can think of the process almost like a diff:
- The providers will be used to check the real world state.
- That state will be compared to the state described in your configuration
- When the two differ OpenTofu will figure out how to change the real world to match your configuration.
The result of the process is then displayed for you to see. Once you have the plan you can runtofo apply
to... well apply the configuration.
This is obviously a very simple example that we could extend in many ways, but is a good starting point. One is example is using Modules which are a mechanism to help reduce duplication. That way when you want to set up additional databases for more services you are not repeating the configuration. Another option is to leverage Credential Helps for managing secrets.
For now I'm keeping my configuration pretty simple. Everything is under version control, but not hooked up to to any CI yet since I have some other changes in the works.
Member discussion