# Scrivere Markdown in locale e fare deploy con git push: il mio workflow bilingue

> Canonical: https://vxi.me/it/posts/markdown-blog-publish-workflow/
> Locale: it-it
> Published: 2026-03-25
> Updated: 2026-03-25
> Markdown: https://vxi.me/it/posts/markdown-blog-publish-workflow.md

## Quale problema risolve questo articolo

Molti blog personali non si fermano perché il sito è difficile da costruire. Si fermano perché pubblicare diventa pesante. Ogni nuovo post significa toccare configurazioni, ricostruire manualmente, caricare file a mano e ripetere ancora gli stessi passaggi di deployment.

Volevo un workflow più leggero: scrivere Markdown in locale, fare push su GitHub e lasciare a GitHub Actions il compito di costruire e pubblicare automaticamente il sito. In questo modo la pubblicazione diventa un'abitudine ripetibile invece di una piccola attività operativa ogni volta.

## Quando questo setup è adatto

- Gestisci un blog personale, una pubblicazione tecnica o un sito leggero in stile documentazione
- Vuoi che i contenuti siano file Markdown versionati in Git
- Non vuoi WordPress o un backend CMS pesante
- Vuoi contenuti bilingui senza mantenere mapping manuali delle traduzioni

Se ti serve prima di tutto un backend editoriale visuale, un flusso di approvazione multi-autore o editing online, probabilmente questo non è il modello migliore.

## Risultato finale

Una volta configurato il workflow, pubblicare un nuovo post diventa:

1. Generare localmente lo scheletro bilingue
2. Modificare i file Markdown cinese e inglese
3. Fare preview del sito in locale
4. `git push origin main`
5. Lasciare che GitHub Actions distribuisca l'aggiornamento

Questa separazione conta. La scrittura rimane concentrata sui contenuti, mentre il deployment diventa automazione.

## Checklist dell'ambiente

Lo stack attuale dietro questo blog è:

- Framework: `Astro`
- Content layer: `astro:content`
- Formato contenuti: `Markdown`
- Modello di deployment: release di artifact statici
- Web server: `Nginx`
- CI/CD: `GitHub Actions`

I post vivono in una struttura bilingue:

```text
src/content/posts/zh-cn/*.md
src/content/posts/en-us/*.md
```

Ogni lingua ha il proprio file, ma entrambi condividono lo stesso `path`, quindi il sito genera:

- Cinese: `/posts/<path>/`
- Inglese: `/en/posts/<path>/`

## Istruzioni passo per passo

### 1. Blocca presto il modello dei contenuti

Se il content model continua a cambiare, ogni nuovo articolo diventa un'attività di codice invece che di scrittura.

In questo progetto, post, page, categorie e risorse vivono tutti in `astro:content`. La regola principale è:

- i post usano `path`
- page e categorie usano `key`

Quindi aggiungere un nuovo articolo dovrebbe richiedere solo nuovi file Markdown, non modifiche alla logica di routing.

### 2. Aggiungi un comando per lo scaffold del post

Copiare manualmente vecchi file funziona per un po', poi diventa inevitabilmente disordinato.

Ho aggiunto uno script semplice per generare un articolo così:

```bash
npm run new:post -- "markdown-blog-publish-workflow" "本地写 Markdown，git push 后自动上线：我的双语博客发布流程" "Write Markdown Locally, Deploy on git push: My Bilingual Blog Publishing Workflow" writing
```

Questo crea subito due file draft:

```text
src/content/posts/zh-cn/markdown-blog-publish-workflow.md
src/content/posts/en-us/markdown-blog-publish-workflow.md
```

Vengono creati con:

```yaml
draft: true
```

Questo default conta perché impedisce che contenuti incompleti vengano pubblicati automaticamente.

### 3. Mantieni il lavoro locale focalizzato su scrittura e preview

Mentre scrivo mi interessano solo due cose:

1. modificare Markdown
2. fare preview con `npm run dev`

I controlli locali sono semplici:

- il post compare in home
- entrambe le versioni linguistiche renderizzano correttamente
- categorie e tag aggregano bene
- titolo e description funzionano per SEO

Se questa fase è solida, non c'è un buon motivo per continuare a fare deploy SSH manuali.

### 4. Affida il deployment a GitHub Actions

Questa è la parte che rende il workflow sostenibile.

Il processo di produzione attuale è:

1. push su `main`
2. eseguire `npm ci`
3. eseguire `npm run build`
4. archiviare `dist`
5. caricare tramite SSH
6. estrarre in un nuovo `releases/<timestamp>-<sha>`
7. cambiare `current`
8. eseguire un controllo di disponibilità pubblica

A quel punto pubblicare un post non è più un'attività manuale di release. È normale CI/CD.

### 5. Lascia al server solo il compito di servire file statici

Un principio a cui tengo è semplice: il server dovrebbe servire, non costruire.

Questo porta diversi vantaggi immediati:

- meno componenti in produzione
- ambiente di build più coerente
- rollback più semplice
- debugging più chiaro in caso di fallimento

La struttura live è:

```text
/var/www/aitokenhacks.com/releases/<release-id>
/var/www/aitokenhacks.com/current
```

Ogni release è isolata e pubblicare equivale praticamente a cambiare un symlink.

### 6. Aggiungi diagnostica al workflow di deployment

L'automazione non è finita quando esiste il file YAML. Diventa utile solo quando gli errori sono facili da capire.

Per questo ho aggiunto diagnostica per cose come:

- quale deploy secret manca
- se l'accesso SSH funziona
- se le directory remote esistono
- verso quale release è stato spostato `current`

Così un deployment fallito non termina con un vago badge rosso. Puoi capire se il problema è GitHub Secrets, autenticazione SSH, permessi della directory o verifica pubblica.

## Problemi comuni

### Perché non usare semplicemente un backend online

Perché l'obiettivo principale del sito è accumulare contenuti e SEO, non la UX dell'editor.

I file Markdown gestiti in Git mi danno cose che considero più importanti:

- cronologia completa
- rollback
- modifiche revisionabili
- contenuti accanto al codice
- nessuna dipendenza da un pannello amministrativo di terze parti

### Perché non tenere entrambe le lingue nello stesso file

Perché un singolo file con frontmatter duplicato e body duplicato diventa rapidamente difficile da mantenere.

Due file con lo stesso `path` sono molto più puliti:

- si adattano naturalmente alle content collections di Astro
- il body resta facile da modificare
- non serve un ulteriore layer di mapping delle traduzioni

### Cosa fallisce più spesso nel deployment automatico

In pratica ho incontrato due classi ricorrenti di problemi:

- problemi di billing o quota di GitHub Actions, in cui il job non parte davvero
- deploy secret mancanti o errati, che fanno fallire immediatamente il setup SSH

Il mio ordine normale di debugging è quindi:

1. il workflow è davvero partito?
2. i deploy secret sono presenti?
3. utente e chiave SSH funzionano?
4. la directory remota permette la pubblicazione?

## Considerazione finale

Se stai costruendo un blog tecnico personale, consiglio fortemente di separare scrittura e meccanica di release.

Durante la scrittura, concentrati sulla qualità del post.
Per la pubblicazione, lascia i passaggi ripetitivi al CI/CD.

Quando il workflow diventa “scrivi Markdown in locale, poi `git push`”, il blog finalmente diventa qualcosa su cui puoi continuare a pubblicare con costanza.
