<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Patric Vormstein</title>
    <description>The latest articles on DEV Community by Patric Vormstein (@pvormste).</description>
    <link>https://dev.to/pvormste</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F405850%2Fc22674e7-de7f-4073-8163-150c893cdfdc.jpeg</url>
      <title>DEV Community: Patric Vormstein</title>
      <link>https://dev.to/pvormste</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pvormste"/>
    <language>en</language>
    <item>
      <title>Blazor WASM with Caddy 2</title>
      <dc:creator>Patric Vormstein</dc:creator>
      <pubDate>Wed, 10 Jun 2020 15:30:09 +0000</pubDate>
      <link>https://dev.to/pvormste/blazor-wasm-with-caddy-2-4a4h</link>
      <guid>https://dev.to/pvormste/blazor-wasm-with-caddy-2-4a4h</guid>
      <description>&lt;p&gt;Are you also so excited about new technologies like me? Are you a fan of .NET? Bonus: Do you dislike to write frontend code because of JavaScript?&lt;/p&gt;

&lt;p&gt;Then welcome to the club!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dotnet.microsoft.com/apps/aspnet/web-apps/blazor"&gt;Blazor&lt;/a&gt; is Microsoft's approach to bring .NET to the browsers and enable developers to use a single stack for backend and frontend development.&lt;br&gt;
There are 2 possible hosting models for Blazor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;as server solution where the state of the client is saved on the server and changes are transported via SignalR (WebSockets)&lt;/li&gt;
&lt;li&gt;as WASM solution where the .NET Runtime and the frontend application are packed as WASM and retrieved by user's browser (yes, the client will need to download up to 7 MB of data initially...)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this article I want to show you how you can statically host you Blazor WASM app with Caddy 2.&lt;br&gt;
&lt;a href="https://caddyserver.com/"&gt;Caddy 2&lt;/a&gt; is a web server / proxy solution similar to Nginx. It is written in Go and therefore available for all major OS.&lt;/p&gt;

&lt;p&gt;So let's get started!&lt;/p&gt;
&lt;h1&gt;
  
  
  Local environment
&lt;/h1&gt;

&lt;p&gt;I will assume that you have basic knowledge of .NET Core and also having Caddy installed on your system. But I won't touch any C# code because the Blazor template is already a working app!&lt;/p&gt;

&lt;p&gt;So first we will setup the project. For the Blazor project, I will use the &lt;code&gt;--pwa&lt;/code&gt; flag because it would be really cool to be able to use the app as desktop app later! (Yes that's all what we need for PWA support)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet new sln &lt;span class="nt"&gt;-n&lt;/span&gt; BlazorWASM
dotnet new blazorwasm &lt;span class="nt"&gt;-o&lt;/span&gt; BlazorWASM.Client &lt;span class="nt"&gt;--pwa&lt;/span&gt;
dotnet sln add BlazorWASM.Client/BlazorWASM.Client.csproj
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With the basic setup inplace we now want to add a so called &lt;code&gt;Caddyfile&lt;/code&gt; which will configure Caddy for us.&lt;br&gt;
Put it into &lt;code&gt;./BlazorWASM.Client/wwwroot/Caddyfile&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;localhost

try_files {path} /index.html
file_server
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The content is a short story: We are telling Caddy that our page should live under the &lt;code&gt;localhost&lt;/code&gt; hostname. It should serve the files as a file server and when a file is not found it should redirect the request to the &lt;code&gt;index.html&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Examples:&lt;br&gt;
&lt;code&gt;https://localhost/css/app.css&lt;/code&gt; =&amp;gt; works!&lt;br&gt;
&lt;code&gt;https://localhost/where-is-my-beer&lt;/code&gt; =&amp;gt; redirect to &lt;code&gt;index.html&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Oh, I forgot to mention that Caddy will automatically setup https for us! Awesome!&lt;/p&gt;

&lt;p&gt;In the next step we need to publish our Blazor app (to a folder):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;BlazorWASM.Client
dotnet publish &lt;span class="nt"&gt;-o&lt;/span&gt; bin/Publish BlazorWASM.Client.csproj
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I'm using the folder &lt;code&gt;bin/Publish&lt;/code&gt; here, but actually this doesn't matter - put it where you want.&lt;/p&gt;

&lt;p&gt;Now head to the publish folder and start Caddy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;bin/Publish/wwwroot
caddy run
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you are wondering whats happening here: Caddy picks up our &lt;code&gt;Caddyfile&lt;/code&gt; we have written before and sets up https for our site. It may be the case that Caddy asks for your system password to install the certificates.&lt;/p&gt;

&lt;p&gt;When Caddy has started you can now head to &lt;code&gt;https://localhost&lt;/code&gt; in your browser of choice (except IE, because IE doesn't support WASM and you really shouldn't use IE anymore ...).&lt;/p&gt;

&lt;p&gt;And tada! 🎉&lt;br&gt;
You are now seeing the Blazor WASM app statically hosted via Caddy.&lt;/p&gt;
&lt;h1&gt;
  
  
  Docker
&lt;/h1&gt;

&lt;p&gt;So far so good! Let's take this further and try to host the Blazor app in a docker container. With Caddy of course.&lt;/p&gt;

&lt;p&gt;For that we need to change our &lt;code&gt;Caddyfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    auto_https disable_redirects
}

localhost:80 {
    try_files {path} /index.html
    file_server
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So, why are we changing the &lt;code&gt;Caddyfile&lt;/code&gt;? We need to turn off the automatic https configuration because we don't have a domain and we will run the container locally. If we wouldn't to this, the browser won't trust the certificate and complain about it.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;auto_https&lt;/code&gt; is a new feature in Caddy 2.1 and won't work with Caddy 2.0 or below. (It is possible for 2.0 with a json config, but this is out of scope)&lt;/p&gt;

&lt;p&gt;Now create the Dockerfile &lt;code&gt;./BlazorWASM.Client/Dockerfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; mcr.microsoft.com/dotnet/core/sdk:3.1 AS builder&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /caddy&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;curl &lt;span class="nt"&gt;-L&lt;/span&gt; https://github.com/caddyserver/caddy/releases/download/v2.1.0-beta.1/caddy_2.1.0-beta.1_linux_amd64.tar.gz &lt;span class="nt"&gt;-o&lt;/span&gt; ./caddy_2.1.0-beta.1_linux_amd64.tar.gz
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;tar &lt;/span&gt;xfvz caddy_2.1.0-beta.1_linux_amd64.tar.gz
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /build&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;dotnet publish &lt;span class="nt"&gt;-o&lt;/span&gt; bin/Publish

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; alpine:latest&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; XDG_CONFIG_HOME=/config&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; XDG_DATA_HOME=/data&lt;/span&gt;
&lt;span class="k"&gt;VOLUME&lt;/span&gt;&lt;span class="s"&gt; /config&lt;/span&gt;
&lt;span class="k"&gt;VOLUME&lt;/span&gt;&lt;span class="s"&gt; /data&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /site&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /caddy/caddy /bin/caddy&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /build/bin/Publish/wwwroot/ .&lt;/span&gt;
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["caddy", "run"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We are using a multi stage Dockerfile here. The first stage will download Caddy 2.1 and publish our Blazor app.&lt;br&gt;
The second stage copies all needed data over from the builder container and sets up some variables needed by Caddy.&lt;/p&gt;

&lt;p&gt;Add a &lt;code&gt;./BlazorWASM.Client/.dockerignore&lt;/code&gt; file and ignore build related directories - we don't need them to be copied over:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# .dockerignore
bin/
obj/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Time to test it! Build the container and create a volume for the data Caddy needs to persist.&lt;br&gt;
Then start it - we will use a port mapping from 9000 to 80.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; blazorwasm &lt;span class="nb"&gt;.&lt;/span&gt; 
docker volume create caddy-data
docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 9000:80 &lt;span class="nt"&gt;-v&lt;/span&gt; caddy-data:/data blazorwasm
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Open your browser again and visit &lt;code&gt;http://localhost:9000&lt;/code&gt;. &lt;br&gt;
Hello Blazor in Docker! 🎉&lt;/p&gt;

&lt;p&gt;Don't forget to try out the PWA functionality 👍.&lt;/p&gt;

&lt;h1&gt;
  
  
  Going further
&lt;/h1&gt;

&lt;p&gt;I hope you can see how powerful this setup can be - you can host you Blazor app on any static hosting provider, e.g. Azure Storage (&lt;a href="https://www.youtube.com/watch?v=T6pepcxEudI"&gt;Video&lt;/a&gt;), Vercel, Render, etc.&lt;br&gt;
And with Docker you can host your app on any Provider supporting Docker. Pretty nice, isn't it?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Related links:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/blazor/webassembly?view=aspnetcore-3.1"&gt;Blazor Hosting Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://caddyserver.com/docs/"&gt;Caddy Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hub.docker.com/_/caddy?tab=description"&gt;Caddy Docker Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>blazor</category>
      <category>webassembly</category>
      <category>dotnet</category>
      <category>caddy</category>
    </item>
  </channel>
</rss>
