Dokploy Deployment Guide for Your Astro App
This guide documents the deployment approach we used deploying an Astro project to Dokploy (Hostinger) with Docker and Nginx.
1. Goal
Deploy a static Astro site using:
- Docker multi-stage build
- Nginx as the runtime web server
- Dokploy as the deployment platform
Why this approach:
- Lower memory usage than running Node in production for static files
- Faster static file delivery
- Smaller production image
2. Project Files Used
These files are used for deployment:
Dockerfilenginx.conf.dockerignore
3. Dockerfile Strategy (Multi-Stage)
The build has two stages:
- Builder stage (
node:22-alpine)
- Installs pnpm
- Installs dependencies
- Runs
pnpm run build - Produces static output in
dist/
- Runtime stage (
nginx:alpine)
- Copies
nginx.conf - Copies built files from
dist/into Nginx web root - Exposes port 80
- Starts Nginx in foreground
Result: production container serves static files with Nginx only.
Important compatibility notes for this repo:
- Astro 6 requires Node
>=22.12.0in build environments. - Use pnpm v9 in Docker to avoid non-interactive
approve-buildsfailures from newer pnpm defaults.
4. Nginx Config Essentials
The Nginx config in this project includes:
- Gzip compression for text assets
- Cache rules:
- Long cache for versioned assets (
.js,.css, fonts, svg) - Medium cache for images
- No cache for HTML
- Long cache for versioned assets (
- Security headers:
X-Frame-OptionsX-Content-Type-OptionsX-XSS-ProtectionReferrer-Policy
- SPA-style fallback:
try_files $uri $uri/ /index.html;
This fallback is important when users open deep routes directly.
5. Local Test Workflow
From project root:
docker build -t my-astro-app:latest .docker run -p 8080:80 my-astro-app:latestOpen:
http://localhost:8080
Quick checks:
- Home page loads
- Refresh works
- Direct route (for example
/about) works
6. Dokploy Deployment Steps
- Push repo changes to your Git provider.
- Open Dokploy dashboard.
- Create or open your application.
- Select Docker-based deployment (not Nixpacks).
- Ensure configuration:
- Dockerfile path:
Dockerfile - Build context:
.
- Deploy.
- Watch build/runtime logs.
- Attach domain and SSL in Dokploy.
7. Troubleshooting
Build fails during pnpm install
Possible causes:
- Lockfile out of sync
- pnpm version mismatch
- network/cache issue in build environment
If you see ERR_PNPM_IGNORED_BUILDS during Docker build:
- Pin pnpm to v9 in
Dockerfile(for examplenpm install -g pnpm@9). - Rebuild image.
If you see Astro Node version error:
- Ensure Docker builder image uses Node 22+ (for example
node:22-alpine).
Try:
pnpm install
pnpm run buildIf local works, rebuild image with no cache:
docker build --no-cache -t my-astro-app:latest .Build succeeds but app is blank/404 on refresh
- Verify Nginx fallback exists:
location / {
try_files $uri $uri/ /index.html;
}Container starts but not reachable
- Confirm Dokploy published port correctly
- Confirm container listens on port 80 (Nginx)
- Check Dokploy service/domain routing and SSL settings
Validate Nginx config inside container
nginx -t8. Useful Nginx Commands (inside container)
nginx -t
nginx -s reload
nginx -s stop9. Recommended Production Notes
- Keep Astro output static when possible.
- Cache immutable assets aggressively.
- Keep HTML non-cached for safe updates.
- Keep image small by using multi-stage Docker builds.
- Monitor Dokploy logs after each deployment.
10. Quick Reference Checklist
-
Dockerfilepresent -
nginx.confpresent -
.dockerignorepresent -
docker buildsucceeds locally -
docker run -p 8080:80 ...serves site - Docker deployment selected in Dokploy
- Domain + SSL configured
11. Hostinger Dokploy Appendix (Project-Specific)
Use this section as your default runbook for this repository.
Repository Mapping
- Repository:
lussino/my-first-app - Production branch:
main - Suggested Dokploy app name:
my-first-app-prod - Suggested staging app name:
my-first-app-staging
Copy-Ready Dokploy Settings (Production)
| Setting | Value |
|---|---|
| Source provider | GitHub |
| Repository | lussino/my-first-app |
| Branch | main |
| Build type | Dockerfile |
| Dockerfile path | Dockerfile |
| Build context | . |
| Internal container port | 80 |
| Health check path | / |
| Auto deploy on push | Enabled |
Domain and Routing
- Add your production domain in Dokploy (for example,
app.yourdomain.com). - Ensure HTTPS/SSL is enabled in Dokploy.
- If you use a root domain and
www, set a single canonical host and redirect the other.
Environment Variables Convention
This Astro setup is static-first. If you do not use runtime server code, you may need few or no runtime env vars.
If needed, define variables in Dokploy using this naming approach:
- Public values exposed to client bundle:
PUBLIC_* - Private values for build-time only: non-
PUBLIC_*
Recommended starter set:
| Variable | Example | Required |
|---|---|---|
PUBLIC_SITE_URL | https://app.yourdomain.com | Yes |
PUBLIC_SITE_NAME | My First App | Optional |
NODE_ENV | production | Yes |
Suggested Branch Strategy
main-> production Dokploy app (my-first-app-prod)develop-> staging Dokploy app (my-first-app-staging)
This lets you validate changes in staging before promoting to production.
Deployment SOP (Production)
- Merge approved changes into
main. - Confirm
Dockerfile,nginx.conf, and.dockerignoreare present. - Dokploy auto-build triggers from
mainpush. - Check build logs for image build success.
- Check runtime logs for healthy startup.
- Validate
https://<your-domain>/in browser. - Validate one deep route (for example
/about) to confirm SPA fallback.
Rollback SOP
- In Dokploy, open deployments history for
my-first-app-prod. - Redeploy last known healthy image/revision.
- Confirm site and deep-route health checks.
- Create a follow-up fix branch before next production deploy.
Pre-Deploy Checklist for This Repo
- Local
docker build -t my-astro-app:latest .succeeds - Local
docker run -p 8080:80 my-astro-app:latestserves correctly - Home route and one deep route load
- Domain points to Dokploy service
- SSL certificate is active
12. Quick Personalization Block (Fill Once)
Fill this section with your real values and keep it updated.
| Key | Your Value |
|---|---|
| Production app name | my-first-app-prod |
| Staging app name | my-first-app-staging |
| Production domain | <set-your-domain> |
| Staging domain | <set-your-staging-domain> |
| Git branch (prod) | main |
| Git branch (staging) | develop |
Tip: after filling this table, reuse these values in Dokploy settings to avoid drift.
13. Dokploy UI Walkthrough (With Screenshot Placeholders)
Use this as a visual checklist. Replace each placeholder with your own screenshot.
Step 1: Create or Open Application
- Go to Dokploy Dashboard -> Applications.
- Click Create Application (or open existing app).
- Select GitHub as source and choose
lussino/my-first-app.
Screenshot placeholder:
docs/screenshots/01-app-create.png
Step 2: Configure Source and Branch
- Set repository to
lussino/my-first-app. - Set branch to
mainfor production. - Enable auto deploy on push (recommended).
Screenshot placeholder:
docs/screenshots/02-source-branch.png
Step 3: Configure Docker Build
- Build type: Dockerfile.
- Dockerfile path:
Dockerfile. - Build context:
.
Screenshot placeholder:
docs/screenshots/03-docker-build.png
Step 4: Configure Runtime/Network
- Internal container port:
80. - Health check path:
/. - Save settings.
Screenshot placeholder:
docs/screenshots/04-runtime-port-health.png
Step 5: Domain and SSL
- Open Domains (or Routing) in Dokploy.
- Add production domain.
- Enable SSL certificate and wait for issuance.
Screenshot placeholder:
docs/screenshots/05-domain-ssl.png
Step 6: Deploy and Verify
- Click Deploy.
- Watch build logs until success.
- Open your domain and validate home + deep route.
Screenshot placeholder:
docs/screenshots/06-deploy-success.png
Step 7: Rollback Drill (Recommended)
- Open Deployment History.
- Identify last healthy deployment.
- Trigger redeploy for that revision.
Screenshot placeholder:
docs/screenshots/07-rollback.png
Optional Folder Convention for Screenshots
If you want to keep screenshots in this repo, use:
docs/
screenshots/
01-app-create.png
02-source-branch.png
03-docker-build.png
04-runtime-port-health.png
05-domain-ssl.png
06-deploy-success.png
07-rollback.png14. Verified Smoke Test (Executed)
This section records a real local verification run against the built Docker image.
Command Used
cid=$(docker run -d --rm -p 8080:80 my-astro-app:latest)
curl -sS -o /tmp/home.html -w "HOME_STATUS=%{http_code}\nHOME_CT=%{content_type}\n" http://localhost:8080/
curl -sS -o /tmp/deep.html -w "DEEP_STATUS=%{http_code}\nDEEP_CT=%{content_type}\n" http://localhost:8080/about
curl -sS -I http://localhost:8080/about
curl -sS -I http://localhost:8080/about/
docker stop "$cid"Observed Results
HOME_STATUS=200HOME_CT=text/htmlDEEP_STATUS=301Locationheader for/aboutredirected to/about//about/returnedHTTP/1.1 200 OK
Interpretation:
- Container is serving the Astro site correctly via Nginx.
- Deep route behavior is correct for trailing-slash canonicalization.
Note:
- A brief connection reset can happen immediately after container startup in fast local checks. Retrying the request resolves it once Nginx is fully ready.