Add new posts for Image Voice Memos, Initial VPS Setup on Debian, Local Webmention Avatars, Security Headers for Astro with Caddy, and Setting up Forgejo Actions Runner
- Created a new post on Image Voice Memos detailing a macOS app for browsing photos and recording voice memos with automatic transcription. - Added a guide for Initial VPS Setup on Debian covering system updates, user creation, and SSH hardening. - Introduced a post on caching webmention avatars locally at build time to enhance privacy and comply with CSP. - Documented the implementation of security headers for an Astro site behind Caddy, focusing on GDPR compliance and CSP. - Set up a Forgejo Actions runner for self-hosted CI/CD, detailing the installation and configuration process for automated deployments.
This commit is contained in:
parent
9d22d93361
commit
4bf4eb03b1
69 changed files with 4904 additions and 344 deletions
|
|
@ -0,0 +1,106 @@
|
|||
---
|
||||
title: Deploying Astro SSR to a VPS with Podman
|
||||
description: A practical VPS deployment flow for Astro SSR using Podman and podman-compose.
|
||||
pubDate: '2026-03-02T11:24:00+01:00'
|
||||
category: en/on-premises-private-cloud
|
||||
tags:
|
||||
- podman
|
||||
- deployment
|
||||
seriesParent: astro-ssr-with-podman
|
||||
seriesOrder: 2
|
||||
---
|
||||
|
||||
With the Astro SSR container running cleanly on my laptop, I wanted to move it onto the VPS without inventing a new set of commands for production. The goal was a short, boring deploy sequence — the same compose file, the same entry point, just a different host.
|
||||
|
||||
This is the exact path that worked on a fresh Debian VPS.
|
||||
|
||||
## The setup
|
||||
|
||||
- **VPS**: Debian, freshly provisioned, SSH access as a non-root user.
|
||||
- **Runtime**: Podman and `podman-compose` from the distro packages.
|
||||
- **Source of truth**: a Git repository cloned into `/opt/website`.
|
||||
|
||||
## Install runtime tools
|
||||
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install podman podman-compose git
|
||||
```
|
||||
|
||||
Nothing exotic — the distro packages are modern enough for a single-container app.
|
||||
|
||||
## Cloning the repository
|
||||
|
||||
**Problem:** My first `git clone` over HTTPS failed immediately with:
|
||||
|
||||
`Invalid username or token. Password authentication is not supported`
|
||||
|
||||
GitHub dropped password auth years ago, and the VPS had no credential helper configured. Rather than pasting a PAT onto the server, I switched to key-based SSH.
|
||||
|
||||
**Implementation:**
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.ssh && chmod 700 ~/.ssh
|
||||
ssh-keygen -t ed25519 -C "vps-website" -f ~/.ssh/id_ed25519 -N ""
|
||||
cat ~/.ssh/id_ed25519.pub
|
||||
```
|
||||
|
||||
That public key went into the repository's Deploy Keys — read-only, scoped to this one repo, nothing else.
|
||||
|
||||
```bash
|
||||
ssh-keyscan github.com >> ~/.ssh/known_hosts
|
||||
git clone git@github.com:adrian-altner/website.git /opt/website
|
||||
```
|
||||
|
||||
**Solution:** `git pull` now works unattended — no PAT expiry, no prompts, no shared account credentials on the box.
|
||||
|
||||
## Starting the app
|
||||
|
||||
```bash
|
||||
cd /opt/website
|
||||
podman-compose -f compose.yml up --build -d
|
||||
```
|
||||
|
||||
Three quick checks — the container is up, the logs show Astro booting, the local port answers:
|
||||
|
||||
```bash
|
||||
podman ps
|
||||
podman logs -f website
|
||||
curl -I http://127.0.0.1:4321
|
||||
```
|
||||
|
||||
A `200` from the last one means the app is healthy behind the scenes. It's still on localhost only — Caddy comes in a later post.
|
||||
|
||||
## The gotchas I hit
|
||||
|
||||
**Docker Hub auth errors on first build.** The initial pull can fail with:
|
||||
|
||||
`unable to retrieve auth token: invalid username/password`
|
||||
|
||||
Even with public images. Pulling the base image explicitly once clears whatever stale state Podman is carrying:
|
||||
|
||||
```bash
|
||||
podman pull docker.io/library/node:20-bookworm-slim
|
||||
```
|
||||
|
||||
After that, `podman-compose up --build -d` goes through cleanly.
|
||||
|
||||
**Compose provider warnings.** If Podman announces it's falling back to an external `docker-compose`, installing and pinning `podman-compose` takes the ambiguity out:
|
||||
|
||||
```bash
|
||||
sudo apt-get -y install podman-compose
|
||||
export PODMAN_COMPOSE_PROVIDER=/usr/bin/podman-compose
|
||||
```
|
||||
|
||||
From then on:
|
||||
|
||||
```bash
|
||||
podman compose -f compose.yml up --build -d
|
||||
```
|
||||
|
||||
## What to take away
|
||||
|
||||
- Key-based SSH with a Deploy Key beats HTTPS + PAT for unattended pulls — no expiry to manage.
|
||||
- The local `compose.yml` transfers to the VPS unchanged; that's the whole point.
|
||||
- A stale Podman auth cache is the most likely cause of mysterious first-pull failures — pull the base image directly once to reset it.
|
||||
- Pin `PODMAN_COMPOSE_PROVIDER` explicitly on servers so the command can't silently change behaviour under you.
|
||||
Loading…
Add table
Add a link
Reference in a new issue