Deploying Astro to Fly: Part 2

4 min read

A quick how-to guide on deploying your server-side rendered Astro projects to Fly.io.

Deploying Astro projects to Fly.io.Deploying Astro projects to Fly.io.

Introduction

In part one of the series we covered how to deploy static Astro projects to fly.io. Here in part two we will cover how to deploy server-side rendered Astro projects, and it’s just as easy if not easier!

Updating our Astro Project for SSR

pnpm astro add node
astro.config.mjs
import { defineConfig } from 'astro/config';
+ import node from '@astrojs/node';
 
export default defineConfig({
+ adapter: node({
+   mode: 'standalone',
+ }),
+ output: 'server',
+ server: {
+   port: 3000,
+ },
  site: "https://astro-project.fly.dev",
});

Updating Docker & Fly Configurations

We are basically going to revert what we did to both files. Like I mentioned before this is actually easier than the static deployment.

Dockerfile
# syntax = docker/dockerfile:1
 
# Adjust NODE_VERSION as desired
ARG NODE_VERSION=20.9.0
FROM node:${NODE_VERSION}-slim as base
 
LABEL fly_launch_runtime="Node.js"
 
# Node.js app lives here
WORKDIR /app
 
# Set production environment
ENV NODE_ENV="production"
 
# Install pnpm
ARG PNPM_VERSION=8.10.5
RUN npm install -g pnpm@$PNPM_VERSION
 
# Throw-away build stage to reduce size of final image
FROM base as build
 
# Install packages needed to build node modules
- RUN apt-get update -qq && \
- apt-get install -y build-essential pkg-config python-is-python3
+ RUN apt-get update -qq && \
+ apt-get install --no-install-recommends -y build-essential node-gyp pkg-config python-is-python3
 
 
# Install node modules
COPY --link package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile --prod=false
 
# Copy application code
COPY --link . .
 
# Build application
RUN pnpm run build
 
# Remove development dependencies
RUN pnpm prune --prod
 
# Final stage for app image
- FROM pierrezemb/gostatic
+ FROM base
 
# Copy built application
- COPY --from=build /app/dist /srv/http
+ COPY --from=build /app /app
 
# Start the server by default, this can be overwritten at runtime
+ EXPOSE 3000
 
+ CMD [ "pnpm", "run", "start" ]
fly.toml
# fly.toml app configuration file generated for astro-project on 2024-01-07T13:23:32-05:00
#
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
#
 
app = "astro-project"
primary_region = "bog"
 
[build]
 
- [[services]]
-	http_checks = []
-	internal_port = 8043
-	processes = ["app"]
-	protocol = "tcp"
-	script_checks = []
-
-	[[services.concurrency]]
-		hard_limit = 25
-		soft_limit = 20
-		type = "connections"
-
-	[[services.ports]]
-		handlers = ["http"]
-		port = 80
-		force_https = true
-
-	[[services.ports]]
-		handlers = ["tls", "http"]
-		port = 443
-
-	[[services.tcp_checks]]
-		grace_period = "1s"
-		interval = "15s"
-		restart_limit = 0
-		timeout = "2s"
 
+ [http_service]
+	internal_port = 3000
+	force_https = true
+	auto_stop_machines = true
+	auto_start_machines = true
+	min_machines_running = 0
+	processes = ["app"]
 
[[vm]]
	cpu_kind = "shared"
	cpus = 1
	memory_mb = 1024

One last thing we will need to do before we can deploy is update our start script in the package.json. When we run pnpm build their will be a dist/ that is output by Astro. In this directory you should find another directory called server/ with an entry.mjs file inside of it. This is the file that we will need to tell Docker to execute on Fly’s servers.

package.json
{
   "name": "astro-project",
   "type": "module",
   "version": "0.0.1",
   "scripts": {
     "dev": "astro dev",
-    "start": "astro dev",
+     "start": "HOST=0.0.0.0 node ./dist/server/entry.mjs",
     "build": "astro check && astro build",
     "preview": "astro preview",
     "astro": "astro"
   },
   "dependencies": {
     "@astrojs/check": "~0.3.4",
     "@astrojs/node": "7.0.4",
     "astro": "^4.1.1",
     "typescript": "~5.3.3"
   },
   "devDependencies": {
     "@flydotio/dockerfile": "~0.5.0"
   }
 }

NOTE: Please note the addition of HOST=0.0.0.0 to the command. This is necessary as when we start the server Astro believes it is running locally so we end up with 127.0.0.1:3000. This is fine on your and my machine but on Fly this will not…fly…hahaha!

And with that we can run fly deploy and wait to visit our updated Astro project that is not server-side rendered.

fly deploy
==> Verifying app config
Validating /Users/cody/Developer/Personal/astro-project/fly.toml
Platform: machines
 Configuration is valid
--> Verified app config
==> Building image
Remote builder fly-builder-throbbing-bush-1757 ready
Remote builder fly-builder-throbbing-bush-1757 ready
==> Building image with Docker
--> docker host: 20.10.12 linux x86_64
# #########################
# ... Lots of Docker output
# #########################
Watch your deployment at https://fly.io/apps/astro-project/monitoring
 
-------
Updating existing machines in 'astro-project' with rolling strategy
 
-------
 [1/2] Machine 9080ee2df06258 [app] update succeeded
 [2/2] Machine e7842741b99483 [app] update succeeded
-------
 
Visit your newly deployed app at https://astro-project.fly.dev/
~ Cody 🚀

Related Articles


    From NextJS to Astro

    In 2023 I began making the move from NextJS to Astro for my personal website and blog. This is my experience with the transition.

    Adding Related Articles with Astro Content Collections

    Astro's content collection feature is a game changer for easily managing content in a type safe manner. It also can help to easily add related collections or data types through referencing. In this article I show how I implemented a related articles feature.

Cody Brunner

Cody is a Christian, USN Veteran, Jayhawk, and an American expat living outside of Bogotá, Colombia where he works as a Senior Frontend Developer for Bitcoin IRA.