From 66672e3651089e62525cd4c6ca8aea298918925f Mon Sep 17 00:00:00 2001 From: Kafeel Hasan Date: Wed, 29 Oct 2025 14:33:31 +0530 Subject: [PATCH 1/4] Add Azure Blob Storage hosting guide and update local hosting docs - Add new documentation for hosting static content in Azure Blob Storage - Update existing static content guide to focus on local hosting - Add cross-references between local and blob storage hosting methods --- .../hosting-static-content-blob-storage.md | 119 ++++++++++++++++++ .../quickstart/hosting-static-content.md | 8 +- 2 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 content/nginxaas-azure/quickstart/hosting-static-content-blob-storage.md diff --git a/content/nginxaas-azure/quickstart/hosting-static-content-blob-storage.md b/content/nginxaas-azure/quickstart/hosting-static-content-blob-storage.md new file mode 100644 index 000000000..4269e619e --- /dev/null +++ b/content/nginxaas-azure/quickstart/hosting-static-content-blob-storage.md @@ -0,0 +1,119 @@ +--- +title: Hosting static content in Azure Blob Storage +weight: 210 +toc: true +nd-docs: DOCS-1344 +url: /nginxaas/azure/quickstart/hosting-static-content-blob-storage/ +type: +- how-to +--- + +F5 NGINXaaS for Azure (NGINXaaS) can serve static content stored in Azure Blob Storage, allowing you to host large static websites without the configuration payload size limitations of local hosting. This approach also keeps your storage account private by restricting access to your NGINXaaS deployment. + +## Prerequisites + +- An Azure Storage Account +- An NGINXaaS for Azure deployment +- Static content files to serve + +## Configure Azure Blob Storage + +### Step 1: Upload static files to the $web container + +Place your static files in the `$web` container in your storage account. This is the standard container used for static website hosting in Azure. + +### Step 2: Configure network access + +1. In your storage account, navigate to **Networking** under **Security + networking**. +2. Under **Public network access**, select **Enable public access from selected virtual networks and IP addresses**. +3. In the **Virtual networks** section, click **Add existing virtual network**. +4. Select the virtual network and subnet where your NGINXaaS deployment is located. +5. Click **Add** to allow your NGINXaaS deployment to connect to the storage account. + +{{< call-out "note" >}}This configuration ensures that your storage account is not accessible from the public Internet, only from your NGINXaaS deployment's subnet.{{< /call-out >}} + +### Step 3: Enable static website hosting + +1. In your storage account, navigate to **Static website** under **Data management**. +2. Enable **Static website**. +3. Set your **Index document name** (e.g., `index.html`). +4. Optionally, set an **Error document path** for 404 errors. +5. Click **Save**. + +Note the **Primary endpoint** URL that appears after enabling static website hosting. You'll need this for your NGINX configuration. + +## Configure NGINXaaS + +Create an NGINX configuration that proxies requests to your Azure Blob Storage static website endpoint: + +```nginx +user nginx; +worker_processes auto; +worker_rlimit_nofile 8192; +pid /run/nginx/nginx.pid; + +error_log /var/log/nginx/error.log error; + +http { + upstream storage_origin { + server your-storage-account.z20.web.core.windows.net:443; + keepalive 32; + } + + server { + listen 443 ssl; + ssl_certificate /etc/nginx/example.cert; + ssl_certificate_key /etc/nginx/example.key; + + location /static/ { + proxy_pass https://storage_origin/content/; + proxy_set_header Host your-storage-account.z20.web.core.windows.net; + proxy_http_version 1.1; + proxy_set_header Connection ""; + } + } +} +``` + +{{< call-out "important" >}}Replace `your-storage-account` with your actual storage account name in both the upstream server definition and the `proxy_set_header Host` directive. The region code (e.g., `z20`) may vary depending on your storage account's region.{{< /call-out >}} + +### Configuration breakdown + +- **upstream storage_origin**: Defines the Azure Blob Storage static website endpoint as the backend server +- **keepalive 32**: Maintains persistent connections to the storage endpoint for better performance +- **location /static/**: Maps the `/static/` path on your NGINXaaS deployment to the `/content/` path in your static website +- **proxy_pass**: Forwards requests to the Azure Blob Storage endpoint with the `/content/` path +- **proxy_set_header Host**: Sets the correct Host header for the storage account +- **proxy_http_version 1.1**: Uses HTTP/1.1 for better connection reuse +- **proxy_set_header Connection ""**: Clears the connection header for proper keepalive behavior + +## Upload the configuration + +Upload your NGINX configuration to your NGINXaaS deployment following the instructions in the [NGINX configuration]({{< ref "/nginxaas-azure/getting-started/nginx-configuration/nginx-configuration-portal.md" >}}) documentation. + +## Test the configuration + +1. Browse to `https:///static/` to access your static content. +2. For example, if you have an `index.html` file in your `$web` container, access it via `https:///static/index.html`. +3. Your content should be served from Azure Blob Storage through your NGINXaaS deployment. + +## Verify traffic routing + +You can verify that requests are properly routed through your NGINXaaS deployment by checking the Azure Storage logs: + +1. Enable logging for your storage account if not already enabled. +2. In the storage logs, you should see requests coming from the private IP address of your NGINXaaS deployment, not from public Internet addresses. + +## Benefits of this approach + +- **No payload size limits**: Unlike local hosting, you're not limited by the 3 MB configuration payload size +- **Scalable storage**: Azure Blob Storage can handle large amounts of static content +- **Private access**: Your storage account remains private and is only accessible through your NGINXaaS deployment +- **Cost-effective**: Azure Blob Storage offers cost-effective storage for static content +- **Global availability**: Leverage Azure's global infrastructure for content delivery + +## Limitations + +- Requires network connectivity between your NGINXaaS deployment and the storage account +- Additional latency compared to locally hosted content due to the proxy pass to Azure Blob Storage +- Storage account must be in a region that allows network connectivity to your NGINXaaS deployment diff --git a/content/nginxaas-azure/quickstart/hosting-static-content.md b/content/nginxaas-azure/quickstart/hosting-static-content.md index 13ad23211..13ffc7fce 100644 --- a/content/nginxaas-azure/quickstart/hosting-static-content.md +++ b/content/nginxaas-azure/quickstart/hosting-static-content.md @@ -1,5 +1,5 @@ --- -title: Hosting static content +title: Hosting static content locally weight: 200 toc: true nd-docs: DOCS-1344 @@ -8,7 +8,7 @@ type: - how-to --- -F5 NGINXaaS for Azure (NGINXaaS) supports hosting static content which allows users to serve static websites from their deployment. +F5 NGINXaaS for Azure (NGINXaaS) supports hosting static content locally on the deployment, which allows users to serve static websites directly from their deployment. ## Uploading static files as a tarball @@ -30,7 +30,7 @@ http { 2. Store your static files alongside the NGINX configuration. -The following shows the structure of a directory containing an NGINX configuration and an `index.html` file that we will be served from the deployment. +The following shows the structure of a directory containing an NGINX configuration and an `index.html` file that will be served from the deployment. ```shell test-static-files $ tree . @@ -65,3 +65,5 @@ You can also upload static files directly to the deployment. See [Adding NGINX C ## Limitations NGINX Configuration payload larger than 3 MB is not supported. + +For hosting larger static content or to avoid the payload size limitation, consider [hosting static content in Azure Blob Storage]({{< ref "/nginxaas-azure/quickstart/hosting-static-content-blob-storage.md" >}}). From 3d092a9b8e0eeed3fc68ce67d83be0b6c48e50cb Mon Sep 17 00:00:00 2001 From: Kafeel Hasan Date: Wed, 29 Oct 2025 14:34:05 +0530 Subject: [PATCH 2/4] Update hosting static content docs --- .../quickstart/hosting-static-content-blob-storage.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/content/nginxaas-azure/quickstart/hosting-static-content-blob-storage.md b/content/nginxaas-azure/quickstart/hosting-static-content-blob-storage.md index 4269e619e..b3f05d8a4 100644 --- a/content/nginxaas-azure/quickstart/hosting-static-content-blob-storage.md +++ b/content/nginxaas-azure/quickstart/hosting-static-content-blob-storage.md @@ -20,7 +20,7 @@ F5 NGINXaaS for Azure (NGINXaaS) can serve static content stored in Azure Blob S ### Step 1: Upload static files to the $web container -Place your static files in the `$web` container in your storage account. This is the standard container used for static website hosting in Azure. +Upload your static files to the `$web` container in your storage account. This is the standard container used for static website hosting in Azure. ### Step 2: Configure network access @@ -40,7 +40,7 @@ Place your static files in the `$web` container in your storage account. This is 4. Optionally, set an **Error document path** for 404 errors. 5. Click **Save**. -Note the **Primary endpoint** URL that appears after enabling static website hosting. You'll need this for your NGINX configuration. +Note the **Primary endpoint** URL that appears after enabling static website hosting. You'll use this URL in your NGINX configuration. ## Configure NGINXaaS @@ -99,10 +99,10 @@ Upload your NGINX configuration to your NGINXaaS deployment following the instru ## Verify traffic routing -You can verify that requests are properly routed through your NGINXaaS deployment by checking the Azure Storage logs: +You can verify that requests are properly routed through your NGINXaaS deployment by examining the Azure Storage logs: 1. Enable logging for your storage account if not already enabled. -2. In the storage logs, you should see requests coming from the private IP address of your NGINXaaS deployment, not from public Internet addresses. +2. In the storage logs, you should see requests originating from the private IP address of your NGINXaaS deployment, not from public Internet addresses. ## Benefits of this approach From d1fd2822a1fbf5795a85b75089a08eb33ab93ad4 Mon Sep 17 00:00:00 2001 From: Kafeel Hasan Date: Wed, 29 Oct 2025 14:56:51 +0530 Subject: [PATCH 3/4] Add security considerations for Azure Storage authorization --- .../quickstart/hosting-static-content-blob-storage.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/content/nginxaas-azure/quickstart/hosting-static-content-blob-storage.md b/content/nginxaas-azure/quickstart/hosting-static-content-blob-storage.md index b3f05d8a4..91c7254b4 100644 --- a/content/nginxaas-azure/quickstart/hosting-static-content-blob-storage.md +++ b/content/nginxaas-azure/quickstart/hosting-static-content-blob-storage.md @@ -112,6 +112,10 @@ You can verify that requests are properly routed through your NGINXaaS deploymen - **Cost-effective**: Azure Blob Storage offers cost-effective storage for static content - **Global availability**: Leverage Azure's global infrastructure for content delivery +## Security considerations + +In this example, we are using anonymous access to the blob storage, but if you want to increase security further, you can add authorization instead. This [Microsoft document](https://learn.microsoft.com/en-us/azure/storage/common/authorize-data-access?tabs=blobs#authorization-for-data-operations) shows the various ways you can authorize your requests to Azure Storage. + ## Limitations - Requires network connectivity between your NGINXaaS deployment and the storage account From 35e164ebd01113c6a5e3cf71562aea3e4e7b737a Mon Sep 17 00:00:00 2001 From: Kafeel Hasan Date: Wed, 29 Oct 2025 18:47:07 +0530 Subject: [PATCH 4/4] Use private endpoint solution and address PR Comments --- .../hosting-static-content-blob-storage.md | 142 ++++++++++++------ 1 file changed, 95 insertions(+), 47 deletions(-) diff --git a/content/nginxaas-azure/quickstart/hosting-static-content-blob-storage.md b/content/nginxaas-azure/quickstart/hosting-static-content-blob-storage.md index 91c7254b4..1174d57e2 100644 --- a/content/nginxaas-azure/quickstart/hosting-static-content-blob-storage.md +++ b/content/nginxaas-azure/quickstart/hosting-static-content-blob-storage.md @@ -2,49 +2,84 @@ title: Hosting static content in Azure Blob Storage weight: 210 toc: true -nd-docs: DOCS-1344 url: /nginxaas/azure/quickstart/hosting-static-content-blob-storage/ type: - how-to --- -F5 NGINXaaS for Azure (NGINXaaS) can serve static content stored in Azure Blob Storage, allowing you to host large static websites without the configuration payload size limitations of local hosting. This approach also keeps your storage account private by restricting access to your NGINXaaS deployment. +F5 NGINXaaS for Azure (NGINXaaS) can serve static content stored in Azure Blob Storage using private endpoints, ensuring maximum security by keeping your storage account completely inaccessible from the public Internet. This approach also eliminates the configuration payload size limitations of local hosting. -## Prerequisites +## Before you begin -- An Azure Storage Account -- An NGINXaaS for Azure deployment +- [An Azure Storage Account](https://learn.microsoft.com/en-us/azure/storage/common/storage-account-create) +- [An NGINXaaS for Azure deployment]({{< ref "/nginxaas-azure/getting-started/create-deployment" >}}) +- [A virtual network with available subnet space for private endpoints](https://learn.microsoft.com/en-us/azure/virtual-network/quick-create-portal) - Static content files to serve ## Configure Azure Blob Storage -### Step 1: Upload static files to the $web container +### Upload static files to a container -Upload your static files to the `$web` container in your storage account. This is the standard container used for static website hosting in Azure. +Upload your static files to a container in your storage account. In this example, we'll use a container named `content`. -### Step 2: Configure network access +### Disable public network access 1. In your storage account, navigate to **Networking** under **Security + networking**. -2. Under **Public network access**, select **Enable public access from selected virtual networks and IP addresses**. -3. In the **Virtual networks** section, click **Add existing virtual network**. -4. Select the virtual network and subnet where your NGINXaaS deployment is located. -5. Click **Add** to allow your NGINXaaS deployment to connect to the storage account. +1. Under **Public network access**, select **Disable**. +1. Click **Save**. -{{< call-out "note" >}}This configuration ensures that your storage account is not accessible from the public Internet, only from your NGINXaaS deployment's subnet.{{< /call-out >}} +### Disable anonymous blob access -### Step 3: Enable static website hosting +1. In your storage account, navigate to **Configuration** under **Settings**. +1. Find the **Allow Blob anonymous access** setting and set it to **Disabled**. +1. Click **Save**. -1. In your storage account, navigate to **Static website** under **Data management**. -2. Enable **Static website**. -3. Set your **Index document name** (e.g., `index.html`). -4. Optionally, set an **Error document path** for 404 errors. -5. Click **Save**. +### Set container access level to private -Note the **Primary endpoint** URL that appears after enabling static website hosting. You'll use this URL in your NGINX configuration. +1. Navigate to **Containers** under **Data management**. +1. Select your container (for example, `content`). +1. Click **Change access level**. +1. Set **Anonymous access level** to **Private (no anonymous access)**. +1. Click **OK**. + +### Create a new subnet for private endpoint NICs + +1. Navigate to your virtual network where NGINXaaS is deployed. +1. Go to **Subnets** under **Settings**. +1. Click **+ Subnet**. +1. Create a new subnet which will be used to assign IP address to your Private Endpoint NIC. +1. Make a note of the subnet name for the next step. + +### Create a private endpoint + +1. In your storage account, navigate to **Networking** under **Security + networking**. +1. Go to the **Private endpoint connections** tab. +1. Click **+ Private endpoint**. +1. Configure the private endpoint: + - **Name**: Provide a descriptive name for the private endpoint + - **Network Interface Name**: Provide a name for the network interface + - **Target sub-resource**: Select **blob** + - **Virtual network**: Select the same virtual network as your NGINXaaS deployment + - **Subnet**: Select the subnet created in the previous step + - **Private DNS integration**: Enable this option to automatically create DNS records + +### Generate a Shared Access Signature (SAS) token + +1. In your storage account, navigate to **Shared access signature** under **Security + networking**. +1. Configure the SAS token with minimal required permissions: + - **Allowed services**: Check **Blob** + - **Allowed resource types**: Check **Object** + - **Allowed permissions**: Check **Read** only + - **Start and expiry date/time**: Set appropriate validity period + - **Allowed protocols**: Select **HTTPS only** +1. Click **Generate SAS and connection string**. +1. Copy the **SAS token** (the part starting with `?sv=`). + +{{< call-out "important" >}}Store the SAS token securely and regenerate it regularly according to your security policies. Grant only the minimum permissions required for your use case.{{< /call-out >}} ## Configure NGINXaaS -Create an NGINX configuration that proxies requests to your Azure Blob Storage static website endpoint: +Create an NGINX configuration that uses the private endpoint and SAS token to access your Azure Blob Storage. The following NGINX config points to the `content` directory with `/static/` location and uses the SAS token from the previous step to authorize requests to blob storage. The resolver is set to 168.63.129.16 which is the Azure internal DNS IP. It doesn't change. It resolves the storage account endpoint to the private endpoint IP configured earlier. ```nginx user nginx; @@ -56,18 +91,19 @@ error_log /var/log/nginx/error.log error; http { upstream storage_origin { - server your-storage-account.z20.web.core.windows.net:443; + server your-storage-account.blob.core.windows.net:443; keepalive 32; } - + resolver 168.63.129.16 valid=10s; server { listen 443 ssl; + set $sas_token '?sv=YYYY-MM-DD&ss=b&srt=o&sp=r&se=YYYY-MM-DDTHH:MM:SSZ&st=YYYY-MM-DDTHH:MM:SSZ&spr=https&sig=YOUR_SAS_SIGNATURE_HERE'; ssl_certificate /etc/nginx/example.cert; ssl_certificate_key /etc/nginx/example.key; - location /static/ { - proxy_pass https://storage_origin/content/; - proxy_set_header Host your-storage-account.z20.web.core.windows.net; + rewrite ^/static/(.*)$ /content/$1 break; + proxy_pass https://storage_origin$uri$sas_token; + proxy_set_header Host your-storage-account.blob.core.windows.net; proxy_http_version 1.1; proxy_set_header Connection ""; } @@ -75,17 +111,23 @@ http { } ``` -{{< call-out "important" >}}Replace `your-storage-account` with your actual storage account name in both the upstream server definition and the `proxy_set_header Host` directive. The region code (e.g., `z20`) may vary depending on your storage account's region.{{< /call-out >}} +{{< call-out "important" >}}Replace the following placeholders: +- `your-storage-account` with your actual storage account name +- `YOUR_SAS_SIGNATURE_HERE` with your actual SAS token signature +- Update the SAS token parameters according to your generated token{{< /call-out >}} ### Configuration breakdown -- **upstream storage_origin**: Defines the Azure Blob Storage static website endpoint as the backend server -- **keepalive 32**: Maintains persistent connections to the storage endpoint for better performance -- **location /static/**: Maps the `/static/` path on your NGINXaaS deployment to the `/content/` path in your static website -- **proxy_pass**: Forwards requests to the Azure Blob Storage endpoint with the `/content/` path -- **proxy_set_header Host**: Sets the correct Host header for the storage account -- **proxy_http_version 1.1**: Uses HTTP/1.1 for better connection reuse -- **proxy_set_header Connection ""**: Clears the connection header for proper keepalive behavior +{{}} +| Directive | Description | +|------------|-------------| +| **upstream storage_origin** | Defines the Azure Blob Storage endpoint as the backend server | +| **resolver 168.63.129.16** | Uses Azure's internal DNS resolver to resolve the storage account to the private endpoint IP | +| **set $sas_token** | Stores the SAS token for authorization | +| **rewrite** | Maps the `/static/` path to the `/content/` container in blob storage | +| **proxy_pass** | Forwards requests to the storage account with the SAS token appended | +| **keepalive 32** | Maintains persistent connections for better performance | +{{
}} ## Upload the configuration @@ -93,31 +135,37 @@ Upload your NGINX configuration to your NGINXaaS deployment following the instru ## Test the configuration -1. Browse to `https:///static/` to access your static content. -2. For example, if you have an `index.html` file in your `$web` container, access it via `https:///static/index.html`. -3. Your content should be served from Azure Blob Storage through your NGINXaaS deployment. +1. Go to `https:///static/` to access your static content. +1. For example, if you have an `index.html` file in your `content` container, access it via `https:///static/index.html`. +1. Your content should be served from Azure Blob Storage through the private endpoint. -## Verify traffic routing +## Verify private endpoint connectivity -You can verify that requests are properly routed through your NGINXaaS deployment by examining the Azure Storage logs: +You can verify that traffic flows through the private endpoint by checking that: -1. Enable logging for your storage account if not already enabled. -2. In the storage logs, you should see requests originating from the private IP address of your NGINXaaS deployment, not from public Internet addresses. +1. The storage account is completely inaccessible from the public Internet +1. DNS resolution of your storage account resolves to the private IP address of the private endpoint +1. Network traffic flows through your virtual network without traversing the public Internet ## Benefits of this approach +- **Maximum security**: Storage account is completely private with no public Internet access - **No payload size limits**: Unlike local hosting, you're not limited by the 3 MB configuration payload size - **Scalable storage**: Azure Blob Storage can handle large amounts of static content -- **Private access**: Your storage account remains private and is only accessible through your NGINXaaS deployment +- **Network isolation**: All traffic flows through your private virtual network - **Cost-effective**: Azure Blob Storage offers cost-effective storage for static content -- **Global availability**: Leverage Azure's global infrastructure for content delivery +- **Controlled access**: SAS tokens provide fine-grained access control with expiration ## Security considerations -In this example, we are using anonymous access to the blob storage, but if you want to increase security further, you can add authorization instead. This [Microsoft document](https://learn.microsoft.com/en-us/azure/storage/common/authorize-data-access?tabs=blobs#authorization-for-data-operations) shows the various ways you can authorize your requests to Azure Storage. +- **SAS token management**: Regularly rotate SAS tokens and grant minimal required permissions +- **Network isolation**: Ensure private endpoints are properly configured in isolated subnets +- **Access monitoring**: Enable logging and monitoring for storage account access +- **Principle of least privilege**: Grant only the minimum permissions necessary for your use case ## Limitations -- Requires network connectivity between your NGINXaaS deployment and the storage account -- Additional latency compared to locally hosted content due to the proxy pass to Azure Blob Storage -- Storage account must be in a region that allows network connectivity to your NGINXaaS deployment +- Requires private endpoint configuration and additional subnet space +- SAS tokens need regular rotation and management +- Additional complexity compared to public access methods +- Private endpoint incurs additional Azure networking costs