Initial Commit

This commit is contained in:
Greyscale 2024-06-21 16:48:12 +02:00
parent 825f466a25
commit 2a613ec57b
No known key found for this signature in database
GPG key ID: 74BAFF55434DA4B2
13 changed files with 433 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/debug/*
/.idea

19
default.conf Normal file
View file

@ -0,0 +1,19 @@
resolver 127.0.0.11 ipv6=off valid=1s;
server {
listen 80;
listen [::]:80;
#listen 443 ssl;
#listen [::]:443 ssl;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

19
default_page.tf Normal file
View file

@ -0,0 +1,19 @@
locals {
default_page = "<h1>Hello, World!</h1>"
}
resource "docker_config" "default_page" {
name = "${var.service_name}.index.html-${substr(sha1(local.default_page), 0, 4)}"
data = base64encode(local.default_page)
}
resource "local_file" "default_page" {
content = base64decode(docker_config.default_page.data)
filename = "${path.root}/.debug/nginx/index.html"
}
resource "docker_config" "default_conf" {
name = "${var.service_name}.default.conf-${substr(sha1(file("${path.module}/default.conf")), 0, 4)}"
data = base64encode(file("${path.module}/default.conf"))
}
resource "local_file" "default_conf" {
content = base64decode(docker_config.default_conf.data)
filename = "${path.root}/.debug/nginx/default.conf"
}

22
inputs.tf Normal file
View file

@ -0,0 +1,22 @@
variable "service_name" {
type = string
default = "nginx"
}
variable "configs" {
type = list(object({
file = string
id = string
name = string
}))
}
variable "networks" {
type = list(object({
name = string
id = string
}))
}
variable "replicas" {
type = number
default = 2
description = "The number of instances to deploy"
}

View file

@ -0,0 +1,11 @@
# Auth file
resource "docker_config" "auth" {
count = var.basic_auth != null ? 1 : 0
name = join(".", [var.config_prefix, "auth", var.hostname, random_id.config_instance.id])
data = base64encode(local.auth)
}
resource "local_file" "auth" {
count = var.basic_auth != null ? 1 : 0
content = local.auth
filename = "${path.root}/.debug/nginx/${local.filenames.auth}"
}

View file

@ -0,0 +1,20 @@
resource "docker_config" "certificate" {
count = var.certificate != null ? 1 : 0
name = join(".", [var.config_prefix, "crt", var.hostname, random_id.config_instance.id])
data = base64encode("${var.certificate.certificate_pem}${var.certificate.issuer_pem}")
}
resource "local_file" "certificate" {
count = var.certificate != null ? 1 : 0
content = local.cert_public
filename = "${path.root}/.debug/nginx/${local.filenames.certificate}"
}
resource "docker_config" "certificate_key" {
count = var.certificate != null ? 1 : 0
name = join(".", [var.config_prefix, "key", var.hostname, random_id.config_instance.id])
data = base64encode(local.cert_private)
}
resource "local_file" "certificate_key" {
count = var.certificate != null ? 1 : 0
content = var.certificate.private_key_pem
filename = "${path.root}/.debug/nginx/${local.filenames.certificate_key}"
}

View file

@ -0,0 +1,70 @@
locals {
auth = var.basic_auth != null ? "${var.basic_auth.username}:${var.basic_auth.password}" : null
config = templatefile("${path.module}/nginx_template.conf", {
hostname = var.hostname
service_name = var.service_name
http_port = var.http_port
https_port = var.https_port
upstream_host = var.upstream_host
enable_ssl = var.certificate != null
certificate = var.certificate
basic_auth = var.basic_auth
auth_file = var.basic_auth != null ? "${var.hostname}-auth.conf" : ""
allow_non_ssl = var.allow_non_ssl
redirect_non_ssl = var.redirect_non_ssl
timeout_seconds = var.timeout_seconds
host_override = var.host_override
extra_upstreams = var.extra_upstreams
extra_locations = var.extra_locations
})
cert_public = "${var.certificate.issuer_pem}${var.certificate.certificate_pem}"
cert_private = var.certificate.private_key_pem
filenames = {
nginx = "${var.hostname}.conf"
auth = "${var.hostname}.auth"
certificate_key = "${var.hostname}.key"
certificate = "${var.hostname}.crt"
}
files = [for f in [
{
file = local.filenames.nginx
name = docker_config.nginx_site_available.name
id = docker_config.nginx_site_available.id
},
var.basic_auth != null ? {
file = local.filenames.auth
name = docker_config.auth[0].name
id = docker_config.auth[0].id
} : null,
var.certificate != null ? {
file = local.filenames.certificate
name = docker_config.certificate[0].name
id = docker_config.certificate[0].id
} : null,
var.certificate != null ? {
file = local.filenames.certificate_key
name = docker_config.certificate_key[0].name
id = docker_config.certificate_key[0].id
} : null
] : f if f != null]
}
# Nginx config
resource "random_id" "config_instance" {
byte_length = 4
keepers = {
config : local.config,
auth : local.auth,
cert_public : local.cert_public,
cert_private : local.cert_private,
}
}
resource "docker_config" "nginx_site_available" {
name = join(".", [var.config_prefix, "conf", var.hostname, random_id.config_instance.id])
data = base64encode(local.config)
}
resource "local_file" "nginx_site_available" {
filename = "${path.root}/.debug/nginx/${local.filenames.nginx}"
content = local.config
}

View file

@ -0,0 +1,67 @@
variable "hostname" {
type = string
description = "The hostname of the server"
}
variable "service_name" {
type = string
description = "The name of the service"
}
variable "upstream_host" {
type = string
description = "The host uri of the upstream server"
}
variable "certificate" {
type = object({
private_key_pem = string
certificate_pem = string
issuer_pem = string
})
default = null
}
variable "basic_auth" {
type = object({
username = string
password = string
})
default = null
}
variable "allow_non_ssl" {
type = bool
default = false
}
variable "redirect_non_ssl" {
type = bool
default = true
}
variable "timeout_seconds" {
type = number
default = 10
}
variable "http_port" {
type = number
default = 80
}
variable "https_port" {
type = number
default = 443
}
variable "host_override" {
type = string
default = null
}
variable "config_prefix" {
type = string
default = "nginx"
}
variable "extra_upstreams" {
type = list(object({
name = string
servers = list(string)
}))
default = []
}
variable "extra_locations" {
type = string
default = ""
}

View file

@ -0,0 +1,83 @@
upstream ${service_name} {
least_conn;
server ${upstream_host};
}
%{for upstream in extra_upstreams~}
upstream ${upstream.name} {
least_conn;
%{for server in upstream.servers~}
server ${server};
%{endfor~}
}
%{endfor~}
%{if !allow_non_ssl~}
server {
# Redirect non-ssl to ssl
listen ${http_port};
listen [::]:${http_port};
server_name ${hostname};
return 301 https://$host$request_uri;
}
%{endif~}
server {
%{if allow_non_ssl~}
# Non-SSL Traffic is allowed
listen ${http_port~}
listen [::]:${http_port};
%{endif~}
# SSL Traffic is allowed
listen ${https_port} ssl;
listen [::]:${https_port} ssl;
server_name ${hostname};
access_log /var/log/nginx/${hostname}.access.log;
error_log /var/log/nginx/${hostname}.error.log;
%{if enable_ssl~}
ssl_certificate /etc/nginx/conf.d/${hostname}.crt;
ssl_certificate_key /etc/nginx/conf.d/${hostname}.key;
# ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# ssl_ciphers HIGH:!aNULL:!MD5;
%{endif~}
client_max_body_size 0;
location / {
%{if host_override != null~}
proxy_set_header Host ${host_override};
%{else~}
proxy_set_header Host $host;
%{endif~}
# Server to send the request on to
proxy_pass http://${service_name};
# Standard headers setting origin data
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
%{if basic_auth != null~}
# Http Basic Auth
auth_basic "closed site";
auth_basic_user_file sites-enabled/${auth_file};
%{endif~}
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_cache_bypass $http_upgrade;
proxy_buffering off;
proxy_set_header Origin "";
# Proxy timeouts
proxy_read_timeout ${timeout_seconds};
proxy_connect_timeout ${timeout_seconds};
proxy_send_timeout ${timeout_seconds};
}
${extra_locations}
}

View file

@ -0,0 +1,6 @@
output "files" {
value = local.files
}
output "hostname" {
value = var.hostname
}

View file

@ -0,0 +1,22 @@
terraform {
required_providers {
docker = {
source = "kreuzwerker/docker"
version = "~>3.0"
}
random = {
source = "hashicorp/random"
version = "~>3.3"
}
local = {
source = "hashicorp/local"
version = "~>2.1"
}
scratch = {
source = "BrendanThompson/scratch"
version = "0.4.0"
}
}
}

78
nginx.tf Normal file
View file

@ -0,0 +1,78 @@
data "docker_registry_image" "nginx" {
name = "nginx:latest"
}
resource "random_id" "iteration" {
keepers = {
configs = jsonencode(var.configs)
}
byte_length = 4
}
resource "docker_service" "nginx" {
name = var.service_name
mode {
replicated {
replicas = var.replicas
}
}
task_spec {
container_spec {
image = "${data.docker_registry_image.nginx.name}@${data.docker_registry_image.nginx.sha256_digest}"
configs {
config_id = docker_config.default_page.id
config_name = docker_config.default_page.name
file_name = "/usr/share/nginx/html/index.html"
}
configs {
config_id = docker_config.default_conf.id
config_name = docker_config.default_conf.name
file_name = "/etc/nginx/conf.d/default.conf"
}
dynamic "configs" {
for_each = var.configs
content {
config_id = configs.value.id
config_name = configs.value.name
file_name = "/etc/nginx/conf.d/${configs.value.file}"
}
}
# Healthcheck that checks that the nginx process is running
#healthcheck {
# test = ["CMD", "pgrep", "nginx"]
# interval = "10s"
# timeout = "5s"
# retries = 3
# start_period = "10s"
#}
healthcheck {
test = ["CMD", "true"]
}
labels {
label = "com.nginx.iteration-id"
value = random_id.iteration.hex
}
}
dynamic "networks_advanced" {
for_each = var.networks
content {
name = networks_advanced.value.id
}
}
}
endpoint_spec {
ports {
target_port = 80
publish_mode = "ingress"
published_port = 80
}
ports {
target_port = 443
publish_mode = "ingress"
published_port = 443
}
}
update_config {
parallelism = ceil(var.replicas / 3)
delay = "10s"
order = "start-first"
}
}

14
terraform.tf Normal file
View file

@ -0,0 +1,14 @@
terraform {
required_providers {
docker = {
source = "kreuzwerker/docker"
version = "~>3.0"
}
scratch = {
source = "BrendanThompson/scratch"
version = "0.4.0"
}
}
}