crystal-deploy

Shard Crystal pour le déploiement d'applications Kemal sur FreeBSD (style Capistrano)

= aloli-cr-deploy :toc: left :toc-title: Table des matières :toclevels: 3 :source-highlighter: rouge :icons: font

Shard Crystal pour le déploiement d'applications https://kemalcr.com[Kemal] sur serveurs FreeBSD. Style Capistrano : releases/, current/, shared/. Génère dynamiquement les scripts rc.d et nginx.conf.

== Fonctionnalités

  • Déploiement SSH depuis votre terminal local — aucune dépendance côté serveur
  • Structure Capistrano : releases/, current/, shared/
  • Génération dynamique du script rc.d FreeBSD (avec daemon(8) et redémarrage automatique)
  • Génération dynamique du nginx.conf (mode pkg FreeBSD ou Passenger dans /opt)
  • Dialogue interactif pour construire le .env lors de l'initialisation
  • Création automatique de l'utilisateur PostgreSQL et de la base de données
  • Création du CNAME OVH via l'API REST
  • Rollback en une commande
  • Conservation des N dernières releases (configurable)
  • Compilation Crystal dans une session tmux (résistante aux coupures SSH)
  • Génération automatique du workflow GitHub Actions (CI/CD) via generate-ci

== Installation

Ajoutez le shard dans votre shard.yml :

[source,yaml]

dependencies: aloli-cr-deploy: github: aloli/aloli-cr-deploy branch: developpement

Puis compilez le binaire deploy :

[source,sh]

shards install crystal build src/deploy.cr --release -o bin/deploy

Ajoutez bin/deploy à votre .gitignore si vous ne souhaitez pas versionner le binaire.

NOTE: Le binaire deploy doit être compilé dans votre projet (pas dans le shard). Il lit config/deploy.yml depuis le répertoire courant.

== Configuration

Copiez le fichier d'exemple dans votre projet :

[source,sh]

cp lib/aloli-cr-deploy/config/deploy.yml config/deploy.yml

Puis adaptez config/deploy.yml :

[source,yaml]

app_name: mon-app # <1> repo_url: git@github.com:aloli/mon-app.git crystal_main: src/mon_app.cr keep_releases: 10

environments: developpement: branch: developpement host: fiona.aloli.net user: deploy app_url: https://dev.mon-app.aloli.app dns_subdomain: dev.mon-app # <2> dns_target: fiona.aloli.net.

production: branch: production host: toby.aloli.net user: deploy app_url: https://mon-app.aloli.app

env_vars:

  • key: SESSION_SECRET label: "SESSION_SECRET" generate: hex32
  • key: APP_URL label: "APP_URL" default_from: app_url
  • key: DATABASE_URL label: "DATABASE_URL" build_from_pg: true
  • key: UNIX_SOCKET label: "UNIX_SOCKET" default_from: socket_path

ovh: dns_zone: aloli.app

<1> Utilisé pour nommer les répertoires, services et binaires : mon-app--developpement <2> Optionnel — nécessite un fichier config/.ovhrc avec les clés API OVH

== Utilisation

=== Génération du workflow GitHub Actions

[source,sh]

bin/deploy generate-ci

Cette commande génère .github/workflows/deploy.yml, un workflow complet qui :

. Lance les tests sur chaque push . Déploie automatiquement sur staging à chaque push sur la branche developpement . Déploie automatiquement sur production à chaque push sur la branche production

Le workflow utilise deux secrets GitHub à configurer dans les paramètres du dépôt :

[cols="1,3"] |=== | Secret | Description

| SSH_PRIVATE_KEY | Clé SSH privée pour se connecter au serveur de déploiement

| SSH_HOST | Adresse du serveur (ex: fiona.aloli.net) |===

=== Initialisation du serveur (une seule fois)

[source,sh]

bin/deploy init --developpement

Cette commande :

. Vérifie la connexion SSH . Propose un dialogue pour configurer le DNS OVH (optionnel) . Construit le fichier .env de façon interactive . Sur le serveur : crée l'utilisateur deploy, les répertoires, le .env, le nginx.conf

=== Déploiement

[source,sh]

bin/deploy deploy --developpement bin/deploy deploy --production

Chaque déploiement :

. Clone la branche dans releases/<timestamp>/ . Lie shared/.env et shared/log/ . Compile le binaire Crystal en mode --release (dans tmux si disponible) . Bascule le lien current vers la nouvelle release . Installe/met à jour le script rc.d . Démarre le service . Recharge NGINX . Supprime les anciennes releases (au-delà de keep_releases)

=== Rollback

[source,sh]

bin/deploy rollback --production

=== Statut

[source,sh]

bin/deploy status --developpement

== Structure sur le serveur

[source]

/home/mon-app--developpement/ ├── releases/ │ ├── 20260304_143022/ ← release horodatée │ │ ├── bin/mon-app--developpement │ │ └── ... │ └── 20260301_091500/ ├── current -> releases/20260304_143022/ └── shared/ ├── .env ← persistant entre les deploys ├── nginx.conf ← généré par init └── log/

/tmp/.mon-app--developpement.pid ← pidfile (convention /tmp comme PostgreSQL) /tmp/.mon-app--developpement.sock ← socket Unix (deploy:www 660)

/usr/local/etc/rc.d/mon-app--developpement /usr/local/bin/mon-app--developpement -> current/bin/...

== NGINX

Le fichier shared/nginx.conf est généré lors de l'init. Il est automatiquement lié selon le mode détecté :

[cols="1,2,2"] |=== | Mode | Lien créé | Directive à ajouter dans nginx.conf principal

| Passenger (/opt/websites/ présent) | /opt/websites/mon-app--developpement.conf | include /opt/websites/*.conf;

| pkg FreeBSD | sites-enabled/mon-app--developpement | include sites-enabled/*; |===

Le socket Unix est créé avec les permissions deploy:www 660 pour que NGINX (qui tourne sous l'utilisateur www) puisse y accéder.

== DNS OVH (optionnel)

Créez le fichier config/.ovhrc (non versionné, permissions 600) :

[source,sh]

OVH_APP_KEY=votre_app_key OVH_APP_SECRET=votre_app_secret OVH_CONSUMER_KEY=votre_consumer_key

=== Génération des clés OVH

Étape 1 — Créez l'application sur https://eu.api.ovh.com/createApp/

Étape 2 — Générez le Consumer Key :

[source,sh]

curl -X POST https://eu.api.ovh.com/1.0/auth/credential
-H 'Content-Type: application/json'
-H 'X-Ovh-Application: VOTRE_APP_KEY'
-d '{ "accessRules": [ {"method": "GET", "path": "/domain/zone/aloli.app"}, {"method": "GET", "path": "/domain/zone/aloli.app/record"}, {"method": "POST", "path": "/domain/zone/aloli.app/record"}, {"method": "POST", "path": "/domain/zone/aloli.app/refresh"} ], "redirection": "https://www.ovhcloud.com/fr/" }'

Ouvrez la validationUrl retournée dans votre navigateur pour valider.

== GitHub Actions (CI/CD automatique)

La commande generate-ci génère automatiquement le fichier de workflow adapté à votre configuration.

=== Étape 1 — Générer la clé SSH dédiée

[source,sh]

ssh-keygen -t ed25519 -C "github-actions-deploy" -f ~/.ssh/deploy_ed25519 -N ""

Autoriser la clé publique sur le serveur

ssh-copy-id -i ~/.ssh/deploy_ed25519.pub deploy@votre-serveur.net

=== Étape 2 — Configurer les secrets GitHub

Dans les paramètres du dépôt GitHub → Settings → Secrets and variables → Actions :

[cols="1,3"] |=== | Secret | Valeur

| SSH_PRIVATE_KEY | Contenu de ~/.ssh/deploy_ed25519 (clé privée)

| SSH_HOST | Adresse du serveur (ex: fiona.aloli.net) |===

=== Étape 3 — Générer le workflow

[source,sh]

bin/deploy generate-ci git add .github/workflows/deploy.yml git commit -m "ci: ajouter le workflow de déploiement automatique" git push

Le workflow généré déclenche automatiquement un déploiement à chaque push sur les branches developpement (staging) et production.

== Licence

MIT — voir link:LICENSE[LICENSE]

Repository

crystal-deploy

Owner
Statistic
  • 0
  • 0
  • 0
  • 0
  • 0
  • about 1 hour ago
  • March 4, 2026
License

MIT License

Links
Synced at

Tue, 10 Mar 2026 20:34:05 GMT

Languages