How to Integrate DigitalOcean with Astro: Complete Guide
Step-by-step guide to integrating DigitalOcean with your Astro website. Setup, configuration, and best practices.
How to Integrate DigitalOcean with Astro: Complete Guide
DigitalOcean provides cloud infrastructure for deploying web applications, with options ranging from managed app hosting to custom servers. For Astro projects, DigitalOcean offers two main deployment paths: App Platform for managed deployments with automatic builds, and Droplets for full control over your server environment. Both support static Astro sites and server-rendered applications.
This guide covers deploying Astro to DigitalOcean App Platform (the managed approach) and setting up a Droplet with Node.js for server-rendered (on-demand) Astro projects. It targets Astro 6 (the current major release), so the configuration reflects the current rendering model where static is the default and output: 'server' plus an adapter is what enables on-demand rendering.
Prerequisites
Before starting, you will need:
- Node.js 22.12.0 or later installed locally. Astro 6 dropped support for Node 18 and Node 20, so Node 22 is now the floor (Node 24 also works). Verify with
node --version. - An existing Astro project in a Git repository (GitHub, GitLab, or Bitbucket)
- A DigitalOcean account (new accounts get free trial credit; the exact amount and duration vary by current promotion, so confirm on the signup page)
- doctl CLI installed (optional but helpful):
brew install doctl(Homebrew currently ships doctl 1.160.0)
Installation
For Static Sites
No additional packages needed. Astro builds static sites by default. In Astro 5 and 6 the output option only accepts 'static' (the default) or 'server'. The old output: 'hybrid' value was removed in Astro 5, so do not add it. If you previously used hybrid, the replacement is to leave output as the default 'static' and opt individual routes into on-demand rendering with export const prerender = false (an adapter is required for those routes).
For Server-Rendered Sites
For on-demand (SSR) rendering, install the Node.js adapter. The astro add command installs the latest adapter and wires it into your config automatically:
npx astro add node
As of this writing the adapter resolves to @astrojs/node 10.1.2, which declares a peer dependency of astro@^6.3.0. Pin it explicitly if you prefer:
npm install @astrojs/node@^10.1.2
Configure your astro.config.mjs:
// astro.config.mjs
import { defineConfig } from 'astro/config';
import node from '@astrojs/node';
export default defineConfig({
output: 'server',
adapter: node({ mode: 'standalone' }),
});
The adapter has two modes. standalone produces a self-contained server that you start by running the entry module directly (used throughout this guide). middleware instead produces a handler you mount inside an existing Node server such as Express or Fastify. For App Platform and Droplet deployments, standalone is the right choice.
Configuration
Method 1: App Platform (Recommended)
DigitalOcean App Platform is a managed PaaS that builds and deploys your app from a Git repository. It handles SSL, CDN, and scaling automatically.
Step 1: Create App Spec
Create an .do/app.yaml file in your project root. For a static Astro site:
# .do/app.yaml
name: my-astro-site
static_sites:
- name: web
github:
repo: your-username/your-repo
branch: main
build_command: npm run build
output_dir: dist
environment_slug: node-js
envs:
- key: NODE_ENV
value: production
The output_dir field is optional. If you omit it, App Platform scans for a build output directory using these names in order: _static, dist, public, build. Astro builds static output to dist, so the auto-detection works without output_dir, but setting it explicitly is clearer.
For a server-rendered Astro site:
# .do/app.yaml
name: my-astro-app
services:
- name: web
github:
repo: your-username/your-repo
branch: main
build_command: npm run build
run_command: node dist/server/entry.mjs
environment_slug: node-js
http_port: 4321
instance_size_slug: basic-xxs
instance_count: 1
envs:
- key: HOST
value: "0.0.0.0"
- key: PORT
value: "4321"
- key: NODE_ENV
value: production
App Platform requires the service to bind to 0.0.0.0 on the port declared in http_port. The Node adapter in standalone mode reads the HOST and PORT environment variables, so setting HOST=0.0.0.0 and PORT=4321 (matching http_port) is what makes the service reachable. Without HOST=0.0.0.0 the server binds to localhost only and App Platform marks the deployment unhealthy.
Step 2: Deploy via Dashboard
- Go to DigitalOcean Dashboard > Apps > Create App
- Connect your GitHub/GitLab repository
- Select the branch to deploy from
- DigitalOcean auto-detects the framework and suggests build settings
- Adjust the build command to
npm run buildand output directory todist - Choose your plan and region
- Click Deploy
Step 3: Deploy via CLI
Alternatively, deploy using the doctl CLI:
doctl auth init
doctl apps create --spec .do/app.yaml
Method 2: Droplet Deployment
For full server control, deploy Astro to a DigitalOcean Droplet.
Step 1: Create the Droplet
doctl compute droplet create astro-server \
--image ubuntu-22-04-x64 \
--size s-1vcpu-1gb \
--region nyc1 \
--ssh-keys YOUR_SSH_KEY_FINGERPRINT
Step 2: Server Setup
SSH into your Droplet and install Node.js:
ssh root@your-droplet-ip
# Install Node.js via nvm (v0.40.4 is the current nvm release)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash
source ~/.bashrc
# Astro 6 needs Node 22.12.0 or later; install the Node 22 LTS line
nvm install 22
nvm use 22
# Install PM2 for process management
npm install -g pm2
# Install Nginx as reverse proxy
apt update && apt install -y nginx
Step 3: Deploy Your Astro App
# Clone your repository
git clone https://github.com/your-username/your-repo.git /var/www/astro-app
cd /var/www/astro-app
# Install dependencies and build
npm install
npm run build
# Start with PM2
pm2 start dist/server/entry.mjs --name astro-app
pm2 save
pm2 startup
Step 4: Configure Nginx
# /etc/nginx/sites-available/astro-app
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
location / {
proxy_pass http://localhost:4321;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}
Enable the site and add SSL:
ln -s /etc/nginx/sites-available/astro-app /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
# Add SSL with Let's Encrypt
apt install -y certbot python3-certbot-nginx
certbot --nginx -d yourdomain.com -d www.yourdomain.com
Common Patterns
Environment Variables on App Platform
Add environment variables through the DigitalOcean dashboard or the app spec:
envs:
- key: DATABASE_URL
value: "postgresql://user:pass@host:5432/db"
type: SECRET
- key: PUBLIC_SITE_URL
value: "https://yourdomain.com"
Variables marked as SECRET are encrypted and hidden in the dashboard.
Connecting to Managed Database
DigitalOcean offers managed PostgreSQL, MySQL, and Redis. Connect your Astro app to a managed database:
# In app.yaml
databases:
- name: db
engine: PG
version: "16"
size: db-s-1vcpu-1gb
num_nodes: 1
Reference the database connection string with ${db.DATABASE_URL} in your app's environment variables.
Auto-Deploy on Push
App Platform automatically deploys when you push to the configured branch. For more control, disable auto-deploy and use the CLI or API:
# Trigger manual deployment
doctl apps create-deployment YOUR_APP_ID
Custom Domain Setup
In the DigitalOcean dashboard, go to your app's Settings > Domains. Add your custom domain and point your DNS to DigitalOcean's nameservers or add the provided CNAME record.
# If using DigitalOcean DNS
doctl compute domain create yourdomain.com
doctl compute domain records create yourdomain.com \
--record-type CNAME \
--record-name www \
--record-data your-app.ondigitalocean.app.
Troubleshooting
Build fails on App Platform: Check the build logs in the DigitalOcean dashboard. Common issues include missing environment variables during build time, Node.js version mismatches, or memory limits on the smallest instance size. Upgrade to a larger instance if builds run out of memory.
"Cannot find module" error on a server-rendered deployment: Make sure your package.json lists all runtime dependencies under dependencies, not devDependencies. Production installs skip dev dependencies (modern npm uses npm install --omit=dev; older docs called this --production), so anything imported by the running server must be a regular dependency.
Port binding error: App Platform expects your app to listen on the port specified in the http_port config and to bind to 0.0.0.0 rather than localhost. The Node adapter in standalone mode reads the HOST and PORT environment variables, so set HOST=0.0.0.0 and a PORT that matches http_port. If HOST is left unset the server binds to localhost and the health check fails.
Static site returning 404 on routes: For static sites with client-side routing, add a catch-all route configuration. In App Platform, set catchall_document: index.html under your static_sites entry in the app spec, which serves index.html for any path that does not match a built file. Note that only one of catchall_document or error_document can be set on a static site. The cleaner option for a content site is to configure your Astro project to generate all routes at build time so every URL has a real HTML file.
static_sites:
- name: web
source_dir: /
catchall_document: index.html
SSL certificate not working on Droplet: Certbot may fail if your DNS has not propagated yet. Verify your domain points to the Droplet's IP address with dig yourdomain.com. Also make sure ports 80 and 443 are open in your firewall: ufw allow 80 && ufw allow 443.
High memory usage on Droplet: Node.js can consume significant memory for on-demand rendering. Set a memory limit with PM2: pm2 start dist/server/entry.mjs --max-memory-restart 512M. For static sites, serve the dist directory directly with Nginx instead of running Node.js.
Common Errors and Fixes
These are the doc-grounded gotchas that catch people most often when pairing Astro 6 with DigitalOcean.
output: 'hybrid' is not a valid config value. Astro removed the hybrid output mode in Astro 5, and Astro 6 keeps only 'static' (default) and 'server'. A config that still sets output: 'hybrid' will error on build. The fix is to leave output as the default 'static' and mark only the routes that need a server with export const prerender = false, or set output: 'server' and mark the static ones with export const prerender = true. An adapter is required for any on-demand route.
Adapter missing for on-demand routes. If you add export const prerender = false (or set output: 'server') without an adapter installed, the build fails because Astro has no server runtime target. Run npx astro add node so the build emits dist/server/entry.mjs.
Node version too old for Astro 6. Astro 6 requires Node 22.12.0 or later and dropped Node 18 and 20. On App Platform, the node-js environment slug provides a recent Node, but if you pin a Node version through an .nvmrc, engines field, or node-js buildpack setting, make sure it is at least 22.12.0. On a Droplet, install Node 22 with nvm as shown above. A too-old Node typically surfaces as a syntax or "unsupported engine" error during npm run build.
Service bound to localhost instead of 0.0.0.0. App Platform routes traffic to the port in http_port and the container must listen on 0.0.0.0. The Node standalone server reads HOST and PORT from the environment, so set HOST=0.0.0.0 and PORT equal to http_port. Omitting HOST leaves the server on localhost and the deployment fails its health check.
Runtime dependency placed in devDependencies. Production installs omit dev dependencies (modern npm uses npm install --omit=dev). Anything the running server imports must live in dependencies, including @astrojs/node. A "Cannot find module" at runtime usually means a dependency landed in the wrong section of package.json.
Static single-page routes 404 because there is no catch-all. App Platform serves real files for static sites. If your site relies on client-side routing for paths that have no built HTML file, set catchall_document: index.html under the static_sites entry. Only one of catchall_document or error_document may be set. For a content-first Astro site, prefer generating every route at build time so each URL maps to a real file.
Build output directory not detected. When output_dir is omitted, App Platform scans for _static, dist, public, then build. Astro outputs to dist, so detection works, but if you customize Astro's outDir you must set output_dir to match or the deploy will publish an empty or wrong directory.
Official Docs and Examples
- Astro deploy guides index: https://docs.astro.build/en/guides/deploy/
- Astro Node adapter reference (
@astrojs/node): https://docs.astro.build/en/guides/integrations-guide/node/ - Astro on-demand rendering and the
outputoption: https://docs.astro.build/en/guides/on-demand-rendering/ - Astro v6 upgrade guide (Node 22 requirement, removed options): https://docs.astro.build/en/guides/upgrade-to/v6/
- DigitalOcean App Platform documentation: https://docs.digitalocean.com/products/app-platform/
- DigitalOcean App Platform "Create Apps" how-to: https://docs.digitalocean.com/products/app-platform/how-to/create-apps/
- DigitalOcean App Spec reference (
static_sites,services,catchall_document,envs): https://docs.digitalocean.com/products/app-platform/reference/app-spec/ - DigitalOcean "Deploy Sample Apps" (includes static-site examples you can adapt for Astro): https://docs.digitalocean.com/products/app-platform/getting-started/deploy-sample-apps/
- Example repository, Astro's own withastro/astro adapter source and examples: https://github.com/withastro/astro/tree/main/packages/integrations/node
Conclusion
DigitalOcean gives you flexibility in how you deploy Astro. App Platform provides the simplest path with managed builds, auto-deploy, and SSL included. Droplets offer full control when you need custom server configurations, additional services, or tighter cost management. For most Astro projects, start with App Platform for simplicity. Move to a Droplet when you need more control over the server environment or want to run multiple services alongside your Astro application. Static sites can use the lowest App Platform tier, making it a cost-effective choice for blogs and marketing sites.
Sources
Versions and configuration facts in this guide were verified against the following sources, checked on 2026-05-29:
- Astro Node adapter docs, install command and adapter modes: https://docs.astro.build/en/guides/integrations-guide/node/
- Astro on-demand rendering docs, valid
outputvalues and adapter requirement: https://docs.astro.build/en/guides/on-demand-rendering/ - Astro v6 upgrade guide, Node 22.12.0 minimum and dropped Node 18 and 20 support: https://docs.astro.build/en/guides/upgrade-to/v6/
- Astro deploy guides index: https://docs.astro.build/en/guides/deploy/
- DigitalOcean App Platform "Create Apps" how-to, static output auto-detection and default run command: https://docs.digitalocean.com/products/app-platform/how-to/create-apps/
- DigitalOcean App Spec reference,
static_sites,services,catchall_document, andenvs: https://docs.digitalocean.com/products/app-platform/reference/app-spec/ - npm registry,
astrolatest version 6.4.2: https://registry.npmjs.org/astro/latest - npm registry,
@astrojs/nodelatest version 10.1.2 with peerastro@^6.3.0: https://registry.npmjs.org/@astrojs/node/latest - Homebrew formula,
doctl1.160.0: https://formulae.brew.sh/api/formula/doctl.json - nvm releases, current release v0.40.4: https://github.com/nvm-sh/nvm/releases/latest
- Node.js release index, Node 22 (Jod) and Node 24 (Krypton) LTS lines: https://nodejs.org/dist/index.json
Related Articles
How to Use Algolia with Astro: Complete Guide
Step-by-step guide to integrating Algolia with your Astro website.
How to Integrate Auth0 with Astro: Complete Guide
Step-by-step guide to integrating Auth0 with your Astro website. Setup, configuration, and best practices.
How to Use AWS Amplify with Astro: Complete Guide
Step-by-step guide to integrating AWS Amplify with your Astro website.