Azure
Self-hosting on Azure
To self-host Membrane on Azure, you need to set up Azure Blob Storage.
Everything else is the same as in the main guide.
Setting up Azure Blob Storage
This guide uses terraform to manage the infrastructure.
- Create a storage account and storage containers:
resource "azurerm_storage_account" "main" {
name = "${var.environment}integrationapp"
resource_group_name = var.resource_group_name
location = var.resource_group_location
account_tier = "Standard"
account_replication_type = "LRS"
min_tls_version = "TLS1_2"
cross_tenant_replication_enabled = true
blob_properties {
cors_rule {
allowed_headers = ["*"]
allowed_methods = ["GET"]
allowed_origins = ["*"]
exposed_headers = ["*"]
max_age_in_seconds = 3000
}
}
tags = local.common_tags
}
# Container for temporary files
resource "azurerm_storage_container" "tmp" {
name = "integration-app-${var.environment}-temp"
storage_account_id = azurerm_storage_account.main.id
container_access_type = "private"
}
# Container for connectors
resource "azurerm_storage_container" "connectors" {
name = "integration-app-${var.environment}-connectors"
storage_account_id = azurerm_storage_account.main.id
container_access_type = "private"
}
# Note: For static website hosting, Azure automatically creates a $web container
# We'll use that container for static files instead of creating a separate one
# Static website configuration
resource "azurerm_storage_account_static_website" "main" {
storage_account_id = azurerm_storage_account.main.id
index_document = "index.html"
error_404_document = "404.html"
}
# Lifecycle management for tmp container
resource "azurerm_storage_management_policy" "tmp" {
storage_account_id = azurerm_storage_account.main.id
rule {
name = "cleanup"
enabled = true
filters {
blob_types = ["blockBlob"]
prefix_match = ["tmp/"]
}
actions {
base_blob {
delete_after_days_since_modification_greater_than = 7
}
}
}
}
- Configure CDN FrontDoor for serving static files (Optional)
resource "azurerm_cdn_frontdoor_profile" "static" {
name = "${var.environment}-afd-static"
resource_group_name = var.resource_group_name
sku_name = "Standard_AzureFrontDoor"
tags = {
Service = "core-azure"
}
}
resource "azurerm_cdn_frontdoor_endpoint" "static" {
name = "${var.environment}-afd-static-endpoint"
cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.static.id
}
resource "azurerm_cdn_frontdoor_origin_group" "static" {
name = "${var.environment}-afd-static-origin-group"
cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.static.id
load_balancing {
sample_size = 4
successful_samples_required = 3
}
}
resource "azurerm_cdn_frontdoor_origin" "static" {
name = "${var.environment}-afd-static-origin"
cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.static.id
enabled = true
host_name = "${azurerm_storage_account.main.name}.z13.web.core.windows.net"
http_port = 80
https_port = 443
origin_host_header = "${azurerm_storage_account.main.name}.z13.web.core.windows.net"
priority = 1
weight = 1000
certificate_name_check_enabled = true
}
resource "azurerm_cdn_frontdoor_route" "static" {
name = "${var.environment}-afd-static-route"
cdn_frontdoor_endpoint_id = azurerm_cdn_frontdoor_endpoint.static.id
cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.static.id
cdn_frontdoor_origin_ids = [azurerm_cdn_frontdoor_origin.static.id]
enabled = true
forwarding_protocol = "HttpsOnly"
https_redirect_enabled = true
patterns_to_match = ["/*"]
supported_protocols = ["Http", "Https"]
link_to_default_domain = true
cdn_frontdoor_custom_domain_ids = [azurerm_cdn_frontdoor_custom_domain.static.id]
cdn_frontdoor_rule_set_ids = [azurerm_cdn_frontdoor_rule_set.static.id]
}
resource "azurerm_cdn_frontdoor_custom_domain" "static" {
name = "staticazureintmembrane"
cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.static.id
host_name = "static.${var.dns_zone_name}"
tls {
certificate_type = "ManagedCertificate"
}
}
resource "azurerm_cdn_frontdoor_custom_domain_association" "static" {
cdn_frontdoor_custom_domain_id = azurerm_cdn_frontdoor_custom_domain.static.id
cdn_frontdoor_route_ids = [azurerm_cdn_frontdoor_route.static.id]
}
resource "azurerm_cdn_frontdoor_rule_set" "static" {
name = "${var.environment}staticrules"
cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.static.id
}
resource "azurerm_cdn_frontdoor_rule" "compression" {
name = "enablecompression"
cdn_frontdoor_rule_set_id = azurerm_cdn_frontdoor_rule_set.static.id
order = 1
behavior_on_match = "Continue"
conditions {
request_method_condition {
match_values = ["GET"]
operator = "Equal"
negate_condition = false
}
}
actions {
route_configuration_override_action {
compression_enabled = true
cache_behavior = "OverrideIfOriginMissing"
cache_duration = "1.00:00:00" # 1 day
query_string_caching_behavior = "IgnoreQueryString"
}
}
}
resource "azurerm_cdn_frontdoor_rule" "cache_static_assets" {
name = "cachestaticassets"
cdn_frontdoor_rule_set_id = azurerm_cdn_frontdoor_rule_set.static.id
order = 2
behavior_on_match = "Continue"
conditions {
request_uri_condition {
match_values = ["*.js", "*.css", "*.png", "*.jpg", "*.jpeg", "*.gif", "*.svg", "*.ico", "*.woff", "*.woff2"]
operator = "EndsWith"
negate_condition = false
}
}
actions {
route_configuration_override_action {
cache_behavior = "OverrideAlways"
cache_duration = "7.00:00:00" # 7 days for static assets
query_string_caching_behavior = "IgnoreQueryString"
}
}
}
- Configure custom domain DNS managed zone for BASE_STATIC_URI (Optional)
resource "azurerm_dns_txt_record" "afd_static_validation" {
name = "_dnsauth.static"
zone_name = var.dns_zone_name
resource_group_name = var.resource_group_name
ttl = 3600
record {
value = azurerm_cdn_frontdoor_custom_domain.static.validation_token
}
}
resource "azurerm_dns_cname_record" "static" {
name = "static"
zone_name = var.dns_zone_name
resource_group_name = var.resource_group_name
ttl = 3600
record = azurerm_cdn_frontdoor_endpoint.static.host_name
}
Updated 3 days ago