Azure Installation (Helm)
This guide walks through deploying JuliaHub as a self-managed installation on Microsoft Azure using Helm. By the end, you will have a running JuliaHub platform on an AKS cluster with Azure Files storage and an external PostgreSQL database.
Prerequisites
Before starting, ensure you have the following:
Hostname
Decide on a hostname for your JuliaHub installation (e.g. juliahub.example.com). You will need to create DNS records after the installation is complete, so the hostname does not need to resolve yet, but it must be decided now as it is baked into the TLS certificate and Helm values.
TLS Certificate
Obtain a TLS certificate and private key in PEM format. The certificate must cover the following domains:
<hostname>— the main platform URL*.apps.<hostname>— JuliaHub-managed application routingdocs.<hostname>— generated Julia package documentation
A wildcard certificate for *.<hostname> plus the bare <hostname> is the simplest option. You can provide the certificate in two ways:
- Inline in Helm values: Save the full certificate chain as
fullchain.pemand the private key asprivkey.pem, then settlsFullchainPemandtlsPrivkeyPemin your values file. - As a Kubernetes TLS Secret: Create a
kubernetes.io/tlsSecret in the target namespace and setcertsSecretNamein your values file. When using this method,tlsFullchainPemandtlsPrivkeyPemdo not need to be set.
Replicated License
JuliaHub self-managed installations are distributed through Replicated. Contact your JuliaHub sales representative to obtain:
- A license ID (used as the Helm registry password)
- A license email (used as the Helm registry username)
Initial User Credentials
JuliaHub will provide initial admin credentials for your installation. These can be overridden by setting settings.initialUsers in your Helm values with a bcrypt hashed password.
CLI Tools
Install the following on your workstation:
| Tool | Minimum Version | Purpose |
|---|---|---|
Azure CLI (az) | 2.50 | Azure resource management |
| Terraform | 1.5 | Infrastructure provisioning (Option A only) |
| Helm | 3.0 | Kubernetes package manager |
| kubectl | 1.28 | Kubernetes CLI |
Log in to Azure:
az login
az account set --subscription <your-subscription-id>Infrastructure Setup
Choose one of the following paths depending on whether you are starting from scratch or have an existing AKS cluster.
Option A: Using JuliaHub Terraform Modules
JuliaHub provides public Terraform modules that provision all required Azure infrastructure: a VNet with private subnets, an AKS cluster, PostgreSQL Flexible Server, and Azure Files Premium storage.
1. Clone the modules:
git clone https://github.com/JuliaComputing/platform-public-terraform-modules.git
cd platform-public-terraform-modules/azure2. Create your configuration:
cp terraform.tfvars.example terraform.tfvarsEdit terraform.tfvars to set your values. At minimum, update:
azure_subscription_id = "<your-subscription-id>"
resource_group_name = "juliahub-rg"
location = "eastus" # your preferred region
# Storage account names must be globally unique, 3-24 lowercase alphanumeric
files_storage_account_name = "<globally-unique-name>"
blob_storage_account_name = "<globally-unique-name>"See the repository README for the full set of configurable variables.
3. Apply the infrastructure:
terraform init
terraform applyThis takes approximately 15–20 minutes. Once complete, Terraform outputs the connection details needed for later steps.
4. Connect to the AKS cluster:
az aks get-credentials \
--resource-group "$(terraform output -raw resource_group_name)" \
--name "$(terraform output -raw aks_cluster_name)"5. Create the Azure Files StorageClass and Secret:
The Helm chart requires a StorageClass and a Kubernetes Secret for Azure Files access:
terraform output -raw storage_files_kubernetes_storage_class_yaml | kubectl apply -f -
kubectl create secret generic azure-files-secret \
--from-literal=azurestorageaccountname="$(terraform output -raw storage_files_account_name)" \
--from-literal=azurestorageaccountkey="$(terraform output -raw storage_files_primary_access_key)"Continue to Install JuliaHub.
Option B: Existing AKS Cluster
If you already have an AKS cluster, ensure the following resources are available and accessible from the cluster's VNet:
| Resource | Requirements |
|---|---|
| AKS cluster | Kubernetes 1.28+, Azure CSI drivers enabled for Disk and Files |
| PostgreSQL | Azure Database for PostgreSQL Flexible Server (or compatible), accessible from the AKS VNet |
| Azure Files Premium | Storage account with NFS-enabled file shares: one for platform configuration, one for compute userdata |
1. Create the StorageClass:
Create a StorageClass for Azure Files Premium NFS. Adjust the skuName and resourceGroup to match your environment:
# azure-files-storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: azurefile-csi-premium-jh
provisioner: file.csi.azure.com
parameters:
skuName: Premium_LRS
protocol: nfs
resourceGroup: <your-resource-group>
storageAccount: <your-storage-account>
reclaimPolicy: Retain
volumeBindingMode: Immediate
mountOptions:
- nconnect=4
- noresvport
- actimeo=1kubectl apply -f azure-files-storageclass.yaml2. Create the Azure Files Secret:
kubectl create secret generic azure-files-secret \
--from-literal=azurestorageaccountname="<your-storage-account>" \
--from-literal=azurestorageaccountkey="<your-storage-account-key>"Install JuliaHub
Log in to the Replicated Registry
helm registry login registry.replicated.com \
--username <license-email> \
--password <license-id>View the Full Values Reference
To see all configurable Helm values and their defaults:
helm show values oci://registry.replicated.com/juliahub/production/juliahub-platformCreate Your Values File
Create a myvalues.yaml with the minimal configuration for Azure. If you used the Terraform modules (Option A), you can retrieve most values from Terraform outputs.
hostname: '<your-hostname>'
# Option 1: Inline TLS certificate
tlsFullchainPem: |
<contents of fullchain.pem, indented 2 spaces>
tlsPrivkeyPem: |
<contents of privkey.pem, indented 2 spaces>
# Option 2: Use an existing Kubernetes TLS Secret (instead of the above)
# certsSecretName: "<tls-secret-name>"
configDirectory:
type: "azure-files"
azureFiles:
volumeName: "juliahub-config-pv"
storageClassName: "azurefile-csi-premium-jh"
shareName: "<config-file-share-name>"
server: "<storage-account>.privatelink.file.core.windows.net"
resourceGroup: "<resource-group>"
storageAccount: "<storage-account>"
postgres:
type: external
external:
username: "<postgres-username>"
password: "<postgres-password>"
database: "<postgres-database>"
host: "<postgres-server-fqdn>"
compute:
userdataDirectory:
type: "azure-files"
azureFiles:
volumeName: "juliahub-userdata-pv"
storageClassName: "azurefile-csi-premium-jh"
shareName: "<userdata-file-share-name>"
server: "<storage-account>.privatelink.file.core.windows.net"
resourceGroup: "<resource-group>"
storageAccount: "<storage-account>"If you used Option A, you can populate the Azure-specific values from Terraform:
terraform output -raw storage_files_account_name # storageAccount
terraform output -raw storage_files_server # server
terraform output -raw resource_group_name # resourceGroup
terraform output -raw postgresql_server_fqdn # postgres host
terraform output -raw postgresql_administrator_login # postgres username
terraform output -raw postgresql_administrator_password # postgres password
terraform output -raw postgresql_database_name # postgres databaseRun the Installation
helm install juliahub-platform \
oci://registry.replicated.com/juliahub/production/juliahub-platform \
--namespace juliahub \
--create-namespace \
--timeout 30m \
--wait \
--wait-for-jobs \
--values myvalues.yamlThe initial installation may take up to 30 minutes as container images are pulled and services start up.
DNS Configuration
Once the installation is complete, get the external IP of the load balancer:
kubectl get svc -n juliahub websrvr-external -o jsonpath='{.status.loadBalancer.ingress[0].ip}'Create the following DNS A records pointing to this IP:
| Record | Type | Value |
|---|---|---|
<hostname> | A | <load-balancer-ip> |
*.apps.<hostname> | A | <load-balancer-ip> |
docs.<hostname> | A | <load-balancer-ip> |
DNS propagation may take time depending on your DNS provider. JuliaHub will not be accessible until these records resolve.
Verify the Installation
1. Check that all pods are running:
kubectl get pods -n juliahubAll pods should be in Running or Completed status.
2. Access JuliaHub:
Open https://<hostname> in your browser. You should see the JuliaHub login page.
Upgrading
To upgrade to a newer version of JuliaHub:
helm upgrade juliahub-platform \
oci://registry.replicated.com/juliahub/production/juliahub-platform \
--namespace juliahub \
--timeout 30m \
--wait \
--wait-for-jobs \
--values myvalues.yaml \
--version <new-version>Next Steps
- Configure authentication providers (OIDC, SAML, LDAP) in the JuliaHub admin settings
- Set up package synchronization to pull packages from the General registry
- Review the full Helm values reference for additional configuration options