Web Framework Guide

    Deploy Astro

    Build lightning-fast static and server-rendered websites with Astro's islands architecture. Deploy production-ready on RamNode's VPS hosting.

    Node.js 22 LTS
    Islands Architecture
    Nginx
    Let's Encrypt SSL
    1

    Prerequisites

    • A RamNode VPS running Ubuntu 24.04 LTS (recommended: 1 GB RAM minimum — available starting at $5/month)
    • SSH access to your VPS (terminal on macOS/Linux, or PuTTY/Windows Terminal on Windows)
    • A registered domain name (optional but recommended for SSL)
    • Basic familiarity with the Linux command line

    Recommended Plans

    Use CasePlanRAMBest For
    Static blog / portfolio$5/mo1 GBPersonal sites, landing pages
    SSR application$10/mo2 GBDynamic sites, API routes
    Multi-site hosting$15/mo3 GBMultiple Astro projects
    High-traffic SSR$20/mo+4 GB+E-commerce, dashboards
    2

    Initial Server Setup

    Connect and update system
    ssh root@YOUR_SERVER_IP
    
    # Update system packages
    apt update && apt upgrade -y

    Create a Deploy User

    Running applications as root is a security risk. Create a dedicated user for your Astro deployment:

    Create deploy user
    adduser astro
    usermod -aG sudo astro
    
    # Switch to the new user
    su - astro

    Configure the Firewall

    Enable UFW
    sudo ufw allow OpenSSH
    sudo ufw allow 'Nginx Full'
    sudo ufw enable
    sudo ufw status
    3

    Install Node.js

    Astro requires Node.js 18.17.1 or later. We recommend Node.js 22 LTS for the best performance and long-term support.

    Install Node.js 22 LTS
    curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
    sudo apt install -y nodejs
    
    # Verify the installation
    node -v
    npm -v
    4

    Create Your Astro Project

    Scaffold a new Astro project
    cd ~
    npm create astro@latest my-astro-site

    The CLI will prompt you with several options. For a production deployment, recommended selections are:

    • Template: Use the "Include sample files" starter for a working baseline
    • TypeScript: Choose "Strict" for type safety in production
    • Install dependencies: Yes
    • Initialize git: Yes
    Test the development server
    cd my-astro-site
    npm run dev -- --host 0.0.0.0
    
    # Visit http://YOUR_SERVER_IP:4321 to confirm
    # Press Ctrl+C to stop

    ⚠️ Warning: The --host 0.0.0.0 flag binds to all interfaces for remote access. Do not leave the dev server running in production — it is not optimized for security or performance.

    5

    Build for Production (Static)

    By default, Astro generates a fully static site. This is the recommended approach for blogs, documentation, portfolios, and marketing pages.

    Generate and preview the static build
    # Build for production
    npm run build
    
    # This compiles into optimized HTML, CSS, and JS in the dist/ directory
    
    # Preview the build locally
    npm run preview -- --host 0.0.0.0
    # Confirm everything renders at http://YOUR_SERVER_IP:4321
    # Press Ctrl+C once confirmed
    6

    Configure Nginx as Web Server

    Nginx serves your static Astro files with high performance and low memory overhead — ideal for a RamNode VPS.

    Install Nginx
    sudo apt install -y nginx
    sudo systemctl enable nginx
    sudo systemctl start nginx
    Create /etc/nginx/sites-available/astro
    server {
        listen 80;
        listen [::]:80;
        server_name your_domain.com www.your_domain.com;
    
        root /home/astro/my-astro-site/dist;
        index index.html;
    
        # Security headers
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    
        # Cache Astro's hashed assets aggressively
        location /_astro/ {
            expires 1y;
            add_header Cache-Control "public, immutable";
        }
    
        # Serve static files with fallback
        location / {
            try_files $uri $uri/ $uri.html =404;
        }
    
        # Gzip compression
        gzip on;
        gzip_types text/css application/javascript application/json image/svg+xml;
        gzip_min_length 256;
    
        error_page 404 /404.html;
    }
    Enable site and test config
    sudo ln -s /etc/nginx/sites-available/astro /etc/nginx/sites-enabled/
    sudo rm /etc/nginx/sites-enabled/default
    sudo nginx -t
    sudo systemctl reload nginx
    7

    Secure with SSL Using Let's Encrypt

    Install Certbot and obtain certificate
    sudo apt install -y certbot python3-certbot-nginx
    
    # Obtain and install the SSL certificate
    sudo certbot --nginx -d your_domain.com -d www.your_domain.com
    
    # Verify auto-renewal is configured
    sudo certbot renew --dry-run

    Certbot automatically modifies your Nginx configuration to handle HTTPS and redirect HTTP traffic. Certificates renew automatically via a systemd timer — no cron jobs needed.

    8

    Server-Side Rendering (Optional)

    If your project requires dynamic routes, API endpoints, or per-request rendering, configure Astro for SSR using the Node.js adapter.

    Install the Node.js Adapter

    Add the Node adapter
    npx astro add node

    Verify Configuration

    astro.config.mjs
    import { defineConfig } from 'astro/config';
    import node from '@astrojs/node';
    
    export default defineConfig({
      output: 'server',
      adapter: node({
        mode: 'standalone',
      }),
    });
    Build and test SSR
    npm run build
    node dist/server/entry.mjs
    # SSR server starts on port 4321 — confirm it responds
    # Press Ctrl+C to stop

    Create a systemd Service

    Manage the Astro SSR process with systemd for automatic startup and crash recovery:

    Create /etc/systemd/system/astro.service
    [Unit]
    Description=Astro SSR Application
    After=network.target
    
    [Service]
    Type=simple
    User=astro
    WorkingDirectory=/home/astro/my-astro-site
    ExecStart=/usr/bin/node dist/server/entry.mjs
    Restart=on-failure
    RestartSec=5
    Environment=HOST=127.0.0.1
    Environment=PORT=4321
    Environment=NODE_ENV=production
    
    [Install]
    WantedBy=multi-user.target
    Enable and start the service
    sudo systemctl daemon-reload
    sudo systemctl enable astro
    sudo systemctl start astro

    Update Nginx for SSR Reverse Proxy

    Replace your static Nginx config with a reverse proxy configuration:

    Update /etc/nginx/sites-available/astro
    server {
        listen 80;
        listen [::]:80;
        server_name your_domain.com www.your_domain.com;
    
        # Security headers
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    
        location / {
            proxy_pass http://127.0.0.1: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;
        }
    
        # Still cache Astro's hashed assets directly
        location /_astro/ {
            alias /home/astro/my-astro-site/dist/client/_astro/;
            expires 1y;
            add_header Cache-Control "public, immutable";
        }
    }
    Reload Nginx
    sudo nginx -t
    sudo systemctl reload nginx
    9

    Automated Deployments

    Create ~/deploy.sh
    #!/bin/bash
    set -e
    
    cd /home/astro/my-astro-site
    git pull origin main
    npm ci
    npm run build
    
    # For SSR deployments, restart the service:
    # sudo systemctl restart astro
    
    echo "Deployment complete!"
    Make executable and run
    chmod +x ~/deploy.sh
    
    # Run whenever you push updates
    ~/deploy.sh

    For fully automated CI/CD, add a GitHub Actions workflow that SSHs into your RamNode VPS and runs the deploy script on every push to main.

    10

    Performance Optimization

    Enable Brotli Compression

    Brotli provides better compression ratios than Gzip for text-based assets:

    Install and configure Brotli
    sudo apt install -y libnginx-mod-http-brotli-filter
    Add to /etc/nginx/nginx.conf http block
    brotli on;
    brotli_types text/plain text/css application/json
                 application/javascript text/xml application/xml
                 image/svg+xml;

    HTTP/2

    HTTP/2 is enabled automatically when you configure SSL with Certbot. If your site includes many assets, HTTP/2 multiplexing significantly reduces load times.

    Swap File for Low-Memory Plans

    On the $5/month plan with 1 GB RAM, add swap to prevent out-of-memory errors during builds:

    Add swap space
    sudo fallocate -l 1G /swapfile
    sudo chmod 600 /swapfile
    sudo mkswap /swapfile
    sudo swapon /swapfile
    echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
    11

    Monitoring & Maintenance

    Check service status and logs
    # Service status
    sudo systemctl status nginx
    sudo systemctl status astro      # If using SSR
    
    # Nginx access and error logs
    sudo tail -f /var/log/nginx/access.log
    sudo tail -f /var/log/nginx/error.log
    
    # Astro SSR service logs (if using SSR)
    sudo journalctl -u astro -f

    Automatic Security Updates

    Enable unattended upgrades
    sudo apt install -y unattended-upgrades
    sudo dpkg-reconfigure --priority=low unattended-upgrades
    12

    Troubleshooting

    Build fails with out-of-memory error

    Add a swap file (see Step 10) or upgrade to a plan with more RAM. Node.js builds can spike to 512 MB+ during compilation.

    Nginx returns 403 Forbidden

    Ensure the astro user's home directory and the dist/ folder have correct permissions: chmod 755 /home/astro && chmod -R 755 /home/astro/my-astro-site/dist

    Port 4321 not accessible externally

    Check UFW rules with sudo ufw status. The dev/preview server port is intentionally not exposed in production — use Nginx as your public-facing server.

    SSL certificate not renewing

    Run sudo certbot renew --dry-run to diagnose. Common causes include DNS misconfiguration or port 80 being blocked.

    SSR service crashes on startup

    Check logs with sudo journalctl -u astro -n 50. Common causes include missing environment variables or a failed npm run build.

    Astro Site Deployed Successfully!

    Your Astro site is now running in production on a RamNode VPS with Nginx, SSL encryption, and a deployment workflow. Astro's zero-JavaScript-by-default architecture combined with RamNode's SSD-backed infrastructure delivers near-instant page loads — starting at just $4/month.