diff --git a/products/seafile/inputs.tf b/products/seafile/inputs.tf new file mode 100644 index 0000000..4b5b06a --- /dev/null +++ b/products/seafile/inputs.tf @@ -0,0 +1,63 @@ +variable "enable" { + type = bool + description = "Whether to enable the service." + default = true +} +variable "seafile_version" { + type = string + default = "11.0.13" + description = "The version of the docker image to use for the Seafile service." +} +# Pass-thru variables +variable "stack_name" { + type = string + default = "seafile" +} +variable "service_name" { + default = "seafile" + type = string + description = "The name of the service to create." +} +variable "networks" { + type = list(object({ + name = string + id = string + })) + default = [] + description = "A list of network names to attach the service to." +} +variable "ports" { + type = list(object({ + host = optional(number, null) + container = number + protocol = optional(string, "tcp") + publish_mode = optional(string, "ingress") + })) + default = [] + description = "A map of port mappings to expose on the host. The key is the host port, and the value is the container port." +} +variable "mysql_ports" { + type = list(object({ + host = optional(number, null) + container = number + protocol = optional(string, "tcp") + publish_mode = optional(string, "ingress") + })) + default = [] + description = "A map of port mappings to expose on the host. The key is the host port, and the value is the container port." +} +variable "mounts" { + type = map(string) + default = {} + description = "A map of host paths to container paths to mount. The key is the host path, and the value is the container path." +} +variable "placement_constraints" { + default = [] + type = list(string) + description = "Docker Swarm placement constraints" +} +variable "data_persist_path" { + default = null + description = "Path on host machine to persist data. Leaving this blank will provision an ephemeral volume." + type = string +} diff --git a/products/seafile/memcached.tf b/products/seafile/memcached.tf new file mode 100644 index 0000000..64ad5e1 --- /dev/null +++ b/products/seafile/memcached.tf @@ -0,0 +1,7 @@ +module "memcached" { + source = "../memcached" + enable = var.enable + stack_name = var.stack_name + networks = [module.network] + placement_constraints = var.placement_constraints +} \ No newline at end of file diff --git a/products/seafile/mysql.tf b/products/seafile/mysql.tf new file mode 100644 index 0000000..dc41df5 --- /dev/null +++ b/products/seafile/mysql.tf @@ -0,0 +1,11 @@ +module "mysql" { + source = "../mysql" + enable = var.enable + stack_name = var.stack_name + database = "seafile" + username = "seafile" + networks = [module.network] + data_persist_path = "${var.data_persist_path}/mysql" + placement_constraints = var.placement_constraints + ports = var.mysql_ports +} \ No newline at end of file diff --git a/products/seafile/network.tf b/products/seafile/network.tf new file mode 100644 index 0000000..9d7b29a --- /dev/null +++ b/products/seafile/network.tf @@ -0,0 +1,5 @@ +module "network" { + source = "../../docker/network" + stack_name = var.stack_name + network_name = "nextcloud" +} \ No newline at end of file diff --git a/products/seafile/seafile.tf b/products/seafile/seafile.tf new file mode 100644 index 0000000..51569ea --- /dev/null +++ b/products/seafile/seafile.tf @@ -0,0 +1,90 @@ +variable "domain" { + type = string + description = "The domain to use for the traefik configuration." +} +module "seafile" { + depends_on = [module.memcached, module.mysql, module.network] + source = "../../docker/service" + enable = var.enable + stack_name = var.stack_name + image = "h44z/seafile-ce:${var.seafile_version}" + placement_constraints = var.placement_constraints + service_name = var.service_name + networks = concat([module.network.network], var.networks, ) + mounts = { + "${var.data_persist_path}/seafile" = "/seafile" + "${var.data_persist_path}/logs" = "/opt/seafile/logs" + } + labels = { + "traefik.enable" = "true" + "traefik.docker.network" = "proxy-net" + # HTTP Router Seafile/Seahub + "traefik.http.routers.seafile.rule" = "(Host(`seafile.${var.domain}`))" + "traefik.http.routers.seafile.entrypoints" = "websecure" + "traefik.http.routers.seafile.tls" = "true" + "traefik.http.routers.seafile.tls.certresolver" = "letsencryptresolver" + "traefik.http.routers.seafile.service" = "seafile" + "traefik.http.routers.seafile.middlewares" = "sec-headers" + "traefik.http.services.seafile.loadbalancer.server.port" = "8000" + # HTTP Router Seafdav + "traefik.http.routers.seafile-dav.rule" = "Host(`seafile.${var.domain}`) && PathPrefix(`/seafdav`)" + "traefik.http.routers.seafile-dav.entrypoints" = "websecure" + "traefik.http.routers.seafile-dav.tls" = "true" + "traefik.http.routers.seafile-dav.tls.certresolver" = "letsencryptresolver" + "traefik.http.routers.seafile-dav.service" = "seafile-dav" + "traefik.http.services.seafile-dav.loadbalancer.server.port" = "8080" + # HTTP Router Seafhttp + "traefik.http.routers.seafile-http.rule" = "Host(`seafile.${var.domain}`) && PathPrefix(`/seafhttp`)" + "traefik.http.routers.seafile-http.entrypoints" = "websecure" + "traefik.http.routers.seafile-http.tls" = "true" + "traefik.http.routers.seafile-http.tls.certresolver" = "letsencryptresolver" + "traefik.http.routers.seafile-http.middlewares" = "seafile-strip" + "traefik.http.routers.seafile-http.service" = "seafile-http" + "traefik.http.services.seafile-http.loadbalancer.server.port" = "8082" + # Middlewares + "traefik.http.middlewares.seafile-strip.stripprefix.prefixes" = "/seafhttp" + "traefik.http.middlewares.sec-headers.headers.sslredirect" = "true" + "traefik.http.middlewares.sec-headers.headers.browserXssFilter" = "true" + "traefik.http.middlewares.sec-headers.headers.contentTypeNosniff" = "true" + "traefik.http.middlewares.sec-headers.headers.forceSTSHeader" = "true" + "traefik.http.middlewares.sec-headers.headers.stsIncludeSubdomains" = "true" + "traefik.http.middlewares.sec-headers.headers.stsPreload" = "true" + "traefik.http.middlewares.sec-headers.headers.referrerPolicy" = "same-origin" + } + environment_variables = { + # Base settings + TIME_ZONE = "Europe/Amsterdam" + + # Database settings, remove this section to use a sqlite database. + # You can either specify a root password (MYSQL_ROOT_PASSWORD), or use your exsting database tables. + # Also specifying MYSQL_USER_HOST only makes sense if MYSQL_ROOT_PASSWORD is given, otherwise no new MySQL user will be created. + # To use an external database, simply remove the MySQL service from the docker-compose.yml. + MYSQL_SERVER = module.mysql.service_name + MYSQL_USER = module.mysql.username + MYSQL_USER_PASSWORD = module.mysql.password + MYSQL_PORT = 3306 + + # General Seafile Settings + SEAFILE_VERSION = var.seafile_version + SEAFILE_NAME = "Seafile" + SEAFILE_ADDRESS = var.domain + SEAFILE_ADMIN = "admin@${var.domain}" + SEAFILE_ADMIN_PW = "changeme" + + # OnlyOffice Settings + ONLYOFFICE_JWT_SECRET = "Supers3cr3t" // @todo generate a key instead + + # Optional Seafile Settings + LDAP_IGNORE_CERT_CHECK = true + + # Traefik (Reverse Proxy) Settings + DOMAINNAME = var.domain + + # All other settings can be edited in the conf dir (/seafile/conf) once the container started up! + + # runmode, default = run + #MODE=maintenance + } + converge_enable = false // @todo: Fix healthcheck and change this. +} + diff --git a/products/seafile/terraform.tf b/products/seafile/terraform.tf new file mode 100644 index 0000000..d2a0d07 --- /dev/null +++ b/products/seafile/terraform.tf @@ -0,0 +1,13 @@ +terraform { + required_version = "~> 1.6" + required_providers { + docker = { + source = "kreuzwerker/docker" + version = "~> 3.0" + } + random = { + source = "hashicorp/random" + version = "~> 3.0" + } + } +}