Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
f526ac9
Add gitignore for terraform
eliaspr Mar 26, 2026
54d3d8e
README updates
eliaspr Mar 26, 2026
13d7bb9
Update zensical
eliaspr Mar 28, 2026
b1f2480
Revert previous commit
eliaspr Mar 28, 2026
0390aff
Separate docker compose docs
eliaspr Mar 28, 2026
340af19
Update navigation
eliaspr Mar 28, 2026
802beec
First rough draft for azure docs
eliaspr Mar 29, 2026
c2e702e
Remove token replace step
eliaspr Mar 29, 2026
26f5072
remove obsolete warning
eliaspr Mar 29, 2026
2916504
Set version in packagejson
eliaspr Apr 11, 2026
746bc7a
Add scipt for set version
eliaspr Apr 11, 2026
ff5731e
Escape . regex
eliaspr Apr 11, 2026
1292b18
Merge branch 'eliaspr/versioning' into eliaspr/azure-deploy
eliaspr Apr 11, 2026
adb70ca
Add tf files from other repo & add docs to bump-version script
eliaspr Apr 11, 2026
0fe8ae9
Update docs
eliaspr Apr 11, 2026
e29cab1
Merge branch 'eliaspr/versioning' into eliaspr/azure-deploy
eliaspr Apr 11, 2026
1679932
Hardcode version in variables.tf
eliaspr Apr 11, 2026
09511ec
Merge branch 'main' into eliaspr/azure-deploy
eliaspr Apr 12, 2026
59af050
Update zensical
eliaspr Apr 12, 2026
90a9b59
Merge branch 'main' into eliaspr/azure-deploy
eliaspr Apr 19, 2026
7e057e0
Zensical => 0.0.33
eliaspr Apr 19, 2026
62e637c
Documentation updates
eliaspr Apr 19, 2026
3c799a4
Documentation complete
eliaspr Apr 21, 2026
a4d1710
Readme for deploy folder
eliaspr Apr 21, 2026
f53ed09
Reset structure of nav
eliaspr Apr 21, 2026
3aa6c34
Start
eliaspr Apr 21, 2026
f05cecb
Update tf source
eliaspr Apr 21, 2026
3d6abfc
newline
eliaspr Apr 21, 2026
6771b86
Add tf outpout
eliaspr Apr 21, 2026
45adb02
Docu update
eliaspr Apr 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

**turnierplan.NET** is mostly written in C# using [.NET](https://dotnet.microsoft.com/). This includes the core logic, the backend API and database connection as well as all publicly visible web pages. In addition, it serves the *turnierplan.NET portal*, the client application for authenticated users, based on the [Angular](https://angular.dev/) framework.

Visit the **turnierplan.NET** documentation using the following link: [docs.turnierplan.net](https://docs.turnierplan.net). If you want to install **turnierplan.NET** on your server, please visit the [Installation guide](https://docs.turnierplan.net/installation).
Visit the **turnierplan.NET** documentation using the following link: [docs.turnierplan.net](https://docs.turnierplan.net). If you want to set up your own instance of **turnierplan.NET**, visit the [Installation guide](https://docs.turnierplan.net/installation) for detailed information on a local or cloud deployment.

> [!NOTE]
> The user interface and documentation are currently only available in German 🇩🇪
Expand Down
3 changes: 3 additions & 0 deletions deploy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# turnierplan.NET · Deployment Scripts

This directory contains scripts for various deployment methods. Refer to the [documentation](https://docs.turnierplan.net/installation/) for details on how to use the scripts.
15 changes: 15 additions & 0 deletions deploy/azure-terraform/app-insights.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
resource "azurerm_log_analytics_workspace" "default" {
name = "log-${var.name}"
location = var.location
resource_group_name = azurerm_resource_group.default.name
sku = "PerGB2018"
}

resource "azurerm_application_insights" "default" {
name = "appi-${var.name}"
location = var.location
resource_group_name = azurerm_resource_group.default.name
workspace_id = azurerm_log_analytics_workspace.default.id
application_type = "web"
retention_in_days = var.app_insights_retention_in_days
}
87 changes: 87 additions & 0 deletions deploy/azure-terraform/app-service.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
locals {
app_service_name = "app-${var.name}"
application_url = var.app_service_custom_domain == null ? "https://${local.app_service_name}.azurewebsites.net" : "https://${var.app_service_custom_domain}"
}

resource "azurerm_service_plan" "default" {
name = "asp-${var.name}"
location = var.location
resource_group_name = azurerm_resource_group.default.name

os_type = "Linux"
sku_name = var.app_service_plan_sku_name
}

resource "random_bytes" "identity_sining_key" {
length = 64
}

resource "azurerm_linux_web_app" "default" {
name = local.app_service_name
location = var.location
resource_group_name = azurerm_resource_group.default.name

service_plan_id = azurerm_service_plan.default.id
virtual_network_subnet_id = azurerm_subnet.app.id

https_only = true

identity {
type = "SystemAssigned"
}

site_config {
always_on = true

application_stack {
docker_registry_url = "https://${var.turnierplan_container_registry}"
docker_image_name = "${var.turnierplan_container_image}:${var.turnierplan_container_version}"
}
}

app_settings = merge(var.turnierplan_additional_app_settings, {
"Turnierplan__ApplicationUrl" = local.application_url
"Turnierplan__InitialUserName" = var.turnierplan_initial_user
"Turnierplan__InitialUserPassword" = var.turnierplan_initial_password

"ApplicationInsights__ConnectionString" = azurerm_application_insights.default.connection_string
"Database__ConnectionString" = "Host=${azurerm_postgresql_flexible_server.default.fqdn};Database=${azurerm_postgresql_flexible_server_database.default.name};Username=${azurerm_postgresql_flexible_server.default.administrator_login};Password=${azurerm_postgresql_flexible_server.default.administrator_password}"
"Identity__SigningKey" = random_bytes.identity_sining_key.base64

"ImageStorage__Type" = "Azure"
"ImageStorage__StorageAccountName" = azurerm_storage_account.default.name
"ImageStorage__ContainerName" = azurerm_storage_container.images.name
})
}

resource "azurerm_role_assignment" "application_blob_storage_contributor" {
role_definition_name = "Storage Blob Data Contributor"
principal_id = azurerm_linux_web_app.default.identity[0].principal_id
scope = azurerm_storage_account.default.id
}

resource "azurerm_app_service_custom_hostname_binding" "default" {
count = var.app_service_custom_domain == null ? 0 : 1

resource_group_name = azurerm_resource_group.default.name
app_service_name = azurerm_linux_web_app.default.name
hostname = var.app_service_custom_domain

lifecycle {
ignore_changes = [ssl_state, thumbprint]
}
}

resource "azurerm_app_service_managed_certificate" "default" {
count = var.app_service_custom_domain == null ? 0 : 1

custom_hostname_binding_id = azurerm_app_service_custom_hostname_binding.default[0].id
}

resource "azurerm_app_service_certificate_binding" "example" {
count = var.app_service_custom_domain == null ? 0 : 1

hostname_binding_id = azurerm_app_service_custom_hostname_binding.default[0].id
certificate_id = azurerm_app_service_managed_certificate.default[0].id
ssl_state = "SniEnabled"
}
39 changes: 39 additions & 0 deletions deploy/azure-terraform/database.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
resource "random_password" "psql_admin" {
length = 32
special = false
}

resource "azurerm_postgresql_flexible_server" "default" {
name = "psql-${var.name}"
location = var.location
resource_group_name = azurerm_resource_group.default.name

public_network_access_enabled = false
delegated_subnet_id = azurerm_subnet.database.id
private_dns_zone_id = azurerm_private_dns_zone.database.id

administrator_login = "tpsqladm"
administrator_password = random_password.psql_admin.result

authentication {
active_directory_auth_enabled = false
password_auth_enabled = true
}

version = "18"
sku_name = var.postgresql_sku_name
zone = var.postgresql_availability_zone
storage_mb = var.postgresql_storage_size_mb
storage_tier = var.postgresql_storage_tier
}

resource "azurerm_postgresql_flexible_server_database" "default" {
name = "turnierplan"
server_id = azurerm_postgresql_flexible_server.default.id
charset = var.postgresql_charset
collation = var.postgresql_collation

lifecycle {
prevent_destroy = true
}
}
50 changes: 50 additions & 0 deletions deploy/azure-terraform/networking.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
resource "azurerm_virtual_network" "default" {
name = "vnet-${var.name}"
location = var.location
resource_group_name = azurerm_resource_group.default.name
address_space = ["10.0.0.0/16"]
}

resource "azurerm_subnet" "app" {
name = "subnet-app-${var.name}"
resource_group_name = azurerm_resource_group.default.name
virtual_network_name = azurerm_virtual_network.default.name
address_prefixes = ["10.0.1.0/24"]

delegation {
name = "app"
service_delegation {
name = "Microsoft.Web/serverFarms"
actions = ["Microsoft.Network/virtualNetworks/subnets/action"]
}
}
}

resource "azurerm_subnet" "database" {
name = "subnet-database-${var.name}"
resource_group_name = azurerm_resource_group.default.name
virtual_network_name = azurerm_virtual_network.default.name
address_prefixes = ["10.0.2.0/24"]
service_endpoints = ["Microsoft.Storage"]

delegation {
name = "psql"
service_delegation {
name = "Microsoft.DBforPostgreSQL/flexibleServers"
actions = ["Microsoft.Network/virtualNetworks/subnets/join/action"]
}
}
}

resource "azurerm_private_dns_zone" "database" {
name = "dnszone-${var.name}.postgres.database.azure.com"
resource_group_name = azurerm_resource_group.default.name
}

resource "azurerm_private_dns_zone_virtual_network_link" "database" {
name = "database-vnet-link"
private_dns_zone_name = azurerm_private_dns_zone.database.name
virtual_network_id = azurerm_virtual_network.default.id
resource_group_name = azurerm_resource_group.default.name
depends_on = [azurerm_subnet.database]
}
4 changes: 4 additions & 0 deletions deploy/azure-terraform/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
output "turnierplan_application_url" {
description = "The application URL of the turnierplan.NET App Service without a trailing slash."
value = local.application_url
}
4 changes: 4 additions & 0 deletions deploy/azure-terraform/resource-group.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
resource "azurerm_resource_group" "default" {
name = "rg-${var.name}"
location = var.location
}
21 changes: 21 additions & 0 deletions deploy/azure-terraform/storage-account.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
resource "azurerm_storage_account" "default" {
name = "st${replace(var.name, "-", "")}"
location = var.location
resource_group_name = azurerm_resource_group.default.name

access_tier = "Hot"
account_tier = "Standard"
account_replication_type = var.storage_account_replication_type

public_network_access_enabled = true

lifecycle {
prevent_destroy = true
}
}

resource "azurerm_storage_container" "images" {
name = "${var.name}-images"
storage_account_id = azurerm_storage_account.default.id
container_access_type = "blob"
}
14 changes: 14 additions & 0 deletions deploy/azure-terraform/terraform.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
terraform {
required_version = ">= 1.0"

required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = ">= 3.0.0"
}
random = {
source = "hashicorp/random"
version = ">= 3.7.2"
}
}
}
111 changes: 111 additions & 0 deletions deploy/azure-terraform/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
variable "name" {
description = "Name suffix for all resources"
type = string
nullable = false
}

variable "location" {
description = "Location of the deployed resources"
type = string
nullable = false
}

variable "turnierplan_container_registry" {
description = "The container registry to pull the image from"
type = string
default = "ghcr.io"
nullable = false
}

variable "turnierplan_container_image" {
description = "The name of the container image to pull"
type = string
default = "turnierplan-net/turnierplan"
nullable = false
}

variable "turnierplan_container_version" {
description = "The name and tag of the container image to pull"
type = string
default = "2026.2.0"
nullable = false
}

variable "turnierplan_initial_user" {
description = "The user name for the initially created admin user"
type = string
nullable = false
}

variable "turnierplan_initial_password" {
description = "The password to initially set for the created admin user"
type = string
nullable = false
}

variable "turnierplan_additional_app_settings" {
description = "Additional configuration values for turnierplan.NET"
type = map(string)
nullable = false
}

variable "app_service_plan_sku_name" {
description = "The SKU name to use for the app service plan"
type = string
nullable = false
}

variable "app_service_custom_domain" {
description = "The domain name which should be bound to the app service (e.g. 'turnierplan.example.com') or null if no custom domain should be used."
type = string
nullable = true
default = null
}

variable "app_insights_retention_in_days" {
description = "The retention period for application insights logs"
type = number
nullable = false
}

variable "storage_account_replication_type" {
description = "The replication type to use for the storage account"
type = string
nullable = false
}

variable "postgresql_availability_zone" {
description = "The availability zone to deploy the PostgreSQL server in"
type = number
nullable = false
}

variable "postgresql_sku_name" {
description = "The name of the SKU to use for the PostgreSQL server"
type = string
nullable = false
}

variable "postgresql_storage_size_mb" {
description = "The storage size in MB for the PostgreSQL server"
type = number
nullable = false
}

variable "postgresql_storage_tier" {
description = "The storage tier for the PostgreSQL server"
type = string
nullable = false
}

variable "postgresql_charset" {
description = "The charset to use for the PostgreSQL database"
type = string
nullable = false
}

variable "postgresql_collation" {
description = "The collation to use for the PostgreSQL database"
type = string
nullable = false
}
Loading
Loading