From 399fd5717bef3bc372aeb4ec6ff9c9b1564e4191 Mon Sep 17 00:00:00 2001 From: Jeroen Vijgen Date: Tue, 7 Oct 2025 19:15:18 +0000 Subject: [PATCH] Add pelican to infra stack for friendos --- README.md | 29 ++++ .../pelican-service/main.tf | 127 ++++++++++++++++++ .../pelican-service/variables.tf | 46 +++++++ services/main.tf | 6 + services/outputs.tf | 1 + 5 files changed, 209 insertions(+) create mode 100644 modules/20-services-entertainment/pelican-service/main.tf create mode 100644 modules/20-services-entertainment/pelican-service/variables.tf diff --git a/README.md b/README.md index 685e4a8..3aee802 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,35 @@ homelab/ └── services/ # Application services (Docker containers) ``` +## Networking structure + +### Internal Network + +For the global network I use the following IP range and Subnet: + +- 10.100.0.0 - 10.100.0.254 +- 255.255.255.0 (/24) + +You will get 253 usable host addresses per network. This network is mainly for connecting pods to Caddy as the external ingress. + +### Intra pod network + +For connecting pods to each other (For example: Postgres -> Project <- Redis ) I use the following IP range and Subnet: + +- 172.16.0.0 - 172.16.0.254 +- 255.255.255.248 (/29) + +You get 6 usable host addresses per internal network, to find the usable addresses you can check [here](https://www.calculator.net/ip-subnet-calculator.html?cclass=b&csubnet=29&cip=172.16.0.0&ctype=ipv4&x=Calculate). + +#### Addresses in use: + +| Network name | IP address range | +| ------------------------ | ---------------- | +| Authentik | .0 - .7 | +| Pelican | .8 - .15 | +| Coder | .16 - .23 | +| Tandoor | .24 - .31 | + ## Configuration 1. **Clone the repository:** diff --git a/modules/20-services-entertainment/pelican-service/main.tf b/modules/20-services-entertainment/pelican-service/main.tf new file mode 100644 index 0000000..e4d00eb --- /dev/null +++ b/modules/20-services-entertainment/pelican-service/main.tf @@ -0,0 +1,127 @@ +terraform { + required_providers { + dotenv = { + source = "germanbrew/dotenv" + } + } +} + +locals { + container_name = "pelican" + wings_container_name = "pelican-wings" + pelican_image = "ghcr.io/pelican-dev/panel" + pelican_wings_image = "ghcr.io/pelican-dev/wings" + pelican_tag = var.image_tag + pelican_wings_tag = var.wings_image_tag + env_file = "${path.module}/.env" + pelican_internal_port = 80 + + caddyfile_content = <<-EOT + { + admin off + auto_https disable_certs + email none@none.invalid + } + + :80 { + root * /var/www/html/public + encode gzip + + php_fastcgi 127.0.0.1:9000 + file_server + } + EOT +} + +resource "local_file" "pelican_caddy_config_file" { + content = local.caddyfile_content + filename = "${var.volume_path}/${local.container_name}/Caddyfile" +} + +module "pelican_network" { + source = "../../01-networking/network-service" + name = "authentik-network" + subnet = "172.16.0.8/29" + driver = "bridge" + options = { + "isolate": false + } +} + +module "pelican-panel" { + source = "../../10-generic/docker-service" + container_name = local.container_name + image = local.pelican_image + tag = local.pelican_tag + networks = concat([pelican_network], var.networks) + restart_policy = "always" + volumes = [ + { + host_path = "${var.volume_path}/${local.container_name}/data" + container_path = "/pelican-data" + read_only = false + }, + { + host_path = "${var.volume_path}/${local.container_name}/logs" + container_path = "/var/www/html/storage/logs" + read_only = false + }, + { + host_path = "${var.volume_path}/${local.container_name}/Caddyfile" + container_path = "/etc/caddy/Caddyfile" + read_only = true + } + ] + env_vars = { + TZ = var.timezone + APP_TIMEZONE = var.timezone + APP_ENV = "production" + APP_URL = "${var.subdomain}.blackchaosnl.myaddr.dev" + ADMIN_EMAIL = "jjvijgen@gmail.com" + } +} + +module "pelican-wings" { + source = "../../10-generic/docker-service" + container_name = local.pelican_wings_image + image = local.pelican_wings_tag + tag = local.pelican_wings_tag + networks = concat([pelican_network], var.networks) + restart_policy = "always" + volumes = [ + { + host_path = "/run/user/1000/podman/podman.sock" + container_path = "/var/run/docker.sock" + read_only = false + }, + { + host_path = "/home/jjvij/.local/share/containers" + container_path = "/var/lib/docker/containers/" + read_only = false + } + ] + env_vars = { + TZ = var.timezone + APP_TIMEZONE = var.timezone + WINGS_UID = var.user_id + WINGS_GID = var.group_id + WINGS_USERNAME = "pelican" + } + userns_mode = "keep-id:uid=1000,gid=1000" + labels = { + "run.oci.keep_original_groups" = "1" + } + security_opts = [ + "label:type:container_runtype_t" + ] +} + +output "service_definition" { + description = "General service definition with optional ingress configuration" + value = { + name = local.container_name + primary_port = local.pelican_internal_port + endpoint = "http://${local.container_name}:${local.pelican_internal_port}" + subdomain = [var.subdomain] + } +} \ No newline at end of file diff --git a/modules/20-services-entertainment/pelican-service/variables.tf b/modules/20-services-entertainment/pelican-service/variables.tf new file mode 100644 index 0000000..4e094ed --- /dev/null +++ b/modules/20-services-entertainment/pelican-service/variables.tf @@ -0,0 +1,46 @@ +variable "image_tag" { + description = "The tag for the Pelican container image. Default: latest" + type = string + default = "latest" +} + +variable "wings_image_tag" { + description = "The tag for the Pelican Wings container image. Default: latest" + type = string + default = "latest" +} + +variable "volume_path" { + description = "Base directory for volumes" + type = string +} + +variable "networks" { + description = "List of networks to which the container should be attached" + type = list(string) + default = [] +} + +variable "user_id" { + description = "User ID for container permissions" + type = string + default = "1000" +} + +variable "group_id" { + description = "Group ID for container permissions" + type = string + default = "1000" +} + +variable "timezone" { + description = "Timezone for the container" + type = string + default = "Europe/Helsinki" +} + +variable "subdomain" { + description = "Subdomain on which the panel is hosted" + type = string + default = "gpanel" +} \ No newline at end of file diff --git a/services/main.tf b/services/main.tf index a64408d..3c2e6a0 100644 --- a/services/main.tf +++ b/services/main.tf @@ -31,6 +31,12 @@ module "calibre" { networks = [module.infrastructure_int.name] } +module "pelican" { + source = "${local.module_dir}/20-services-entertainment/pelican-service" + volume_path = "${local.root_volume}/pelican" + networks = [module.infrastructure_int.name] +} + module "authentik" { source = "${local.module_dir}/30-services-software/authentik-service" volume_path = "${local.root_volume}/authentik" diff --git a/services/outputs.tf b/services/outputs.tf index bd010ae..665ac7e 100644 --- a/services/outputs.tf +++ b/services/outputs.tf @@ -3,6 +3,7 @@ output "service_definitions" { value = [ module.jellyfin.service_definition, module.calibre.service_definition, + module.pelican.service_definition, module.authentik.service_definition, module.traccar.service_definition, module.tandoor.service_definition,