Deploy your Astro.js Project on Mittwald Hosting

Sven BergendahlSven Bergendahl
3 min read

As you may have noticed, I recently switched my personal website from Hashnode to the Astro.js framework. Don't get me wrong - Hashnode is great, but Astro.js has captured my heart in a special way.

I've built several sites with Astro now, and as someone with minimal programming knowledge, this framework feels like a dream. It's always been my goal to build my own site with it, and now I finally did it.

In this guide, I'll show you exactly how I deploy my static Astro site to Mittwald, a German web hosting provider. Looking back at my journey, from my first steps with Netscape Composer, Microsoft FrontPage, and Namo WebEditor, I have used a ton of different hosting providers over the years. For fun, for work, for whatever reason. But somehow, I never tried Mittwald, even though they've been around forever. I think I first read about them in c't magazine around 2000? But could be wrong.

Mittwald is a German hosting company with a nice Interface and API-first approach that makes deployment simple. Through my wife, I got the chance to try their hosting service.

Prerequisites

For sure, you need a Mittwald account. I'm currently using a vServer from my wife. Once you're in mStudio, you should create a project for your website.

The Deployment Process

1. Create Static Web Apps (Preview and Production)

In your project create two apps - one for preview and one for production:

Production:

  • Inside your project, click "Apps"

  • Select "Anlegen"

  • Select "Static Files"

  • Name it "production-app"

Preview:

  • Same process, name it "preview-app"

2. Create Virtual Domains

Each app needs its own domain:

Production:

  • In your mStudio, go to "Domains"

  • Add your domain as virtual host (if you're using another provider for domains like me) or register a domain at Mittwald

Preview:

  • Same for preview app

  • Use a subdomain like preview.yourdomain.com

Mittwald shows you the IP addresses for DNS setup and verification. Change these accordingly to Mittwalds instructions at your provider (mine was Cloudflare).

3. Configure SSH Key(s) at Mittwald

  • mStudio → SSH/SFTP → SFTP-Benutzer → "Anlegen" → Add your public SSH key and optionally configure expiration date and restrict folder access

4. Set GitHub Secrets

Repository Settings > Secrets and variables > Actions

Secrets:

  • MITTWALD_DEPLOY_KEY (your SSH private key)

  • MITTWALD_USER (your SSH username)

  • MITTWALD_HOST (server's SSH hostname)

Variables:

  • MITTWALD_PRODUCTION_PATH (production app path)

  • MITTWALD_PREVIEW_PATH (preview app path)

5. Build GitHub Workflow

Create .github/workflows/deploy.yml:

name: Deploy to Mittwald

on:
  push:
    branches:
      - main
      - preview
  workflow_dispatch:

permissions:
  contents: read

jobs:
  build-and-deploy:
    runs-on: self-hosted

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Build Astro site
        run: npm run build

      - name: Set deployment path
        id: set-path
        run: |
          if [ "${{ github.ref_name }}" = "main" ]; then
            echo "DEPLOY_PATH=${{ vars.MITTWALD_PRODUCTION_PATH }}" >> $GITHUB_OUTPUT
          elif [ "${{ github.ref_name }}" = "preview" ]; then
            echo "DEPLOY_PATH=${{ vars.MITTWALD_PREVIEW_PATH }}" >> $GITHUB_OUTPUT
          else
            echo "Unknown branch: ${{ github.ref_name }}"
            exit 1
          fi

      - name: Setup SSH
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.MITTWALD_DEPLOY_KEY }}" > ~/.ssh/deploy_key
          chmod 600 ~/.ssh/deploy_key
          ssh-keyscan -H ${{ secrets.MITTWALD_HOST }} >> ~/.ssh/known_hosts 2>/dev/null || true

      - name: Deploy to Mittwald via SCP
        run: |
          echo "Deploying to: ${{ steps.set-path.outputs.DEPLOY_PATH }}"
          scp -i ~/.ssh/deploy_key -r dist/* ${{ secrets.MITTWALD_USER }}@${{ secrets.MITTWALD_HOST }}:${{ steps.set-path.outputs.DEPLOY_PATH }}

      - name: Clean up SSH key
        if: always()
        run: rm -f ~/.ssh/deploy_key

6. Deploy

Push to main for production, push to preview Branch for preview environment.

Done

That's it. No more FTP, no manual builds. Just code, commit, deploy.

0
Subscribe to my newsletter

Read articles from Sven Bergendahl directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Sven Bergendahl
Sven Bergendahl

Sr. Cloud Consultant with Azure expertise. Former NOC tech & sysadmin. Passionate about learning & providing great solutions.