Hosting Blazor WebAssembly Applications on AWS CloudFront

Somebody who likes to code
Search for a command to run...

Somebody who likes to code
No comments yet. Be the first to comment.
Google processes tens of thousands of code changes every day across a codebase of hundreds of millions of lines. The secret isn't magic tooling — it's a documented, principled approach to code review

Amazon Simple Notification Service (SNS) looks straightforward on the surface — publish a message, deliver it to subscribers — but the gap between a topic that "works in dev" and one that is productio

Amazon Simple Queue Service (SQS) is deceptively simple to get started with, but surprisingly easy to misconfigure in ways that cause silent message loss, runaway costs, duplicate processing storms, o

HTTP API is the right default choice for the majority of .NET serverless workloads. At 70% less cost than REST API, lower latency, and native JWT authorization, it covers most production requirements

AWS Lambda has become a cornerstone of modern serverless architectures, but writing a function that "just works" is very different from writing one that is performant, cost-effective, secure, and read

Blazor is becoming a popular choice for developing modern web applications using C# and .NET, offering two distinct hosting models:
Blazor Server: In this model, the application runs on the server, and UI updates are sent to the browser through a SignalR connection.
Blazor WebAssembly: In this model, the application runs directly in the browser using WebAssembly.
Within the Blazor WebAssembly model, there are two options for deploying our application:
Hosted deployment: In this option, the Blazor WebAssembly application is delivered from an ASP.NET Core app.
Standalone deployment: In this deployment, the Blazor WebAssembly application is delivered from a static web server. This option allows us to use various hosting environments like Amazon S3, GitHub Pages, Azure Static Web Apps, Azure Storage, and more.
In this article, we will deploy a Blazor WebAssembly application in an AWS S3 bucket and deliver it to our users using a CDN such as AWS CloudFront.
An IAM User with programmatic access.
Install the AWS CLI.
Install AWS SAM CLI.
We will use the default Blazor WebAssembly application provided by the templates. Run the following commands:
dotnet new blazorwasm -o MyApp
dotnet new sln -n Blazor
dotnet sln add --in-root MyApp
At the solution level, create a template.yml file with the following content:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
SAM
Resources:
MyBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: "<MY_BUCKET_NAME>"
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
MyCloudFrontOriginAccessControl:
Type: AWS::CloudFront::OriginAccessControl
Properties:
OriginAccessControlConfig:
Name: !Sub "OAC for ${MyBucket}"
OriginAccessControlOriginType: s3
SigningBehavior: always
SigningProtocol: sigv4
MyCloudFrontDistribution:
Type: AWS::CloudFront::Distribution
DependsOn:
- MyBucket
Properties:
DistributionConfig:
Origins:
- DomainName: !GetAtt MyBucket.DomainName
Id: !Sub "origin-${MyBucket}"
S3OriginConfig:
OriginAccessIdentity: ""
OriginAccessControlId: !GetAtt MyCloudFrontOriginAccessControl.Id
Enabled: "true"
PriceClass: "PriceClass_200"
IPV6Enabled : "false"
DefaultRootObject: index.html
ViewerCertificate:
CloudFrontDefaultCertificate: true
DefaultCacheBehavior:
AllowedMethods:
- DELETE
- GET
- HEAD
- OPTIONS
- PATCH
- POST
- PUT
CachedMethods :
- GET
- HEAD
Compress: true
TargetOriginId: !Sub "origin-${MyBucket}"
ForwardedValues:
QueryString: "false"
Cookies:
Forward: none
ViewerProtocolPolicy: allow-all
MyBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref MyBucket
PolicyDocument:
Version: 2008-10-17
Statement:
- Action:
- 's3:GetObject'
Effect: Allow
Principal:
Service: cloudfront.amazonaws.com
Resource: !Sub "${MyBucket.Arn}/*"
Condition:
StringEquals:
AWS:SourceArn: !Sub "arn:aws:cloudfront::${AWS::AccountId}:distribution/${MyCloudFrontDistribution.Id}"
Outputs:
CloudFrontURL:
Description: URL of CloudFront distribution.
Value: !GetAtt MyCloudFrontDistribution.DomainName
The script above defines the following resources:
AWS::S3::Bucket: This resource creates the AWS S3 bucket, blocking all public access.
AWS::CloudFront::OriginAccessControl: This resource creates a new origin access control (OAC). Once created, it can be added to an origin in a CloudFront distribution. This allows CloudFront to send authenticated requests to the origin, allowing us to block public access.
AWS::CloudFront::Distribution: This resource creates the distribution that instructs CloudFront where to locate the content to deliver and provides details on how to track and manage it.
AWS::S3::BucketPolicy: This resource configures our AWS S3 bucket to allow access for requests from the CloudFront distribution with OAC.
Run the following commands to deploy the resources to AWS:
sam build
sam deploy --guided
Once the resources are deployed, it's time to deploy our Blazor application to AWS S3:
dotnet publish -c Release
aws s3 sync '.\MyApp\bin\Release\net8.0\publish\wwwroot' s3://<MY_BUCKET_NAME>
Browse to the output URL to view the Blazor application up and running:

You can find all the code here. Thanks, and happy coding.