<?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: Scott</title>
    <description>The latest articles on DEV Community by Scott (@smjburton).</description>
    <link>https://dev.to/smjburton</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%2F2929278%2Fa56340ad-afcf-4367-a3e2-41b3d2205fa1.png</url>
      <title>DEV Community: Scott</title>
      <link>https://dev.to/smjburton</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/smjburton"/>
    <language>en</language>
    <item>
      <title>How to Set Up a Website using Astro and Podman Containers</title>
      <dc:creator>Scott</dc:creator>
      <pubDate>Mon, 31 Mar 2025 00:00:00 +0000</pubDate>
      <link>https://dev.to/smjburton/how-to-set-up-an-astro-website-using-podman-containers-4jam</link>
      <guid>https://dev.to/smjburton/how-to-set-up-an-astro-website-using-podman-containers-4jam</guid>
      <description>&lt;p&gt;Over the past couple years, containers have become my preferred method for developing applications, APIs, and websites. Podman containers offer a straightforward and efficient way to create isolated, consistent environments.&lt;/p&gt;

&lt;p&gt;Here's a few of the reasons I enjoy using Podman for development:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Consistency and Isolation&lt;/strong&gt;: Containers create a predictable environment by isolating dependencies, ensuring my local setup mirrors the production environment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Versioned Artifacts&lt;/strong&gt;: I utilize a CI/CD pipeline to publish apps, APIs, and websites; containers make it easy to generate versioned artifacts for easy tracking and management.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplified Development Workflow&lt;/strong&gt;: It streamlines moving from local development to production, avoiding common pitfalls related to running code in different environments.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Admittedly, developing Astro websites with containers is somewhat of a niche interest (hence the limited documentation available). However, I put together this guide to help readers who might be interested in this approach given the benefits of container development and deployment.&lt;/p&gt;

&lt;p&gt;In this post, I'll demonstrate how to set up an Astro project locally, then containerize it using Podman. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: This guide is valid for both Podman and Docker, just replace ‘podman’ for ‘docker’ for the commands. The instructions included here use Podman because it's my preferred platform, but you can use whichever container platform suits you best.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Initializing Astro Locally
&lt;/h2&gt;

&lt;p&gt;First, initialize your Astro project locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm create astro@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also initialize your Astro project using a template like the blog template to help you get started:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm create astro@latest &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--template&lt;/span&gt; blog &lt;span class="nt"&gt;--install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want additional dependencies like Tailwind CSS, install them locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;tailwindcss @tailwindcss/vite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: If you'd prefer bootstrapping Astro entirely within a container, run:&lt;/p&gt;


&lt;pre class="highlight shell"&gt;&lt;code&gt;podman run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PWD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;:/app:Z &lt;span class="nt"&gt;-w&lt;/span&gt; /app docker.io/library/node:22.14-alpine3.21 npm create astro@latest &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--template&lt;/span&gt; blog &lt;span class="nt"&gt;--install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Then, add dependencies similarly within the container:&lt;/p&gt;


&lt;pre class="highlight shell"&gt;&lt;code&gt;podman run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PWD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;:/app:Z &lt;span class="nt"&gt;-w&lt;/span&gt; /app docker.io/library/node:22.14-alpine3.21 npm &lt;span class="nb"&gt;install &lt;/span&gt;tailwindcss @tailwindcss/vite 
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;One of the benefits of this approach is that it's not necessary to install Node.js locally because you can use Node.js within the container to install your dependencies.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Preparing the Container for Build
&lt;/h2&gt;

&lt;p&gt;Include a &lt;code&gt;.dockerignore&lt;/code&gt; or &lt;code&gt;.containerignore&lt;/code&gt; file before building your container.&lt;/p&gt;

&lt;p&gt;At minimum, include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;dependencies&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;node_modules/&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;build&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;output&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;dist/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Review your project directory and add any other files you’d like to leave out of your container build (&lt;em&gt;like static images and videos&lt;/em&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Container
&lt;/h2&gt;

&lt;p&gt;Here's a simple &lt;code&gt;Containerfile&lt;/code&gt; example for creating an Astro website container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Linux&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;smaller&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;container&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;size&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;docker.io/node:&lt;/span&gt;&lt;span class="mf"&gt;22.14&lt;/span&gt;&lt;span class="err"&gt;-alpine&lt;/span&gt;&lt;span class="mf"&gt;3.21&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;WORKDIR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/app&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;COPY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;package*.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;./&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;npm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;install&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;npx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;astro&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;telemetry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;disable&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;COPY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;ENV&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;HOST=&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;ENV&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;PORT=&lt;/span&gt;&lt;span class="mi"&gt;4321&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;EXPOSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4321&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;CMD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"npm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"run"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--host"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: To access your Astro container from the host, you must use the &lt;code&gt;--host&lt;/code&gt; flag, as shown above.&lt;br&gt;
Another option is to update your &lt;code&gt;package.json&lt;/code&gt; scripts to:&lt;/p&gt;


&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"astro dev --host"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"preview"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"astro preview --host"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Then your &lt;code&gt;Containerfile&lt;/code&gt; would simply use:&lt;/p&gt;


&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;CMD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"npm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"run"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Instead of the &lt;code&gt;CMD ["npm", "run", "dev", "--", "--host"]&lt;/code&gt; shown above.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this example, I used the Alpine Linux image for the container to significantly reduce the image size, improving build and deployment times.&lt;/p&gt;

&lt;p&gt;For consistent builds, especially in CI/CD environments, you should consider using “npm ci” instead of “npm install” in your container builds. Also, for production deployments, it's recommended to build static assets using “npm run build” (“astro build”) and serve them with a production-ready web server, such as nginx, instead of running the development server (“npm run dev”).&lt;/p&gt;

&lt;p&gt;Finally, build the container using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;podman build &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; Containerfile &lt;span class="nt"&gt;-t&lt;/span&gt; localhost/astro-podman-website:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tag “latest” is used here for demonstration purposes, but you should ideally use semantic versioning tags (e.g., localhost/astro-podman-website:1.0.0) to manage container versions clearly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running the Container
&lt;/h2&gt;

&lt;p&gt;To run your Astro container, use the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;podman run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; astro-podman-website &lt;span class="nt"&gt;-p&lt;/span&gt; 4321:4321 &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PWD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;:/app:Z localhost/astro-podman-website:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your Astro website will be available on &lt;code&gt;localhost:4321&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A couple notes on this “podman run” command:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The volume mount (-v "${PWD}":/app:Z) links your local project directory directly to the container's /app directory. This setup ensures any changes you make locally are immediately reflected inside the running container, eliminating the need to rebuild the container each time. This greatly speeds up the development cycle and simplifies testing changes.&lt;/li&gt;
&lt;li&gt;The “:Z” tag at the end of the volume mount helps with permission or SELinux issues with Podman by addressing SELinux contexts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you encounter any issues running the container, you can inspect the container by viewing its logs (“podman logs astro-podman-website”), or by entering the container’s shell to debug issues (“podman exec -it astro-podman-website /bin/sh").&lt;/p&gt;

&lt;p&gt;Once you are done, run the commands “podman stop astro-podman” and then “podman rm astro-podman” to stop and remove the container.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing Thoughts
&lt;/h2&gt;

&lt;p&gt;Deploying your Astro website using Podman containers can make your workflow more efficient by providing a seamless way to manage your development and production environments.&lt;/p&gt;

&lt;p&gt;What do you think about this approach? Could you see yourself using containers to develop and deploy Astro websites? Let me know what you think in the comments.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>astro</category>
      <category>podman</category>
      <category>containers</category>
    </item>
  </channel>
</rss>
