v0.3.1 - UI restyle, inklapbaar menu, taalmodule
Some checks failed
Deploy server-up (prod) / deploy (push) Successful in 6s
Build and push image / build (push) Has been cancelled

This commit is contained in:
bes-r 2026-06-02 23:25:30 +02:00
parent d866a13c20
commit 34edd95c9b
8 changed files with 1306 additions and 2 deletions

View file

@ -0,0 +1,47 @@
# Forgejo Actions — bouw + push image bij elke tag-push
#
# Activeert wanneer je `git push --tags` doet met een v*-tag.
# Bakt de tag in als SU_VERSION zodat het image z'n eigen versie kent.
#
# Vereisten in Forgejo:
# Settings → Variables → REGISTRY=git.example.com, OWNER=bes-r
# Settings → Secrets → PACKAGE_TOKEN=<token met write:package scope>
name: Build and push image
on:
push:
tags:
- "v*"
jobs:
build:
runs-on: docker
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Extract versie uit tag
id: tag
run: echo "v=${GITHUB_REF_NAME#v}" >> $GITHUB_OUTPUT
- name: Login op Forgejo registry
run: |
echo "${{ secrets.PACKAGE_TOKEN }}" \
| docker login ${{ vars.REGISTRY }} \
-u ${{ vars.OWNER }} \
--password-stdin
- name: Bouw image met versie ingebakken
run: |
docker build \
--build-arg SU_VERSION=${{ steps.tag.outputs.v }} \
-t ${{ vars.REGISTRY }}/${{ vars.OWNER }}/server-up:${{ steps.tag.outputs.v }} \
-t ${{ vars.REGISTRY }}/${{ vars.OWNER }}/server-up:latest \
.
- name: Push image
run: |
docker push ${{ vars.REGISTRY }}/${{ vars.OWNER }}/server-up:${{ steps.tag.outputs.v }}
docker push ${{ vars.REGISTRY }}/${{ vars.OWNER }}/server-up:latest

View file

@ -1,3 +1,26 @@
# v0.3.1 — UI-restyle + taalmodule (add-on)
## Nieuw in v0.3.1
### 🎨 Grondige UI-restyle
Grotere, touch-vriendelijke knoppen (min. 44px), ruimere spacing, grotere
typografie en kaarten. Layout gecentreerd met max-breedte voor meer lucht op
grote schermen. Volledig mobielvriendelijk.
### 📐 Inklapbaar menu (ook op desktop)
De hamburger klapt de sidebar nu ook op desktop in/uit; voorkeur wordt onthouden
(`localStorage`), hoofdinhoud en log-paneel schuiven mee. Op mobiel een
tap-to-close overlay.
### 🌐 Taalmodule als add-on
Nieuwe sectie in Instellingen → "Taalmodule": talen toevoegen, bewerken,
verwijderen en ingebouwde talen (NL/EN) dupliceren als startpunt. Editor toont
per sleutel de Engelse referentie met zoekfilter. Backend-endpoints:
`POST/DELETE /api/i18n`, `GET /api/i18n/keys`, `GET /api/i18n/<code>/raw`.
Toegevoegde talen komen als JSON in `translations/` en zijn direct beschikbaar.
---
# v0.3.01 — Boilerplates fixes + git-driven versioning # v0.3.01 — Boilerplates fixes + git-driven versioning
## Fixes bovenop v0.3.0 ## Fixes bovenop v0.3.0

View file

@ -0,0 +1,669 @@
# Forgejo Actions — deploy-pipeline opzetten voor Server Up
Volledig stappenplan om vanuit je laptop via Forgejo automatisch te deployen naar een Ubuntu/Debian server met Docker Compose. Inclusief een dev/prod-splitsing zodat je `dev`-server alleen de ontwikkelversie krijgt en prod-servers alleen stabiele releases.
## Al eerder opgezet? Lees dit eerst
Als je de pipeline al hebt ingericht en alleen de dev/prod-splitsing wilt toevoegen, hoef je niet alles opnieuw te doen. Voer alleen deze stappen uit:
1. **Runner opnieuw registreren met label `dev`** — zie [Stap 4b](#4b-registreren-op-de-app-server)
2. **`dev`-branch aanmaken** in je repo: `git checkout -b dev && git push -u origin dev`
3. **Workflow-bestanden bijwerken** — commit en push de gewijzigde `.forgejo/workflows/deploy.yml` en nieuwe `deploy-prod.yml` naar `dev`
4. **`/opt/server-up/.env`** aanmaken voor handmatige builds buiten de pipeline:
```bash
echo "SU_VERSION=dev-handmatig" > /opt/server-up/.env
```
---
## Architectuur
```
[ Laptop ]
|
| git push naar dev-branch
v
[ Forgejo VPS ] ──── dispatcht workflow ────> [ Dev-server ]
- act_runner (label: dev)
- Docker + Compose
- /opt/server-up/
[ Forgejo VPS ] ──── dispatcht workflow ────> [ Prod-server(s) ]
- act_runner (label: prod)
- Docker + Compose
- /opt/server-up/
```
Twee soorten servers:
- **Dev-server** — draait de `dev` branch. Wordt automatisch bijgewerkt bij elke push naar `dev`. Bedoeld voor testen.
- **Prod-server(s)** — draaien de `main` branch of een `v*`-tag. Worden alleen bijgewerkt als je bewust naar `main` merget of een release tagt.
De routing werkt via **runner-labels**: elke server registreert zijn runner met een eigen label (`dev` of `prod`). De workflow kiest op dat label. Zo pikt een dev-server nooit een prod-deploy op en andersom.
We draaien de runner in _host mode_: jobs draaien direct op de host, niet in een container. Dat is voor deploy-jobs verreweg het simpelst — Docker socket en bind-mount paden kloppen vanzelf.
---
## Wat je nodig hebt
- Forgejo VPS met root- of admin-toegang
- App-server (Ubuntu 22.04/24.04 of Debian 12) met root- of sudo-toegang
- DNS-naam voor je Forgejo-instance (bv. `forgejo.example.com`) met geldig TLS-certificaat
- Server Up uitgecheckt lokaal, met `Dockerfile` en `docker-compose.yml`
---
## Stap 1 — Actions globaal aanzetten in Forgejo
Forgejo heeft **geen UI-toggle** voor Actions. Je zet het aan in `app.ini`. Zolang het uit staat zie je geen **Actions**-tab in repo's.
### 1a. Snelle check: staat het al aan?
Open een willekeurige repo in Forgejo. Zie je bovenaan een **Actions**-tab? Dan is het al aan — ga door naar stap 1d.
### 1b. `app.ini` vinden
SSH naar je Forgejo VPS:
```bash
# Zoek de containernaam
docker ps --format 'table {{.Names}}\t{{.Image}}' | grep -i forgejo
# Bekijk huidige Actions-config
docker exec forgejo cat /data/gitea/conf/app.ini | grep -A2 "\[actions\]" \
|| echo "Geen [actions] blok gevonden"
# Vind het hostpad van de data-map
docker inspect forgejo --format \
'{{ range .Mounts }}{{ .Source }} -> {{ .Destination }}{{ "\n" }}{{ end }}'
```
Zoek de regel waar `Destination` `/data` is. Het bestand staat dan op `<Source>/gitea/conf/app.ini`. Typische plekken:
- `/var/lib/forgejo/gitea/conf/app.ini`
- `./forgejo/gitea/conf/app.ini` (relatief aan je `docker-compose.yml`)
- Bij een named volume: `/var/lib/docker/volumes/<naam>/_data/gitea/conf/app.ini`
### 1c. `app.ini` aanpassen en Forgejo herstarten
```bash
APP_INI=/var/lib/forgejo/gitea/conf/app.ini # pas aan naar jouw pad
sudo cp "$APP_INI" "$APP_INI.bak"
sudo nano "$APP_INI"
```
Voeg onderaan toe — of update het bestaande `[actions]`-blok:
```ini
[actions]
ENABLED = true
DEFAULT_ACTIONS_URL = https://code.forgejo.org
```
Herstart Forgejo:
```bash
docker compose restart forgejo # in de map waar je docker-compose.yml staat
# of zonder compose:
docker restart forgejo
```
Refresh een repo-pagina — de **Actions**-tab moet nu zichtbaar zijn.
### 1d. Repo-Actions inschakelen
Ga in je repo naar **Settings → Actions → General → Enable Repository Actions** (dit is standaard aan zodra Actions globaal aan staan).
---
## Stap 2 — App-server voorbereiden
SSH naar de app-server als root of met `sudo`.
### 2a. Systeem up-to-date
```bash
apt update && apt upgrade -y
apt install -y curl ca-certificates gnupg git rsync ufw
```
### 2b. Docker + Compose plugin installeren
```bash
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | \
gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
# Voor Ubuntu vervang 'debian' door 'ubuntu'
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/debian $(. /etc/os-release && echo $VERSION_CODENAME) stable" \
> /etc/apt/sources.list.d/docker.list
apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
systemctl enable --now docker
docker --version && docker compose version
```
### 2c. Deploy-user aanmaken
```bash
useradd -m -s /bin/bash deploy
usermod -aG docker deploy
mkdir -p /opt/server-up
chown deploy:deploy /opt/server-up
```
De runner draait als `deploy`. Door deze user in de `docker`-groep te zetten kan hij `docker compose` zonder sudo aanroepen.
### 2d. Firewall (optioneel maar aanbevolen)
```bash
ufw default deny incoming
ufw default allow outgoing
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
```
De runner heeft alleen _uitgaande_ HTTPS naar je Forgejo nodig — geen inkomende poort.
---
## Stap 3 — Act_runner installeren
Forgejo gebruikt `act_runner` als runner-daemon.
```bash
# Controleer de nieuwste versie op:
# https://code.forgejo.org/forgejo/act_runner/releases
VERSION=6.2.2
ARCH=amd64 # of arm64 voor ARM-servers
curl -fsSL -o /usr/local/bin/act_runner \
"https://code.forgejo.org/forgejo/runner/releases/download/v${VERSION}/forgejo-runner-${VERSION}-linux-${ARCH}"
chmod +x /usr/local/bin/act_runner
act_runner --version
```
### Werkdirectory en config
```bash
mkdir -p /etc/act_runner /var/lib/act_runner
chown deploy:deploy /var/lib/act_runner
act_runner generate-config > /etc/act_runner/config.yaml
chown root:deploy /etc/act_runner/config.yaml
chmod 640 /etc/act_runner/config.yaml
```
Open `/etc/act_runner/config.yaml` en pas deze velden aan:
```yaml
runner:
file: /var/lib/act_runner/.runner
capacity: 1
timeout: 30m
insecure: false
fetch_timeout: 5s
fetch_interval: 2s
cache:
enabled: true
dir: /var/lib/act_runner/cache
host:
workdir_parent: /var/lib/act_runner/host-work
```
---
## Stap 4 — Runner registreren
### 4a. Token ophalen uit Forgejo
Ga in Forgejo naar je repo → **Settings → Actions → Runners → Create new Runner**. Kopieer het token.
Kies het niveau dat bij je gebruik past:
- **Repo-niveau** (alleen deze repo) — veiligst
- **Organization-niveau** — handig als je meerdere repo's hebt
- **Site-niveau** — alleen als je veel repo's wilt deployen
### 4b. Registreren op de app-server
**Dev-server** — registreer met label `dev`:
```bash
sudo -u deploy bash -c '
cd /var/lib/act_runner && \
act_runner register \
--no-interactive \
--instance https://jouw-forgejo-url \
--token JOUW_TOKEN \
--name dev-server \
--labels self-hosted,dev \
--config /etc/act_runner/config.yaml
'
```
**Prod-server** — registreer met label `prod`:
```bash
sudo -u deploy bash -c '
cd /var/lib/act_runner && \
act_runner register \
--no-interactive \
--instance https://jouw-forgejo-url \
--token JOUW_TOKEN \
--name prod-server-1 \
--labels self-hosted,prod \
--config /etc/act_runner/config.yaml
'
```
> **Al geregistreerd met andere labels?** Stop de service, verwijder het `.runner`-bestand en registreer opnieuw:
> ```bash
> systemctl stop act_runner
> rm /var/lib/act_runner/.runner
> # voer daarna bovenstaand register-commando uit
> ```
Controleer in Forgejo onder **Settings → Actions → Runners** — je runner staat als **Idle**.
---
## Stap 5 — Runner als systemd-service instellen
Doe dit op elke server na de registratie:
```bash
cat > /etc/systemd/system/act_runner.service << 'EOF'
[Unit]
Description=Forgejo Actions runner
After=network-online.target docker.service
Wants=network-online.target
[Service]
Type=simple
User=deploy
Group=deploy
WorkingDirectory=/var/lib/act_runner
ExecStart=/usr/local/bin/act_runner daemon --config /etc/act_runner/config.yaml
Restart=on-failure
RestartSec=5s
NoNewPrivileges=true
ProtectSystem=full
ProtectHome=read-only
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now act_runner
systemctl status act_runner
```
Logs volgen:
```bash
journalctl -u act_runner -f
```
---
## Stap 6 — Branches inrichten
De workflows zijn opgezet rond twee branches:
| Branch | Doel | Deploy naar |
|--------|------|-------------|
| `dev` | Ontwikkeling, testen | Dev-server |
| `main` | Stabiele releases | Prod-server(s) |
Maak de `dev`-branch aan als die er nog niet is:
```bash
git checkout -b dev
git push -u origin dev
```
Typische werkwijze:
```
feature-branch → merge naar dev → automatisch op dev-server getest
dev → stabiel → merge naar main → automatisch op prod-server(s)
main → git tag v1.2.3 → deploy met versienummer ingebakken
```
---
## Stap 7 — Workflow-bestanden
De repo bevat twee deploy-workflows in `.forgejo/workflows/`:
### `deploy.yml` — dev-server
Triggert bij elke push naar `dev`. Draait alleen op runners met label `dev`.
```yaml
name: Deploy server-up (dev)
on:
push:
branches: [dev]
workflow_dispatch:
concurrency:
group: server-up-deploy-dev
cancel-in-progress: false
jobs:
deploy:
runs-on: [self-hosted, dev]
timeout-minutes: 20
env:
DEPLOY_DIR: /opt/server-up
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Bepaal versie
id: version
run: |
set -euo pipefail
VERSION="dev-${GITHUB_SHA:0:8}"
echo "VERSION=${VERSION}" >> "$GITHUB_ENV"
echo "SU_VERSION=${VERSION}" >> "$GITHUB_ENV"
echo "CHANNEL=dev" >> "$GITHUB_ENV"
echo "Deploying version: ${VERSION}"
- name: Sync code naar deploy-directory
run: |
set -euo pipefail
rsync -a --delete \
--exclude='.git/' \
--exclude='.forgejo/' \
./ "$DEPLOY_DIR/"
- name: Schrijf VERSION-bestand
working-directory: ${{ env.DEPLOY_DIR }}
run: echo "${VERSION}" > VERSION
- name: Build image
working-directory: ${{ env.DEPLOY_DIR }}
run: |
docker compose build --pull
docker tag "server-up:${VERSION}" server-up:latest
docker tag "server-up:${VERSION}" server-up:dev
- name: Deploy
working-directory: ${{ env.DEPLOY_DIR }}
run: |
set -euo pipefail
docker compose up -d --remove-orphans
docker compose ps
- name: Wachten op healthcheck
run: |
set -euo pipefail
for i in {1..40}; do
status=$(docker inspect --format '{{.State.Health.Status}}' server-up 2>/dev/null || echo "starting")
echo "poll $i: $status"
if [ "$status" = "healthy" ]; then
echo "server-up is healthy als versie ${VERSION}"
exit 0
fi
sleep 3
done
echo "server-up werd niet healthy in tijd — logs:"
cd "$DEPLOY_DIR" && docker compose logs --tail=200
exit 1
- name: Oude images opruimen (behoud laatste 5)
if: success()
run: |
docker images server-up --format '{{.Tag}} {{.ID}}' \
| grep -vE '^(latest|release|dev) ' \
| tail -n +6 \
| awk '{print $2}' \
| xargs -r docker rmi -f || true
docker image prune -f
```
### `deploy-prod.yml` — prod-servers
Triggert bij push naar `main` of een `v*`-tag. Draait alleen op runners met label `prod`.
```yaml
name: Deploy server-up (prod)
on:
push:
branches: [main]
tags: ['v*']
workflow_dispatch:
concurrency:
group: server-up-deploy-prod
cancel-in-progress: false
jobs:
deploy:
runs-on: [self-hosted, prod]
timeout-minutes: 20
env:
DEPLOY_DIR: /opt/server-up
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Bepaal versie
id: version
run: |
set -euo pipefail
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
VERSION="${GITHUB_REF_NAME}"
CHANNEL="release"
else
VERSION="main-${GITHUB_SHA:0:8}"
CHANNEL="main"
fi
echo "VERSION=${VERSION}" >> "$GITHUB_ENV"
echo "CHANNEL=${CHANNEL}" >> "$GITHUB_ENV"
echo "SU_VERSION=${VERSION}" >> "$GITHUB_ENV"
echo "Deploying version: ${VERSION} (${CHANNEL})"
- name: Sync code naar deploy-directory
run: |
set -euo pipefail
rsync -a --delete \
--exclude='.git/' \
--exclude='.forgejo/' \
./ "$DEPLOY_DIR/"
- name: Schrijf VERSION-bestand
working-directory: ${{ env.DEPLOY_DIR }}
run: echo "${VERSION}" > VERSION
- name: Build image
working-directory: ${{ env.DEPLOY_DIR }}
run: |
docker compose build --pull
docker tag "server-up:${VERSION}" server-up:latest
docker tag "server-up:${VERSION}" "server-up:${CHANNEL}"
- name: Deploy
working-directory: ${{ env.DEPLOY_DIR }}
run: |
set -euo pipefail
docker compose up -d --remove-orphans
docker compose ps
- name: Wachten op healthcheck
run: |
set -euo pipefail
for i in {1..40}; do
status=$(docker inspect --format '{{.State.Health.Status}}' server-up 2>/dev/null || echo "starting")
echo "poll $i: $status"
if [ "$status" = "healthy" ]; then
echo "server-up is healthy als versie ${VERSION}"
exit 0
fi
sleep 3
done
echo "server-up werd niet healthy in tijd — logs:"
cd "$DEPLOY_DIR" && docker compose logs --tail=200
exit 1
- name: Oude images opruimen (behoud laatste 5)
if: success()
run: |
docker images server-up --format '{{.Tag}} {{.ID}}' \
| grep -vE '^(latest|release|main) ' \
| tail -n +6 \
| awk '{print $2}' \
| xargs -r docker rmi -f || true
docker image prune -f
```
### Wat doet een deploy-workflow?
1. Code uitchecken in de runner-workspace
2. Versienummer bepalen (`dev-<sha>` voor dev, `v1.2.3` voor tags)
3. Code naar `/opt/server-up` synchen via `rsync --delete`
4. Docker-image bouwen met `docker compose build --pull` en `SU_VERSION` ingebakken
5. Container herstarten met `docker compose up -d`
6. Wachten tot de healthcheck groen is (max. ~2 minuten)
7. Oude images opruimen (behoudt de laatste 5)
---
## Stap 8 — Handmatig triggeren
Elke workflow heeft `workflow_dispatch`, waarmee je hem handmatig start zonder een commit:
**Forgejo UI**: Actions → selecteer de workflow → **Run workflow**
Handig als je de pipeline opnieuw wilt draaien na een serverherstel of configuratiewijziging.
---
## Stap 9 — Eerste deploy testen
Vanuit je repo op je laptop:
```bash
git checkout dev
echo "# Deploy test $(date)" >> README.md
git add README.md
git commit -m "ci: trigger first deploy"
git push origin dev
```
In Forgejo: ga naar de **Actions**-tab van je repo. Je ziet de workflow-run starten. Klik erop om de logs live te volgen.
Op de server parallel meekijken:
```bash
journalctl -u act_runner -f
# in een tweede shell:
docker logs -f server-up
```
Als alles goed gaat: groen vinkje, container draait nieuwe image.
---
## Stap 10 — Rollback
Omdat images getagd worden met de git SHA is rollback eenvoudig:
```bash
cd /opt/server-up
# Beschikbare images bekijken
docker images server-up --format '{{.Tag}}\t{{.CreatedAt}}'
# Rollback naar een eerdere SHA — pas aan
SU_VERSION=dev-abcdef12 docker compose up -d
```
Voor extra zekerheid kun je in de workflow de huidige tag wegschrijven vóór de deploy:
```bash
echo "$(docker inspect server-up --format '{{.Config.Image}}')" \
> /opt/server-up/.last-good-image
```
---
## Stap 11 — Uitbreidingen
### CI vóór deploy (tests, lint)
Splits in twee jobs zodat tests in isolatie draaien en de deploy alleen bij groen start:
```yaml
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: docker build --target build -t server-up:test .
# voeg je eigen testcommando's toe
deploy:
needs: test
runs-on: [self-hosted, dev]
steps:
# ... zoals hierboven
```
### Nieuwe prod-server toevoegen
1. Installeer `act_runner` op de nieuwe server (stap 3)
2. Maak een nieuw runner-token aan in Forgejo
3. Registreer met `--labels self-hosted,prod` (stap 4b)
4. Stel de systemd-service in (stap 5)
De `deploy-prod.yml` workflow pikt de nieuwe runner automatisch op bij de volgende push naar `main` of een tag.
### Image registry
Voor grotere setups wil je niet op de productieserver bouwen. Push de image naar de Forgejo Container Registry (ingebouwd onder **Packages**) vanuit een aparte build-job, en trek alleen op de app-server. Scheelt CPU en disk op productie.
---
## Beveiligingstips
- **Runner draait niet als root** — de `deploy`-user heeft alleen rechten op `/opt/server-up` en is lid van de `docker`-groep. Het Server Up-container zelf draait als root (`user: "0:0"` in compose), dat is een bewuste keuze voor Docker socket-toegang.
- **Repo-niveau token** is veiliger dan site-niveau — bij een lek heeft een aanvaller niet meteen toegang tot alle repo's.
- **Branch protection op `main`** — Repo → Settings → Branches → Add Rule. Vereis dat pushes via een PR gaan en de dev-pipeline groen is.
- **Secrets nooit in compose of git** — zet gevoelige waarden in Forgejo Secrets en schrijf ze in de workflow-step naar `.env`.
- **Runner-binary updaten** — periodiek bijwerken: nieuwe versie naar `/usr/local/bin/act_runner` schrijven en `systemctl restart act_runner`. Geen herregistratie nodig.
- **Forgejo zelf** — zet 2FA aan, draai achter een reverse proxy met TLS, configureer fail2ban op de SSH-poort.
---
## Problemen oplossen
| Symptoom | Oorzaak / oplossing |
|----------|---------------------|
| Workflow blijft "queued" hangen | Geen runner met het juiste label online. Check `systemctl status act_runner` en of het label (`dev`/`prod`) overeenkomt met `runs-on` in de workflow. |
| `permission denied` bij Docker | `deploy`-user niet in `docker`-groep, of service gestart vóór die toevoeging — `systemctl restart act_runner`. |
| `rsync: not found` | `apt install rsync` op de server. |
| `SU_VERSION ontbreekt` bij handmatige build | Maak `/opt/server-up/.env` aan: `echo "SU_VERSION=dev-handmatig" > /opt/server-up/.env` |
| Container draait oude code na rebuild | Deploy-directory niet bijgewerkt. Controleer: `docker exec --workdir /app server-up grep -n "trim_blocks" core/boilerplates.py`. Als dit `True` toont, trigger de pipeline handmatig of sync de code zelf: `rsync -a --delete --exclude='.git/' --exclude='.forgejo/' ./ /opt/server-up/` |
| Boilerplate geeft `yaml: line 5` fout | Zelfde oorzaak als boven — `trim_blocks=True` in de draaiende container. Fix: rebuild na correcte sync. Eerder geïnstalleerde stacks met kapotte compose-bestanden opnieuw installeren via de app-store. |
| Healthcheck-step faalt altijd | Check `docker compose logs`. Vaak ontbreekt een env-var of klopt een pad niet. |
| TLS-fout bij registreren | Zet `runner.insecure: true` in config alleen tijdelijk voor self-signed certs. Een geldig certificaat (Let's Encrypt) is de structurele oplossing. |

389
docs/synchroniseren.md Normal file
View file

@ -0,0 +1,389 @@
# Code synchroniseren via Forgejo
Dit is hoe je code van je eigen apparaat automatisch op een server krijgt via Forgejo. Je pusht naar een branch, en de server haalt de wijzigingen zelf op en herstart de applicatie. Je hoeft nooit handmatig in te loggen op de server om iets bij te werken.
Als voorbeeld gebruik ik Server Up, maar de werkwijze is voor elke applicatie hetzelfde.
---
## Hoe het werkt
Je werkt met twee branches in je repository:
| Branch | Doel | Wat er gebeurt bij een push |
|--------|------|-----------------------------|
| `dev` | Testen en ontwikkelen | De dev-server wordt automatisch bijgewerkt |
| `main` | Stabiele versie voor eindgebruikers | De prod-server wordt automatisch bijgewerkt |
Jij pusht code naar Forgejo. Forgejo start automatisch een workflow (een reeks stappen). Die workflow draait op de server zelf via een kleine achtergrondservice genaamd `act_runner`. De server haalt de code op, bouwt een nieuw Docker-image en herstart de applicatie.
---
## Stap 1 — Git installeren op je eigen apparaat
Git heb je nodig om code te beheren en naar Forgejo te pushen.
Download en installeer Git via [git-scm.com](https://git-scm.com). Tijdens de installatie kun je alle standaardinstellingen accepteren.
Controleer daarna of het werkt:
```bash
git --version
```
---
## Stap 2 — Pakketten installeren op de server
Log in op de server als root of met `sudo`. Installeer de benodigde pakketten:
```bash
apt update
apt install -y git rsync nodejs
```
Toelichting:
- **git** — de pipeline checkt de repository uit op de server
- **rsync** — kopieert de bestanden naar de juiste map op de server
- **nodejs** — vereist door `actions/checkout`, de stap die de code ophaalt
---
## Stap 3 — Docker installeren op de server
Docker is nodig om de applicatie te draaien en te bouwen.
```bash
apt install -y ca-certificates curl gnupg
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | \
gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/debian $(. /etc/os-release && echo $VERSION_CODENAME) stable" \
> /etc/apt/sources.list.d/docker.list
apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
systemctl enable --now docker
```
Controleer of Docker werkt:
```bash
docker --version
docker compose version
```
> Draai je Ubuntu in plaats van Debian? Vervang beide keren `debian` door `ubuntu` in bovenstaande commando's.
---
## Stap 4 — Runner-gebruiker aanmaken op de server
De pipeline draait niet als root maar als een aparte gebruiker. Maak die aan en geef hem toegang tot Docker:
```bash
useradd -m -s /bin/bash git-user
usermod -aG docker git-user
```
Controleer of het gelukt is:
```bash
groups git-user
```
Je ziet `git-user docker` in de uitvoer.
---
## Stap 5 — Act_runner installeren op de server
`act_runner` is de achtergrondservice die de Forgejo-workflows uitvoert.
```bash
VERSION=6.2.2
ARCH=amd64 # gebruik arm64 voor ARM-servers
curl -fsSL -o /usr/local/bin/act_runner \
"https://code.forgejo.org/forgejo/runner/releases/download/v${VERSION}/forgejo-runner-${VERSION}-linux-${ARCH}"
chmod +x /usr/local/bin/act_runner
act_runner --version
```
Maak de benodigde mappen aan:
```bash
mkdir -p /etc/act_runner /var/lib/act_runner
chown git-user:git-user /var/lib/act_runner
act_runner generate-config > /etc/act_runner/config.yaml
chown root:git-user /etc/act_runner/config.yaml
chmod 640 /etc/act_runner/config.yaml
```
---
## Stap 6 — Runner registreren in Forgejo
### Token ophalen
Ga in Forgejo naar je repository → **Settings → Actions → Runners → Create new Runner**. Kopieer het token.
### Registreren
**Voor een dev-server:**
```bash
sudo -u git-user bash -c '
cd /var/lib/act_runner && \
act_runner register \
--no-interactive \
--instance https://jouw-forgejo-url \
--token JOUW_TOKEN \
--name dev-server \
--labels self-hosted,dev \
--config /etc/act_runner/config.yaml
'
```
**Voor een prod-server:**
```bash
sudo -u git-user bash -c '
cd /var/lib/act_runner && \
act_runner register \
--no-interactive \
--instance https://jouw-forgejo-url \
--token JOUW_TOKEN \
--name prod-server \
--labels self-hosted,prod \
--config /etc/act_runner/config.yaml
'
```
Controleer in Forgejo onder **Settings → Actions → Runners** — de runner verschijnt als **Idle**.
---
## Stap 7 — Runner instellen als achtergrondservice
Zodat de runner automatisch start bij een herstart van de server:
```bash
cat > /etc/systemd/system/act_runner.service << 'EOF'
[Unit]
Description=Forgejo Actions runner
After=network-online.target docker.service
Wants=network-online.target
[Service]
Type=simple
User=git-user
Group=git-user
WorkingDirectory=/var/lib/act_runner
ExecStart=/usr/local/bin/act_runner daemon --config /etc/act_runner/config.yaml
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now act_runner
systemctl status act_runner
```
De runner is nu actief en start automatisch opnieuw na een herstart.
---
## Stap 8 — Deploy-map aanmaken op de server
De pipeline kopieert de code naar een vaste map. Maak die eenmalig aan:
```bash
mkdir -p /opt/docker/server-up
chown git-user:git-user /opt/docker/server-up
```
---
## Stap 9 — Repository klonen op je eigen apparaat
Als je de repository nog niet lokaal hebt staan:
```bash
git clone https://jouw-forgejo-url/gebruiker/server-up.git
cd server-up
```
---
## Stap 10 — Dev-branch aanmaken
Doe dit één keer. Als de branch al bestaat, sla je deze stap over.
```bash
git checkout -b dev
git push -u origin dev
```
De pipeline voor de dev-server is nu gekoppeld aan deze branch.
---
## Dagelijks gebruik: wijzigingen naar de dev-server sturen
Dit doe je elke keer als je iets hebt aangepast en wilt testen.
```bash
# Zorg dat je op de dev-branch zit
git checkout dev
# Voeg je gewijzigde bestanden toe
git add .
# Maak een commit met een korte omschrijving
git commit -m "Omschrijving van je wijziging"
# Push naar Forgejo
git push origin dev
```
De pipeline start automatisch. Binnen een paar minuten draait de dev-server de nieuwe versie.
---
## Controleren of de pipeline gelukt is
Ga in Forgejo naar je repository en klik op **Actions**. Je ziet de pipeline-run staan:
- **Groen vinkje** — gelukt, de server draait de nieuwe versie
- **Rood kruis** — er is iets misgegaan, klik erop om de logs te zien
Je kunt ook direct op de server controleren:
```bash
docker inspect --format '{{.State.Health.Status}}' server-up
```
`healthy` betekent dat alles goed draait.
---
## Stabiele versie naar de prod-server sturen
Doe dit alleen als de versie op dev goed werkt.
```bash
# Schakel over naar main
git checkout main
# Haal de laatste versie van main op
git pull origin main
# Voeg alles uit dev samen met main
git merge dev
# Push naar Forgejo
git push origin main
```
De prod-server wordt automatisch bijgewerkt.
---
## Een versienummer vastleggen (optioneel)
Wil je een officieel versienummer aan een release hangen:
```bash
git checkout main
git tag v1.2.3
git push origin v1.2.3
```
Het versienummer `v1.2.3` wordt ingebakken in het Docker-image en is zichtbaar in de applicatie.
---
## Pipeline handmatig opnieuw starten
Wil je de pipeline herhalen zonder iets te wijzigen:
1. Ga naar je repository → **Actions**
2. Klik op de workflow die je wilt starten
3. Klik rechtsboven op **Run workflow**
---
## Iets terugdraaien
Elk gebouwd image krijgt een versietag mee. Je kunt altijd terug:
```bash
# Bekijk beschikbare versies
docker images server-up --format '{{.Tag}}\t{{.CreatedAt}}'
# Start de container met een eerdere versie
cd /opt/docker/server-up
SU_VERSION=dev-abcdef12 docker compose up -d
```
Vervang `dev-abcdef12` door de versietag die je terug wilt zetten.
---
## Problemen oplossen
**De pipeline start niet**
Ga in Forgejo naar **Settings → Actions → Runners**. Als de runner offline is, log dan in op de server en voer uit:
```bash
systemctl start act_runner
systemctl status act_runner
```
**Fout: `rsync: command not found`**
```bash
apt install -y rsync
```
**Fout: `Cannot find node in PATH`**
```bash
apt install -y nodejs
```
**Fout: `permission denied` bij rsync**
De runner-gebruiker heeft geen schrijfrechten op de deploy-map:
```bash
chown -R git-user:git-user /opt/docker/server-up
```
**Fout: `usermod: command not found`**
Je bent niet ingelogd als root. Zet `sudo` voor het commando:
```bash
sudo usermod -aG docker git-user
```
**Fout: `No such image` bij docker tag**
Docker Compose bouwt het image als `latest`. De workflow moet `latest` taggen als de versie, niet andersom. Controleer de build-stap in `.forgejo/workflows/deploy.yml` — die moet er zo uitzien:
```yaml
docker compose build --pull
docker tag server-up:latest "server-up:${VERSION}"
docker tag server-up:latest "server-up:${CHANNEL}"
```
**Je staat op de verkeerde branch**
```bash
git branch # toont welke branch actief is
git checkout dev # wissel naar dev
git checkout main # wissel naar main
```
**Bestanden worden niet meegenomen**
```bash
git status # toont welke bestanden nog niet zijn toegevoegd
git add . # voeg alles toe
```

47
fix-config.sh Normal file
View file

@ -0,0 +1,47 @@
#!/bin/bash
# Repareer de APP_REPOS in de Server Up config:
# - Verwijdert dubbele entries
# - Geeft de Forgejo dev-repo een uniek id (bes-r-dev)
set -euo pipefail
docker exec server-up python3 -c "
import json
from pathlib import Path
p = Path('/data/config.json')
cfg = json.loads(p.read_text())
cfg['APP_REPOS'] = [
{
'id': 'server-up',
'name': 'server-up (GitHub)',
'url': 'https://github.com/bes-r/server-up.git',
'branch': 'main',
'subdir': 'apps',
'token': ''
},
{
'id': 'boilerplates',
'name': 'Boilerplates (ChristianLempa)',
'url': 'https://github.com/ChristianLempa/boilerplates-library.git',
'branch': 'main',
'subdir': 'compose'
},
{
'id': 'bes-r-dev',
'name': 'bes-r (dev)',
'url': 'http://10.0.20.22:3000/bes-r/server-up.git',
'branch': 'dev',
'token': '',
'subdir': 'apps'
}
]
p.write_text(json.dumps(cfg, indent=2))
print('Config bijgewerkt.')
"
echo "Container herstarten..."
cd /opt/docker/server-up && docker compose restart
echo "Klaar. Ga in Server Up naar de app-store en klik op Synchroniseren voor 'bes-r (dev)'."

129
release.ps1 Normal file
View file

@ -0,0 +1,129 @@
# release.ps1 — Server Up release-script
#
# Eén commando: stage alles → commit → tag → push (commit + tag) naar Forgejo.
# Forgejo Actions pakt de tag en bouwt automatisch het image met de juiste
# SU_VERSION (zie .forgejo/workflows/build.yml of server-up-deploy/README.md).
#
# Gebruik:
# .\release.ps1 -Version 0.3.02 -Message "Boilerplates YAML rendering fix"
#
# Optioneel:
# -DryRun Toon alles, voer niets uit
# -NoPush Wel taggen, niet pushen
# -AllowDirty Sla de "wel echt iets gewijzigd?" check over
# -ChangelogTop Plak een ## v$Version blok bovenaan CHANGELOG.md
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)][string]$Version,
[Parameter(Mandatory = $true)][string]$Message,
[string]$Remote = "origin",
[switch]$DryRun,
[switch]$NoPush,
[switch]$AllowDirty,
[switch]$ChangelogTop
)
$ErrorActionPreference = "Stop"
# ── Sanity checks ─────────────────────────────────────────────────────────────
# Versie formaat (semver met optionele suffix)
if ($Version -notmatch '^\d+\.\d+(\.\d+)?([\-_.][\w]+)?$') {
throw "Versie moet 'x.y' of 'x.y.z' formaat zijn, kreeg: '$Version'"
}
# In een git repo?
$gitRoot = & git rev-parse --show-toplevel 2>$null
if ($LASTEXITCODE -ne 0) { throw "Niet in een git-repository" }
Set-Location $gitRoot
Write-Host "Repo: $gitRoot" -ForegroundColor DarkGray
# Tag bestaat al?
$existing = & git tag --list "v$Version"
if ($existing) { throw "Tag v$Version bestaat al — kies een ander versienummer of verwijder de tag eerst" }
# Iets om te committen?
$status = & git status --porcelain
if (-not $status -and -not $AllowDirty) {
Write-Host "Geen wijzigingen om te committen." -ForegroundColor Yellow
$reply = Read-Host "Alleen taggen op huidige HEAD? [y/N]"
if ($reply -notmatch '^[yY]') { exit 0 }
$tagOnly = $true
} else {
$tagOnly = $false
}
# ── Plan tonen ────────────────────────────────────────────────────────────────
Write-Host ""
Write-Host "═══ Release plan ═══" -ForegroundColor Cyan
Write-Host " Versie : v$Version"
Write-Host " Bericht: $Message"
Write-Host " Remote : $Remote"
if ($DryRun) { Write-Host " Mode : DRY RUN — niets wordt uitgevoerd" -ForegroundColor Yellow }
if ($tagOnly) { Write-Host " Mode : alleen tag (geen nieuwe commit)" -ForegroundColor Yellow }
if ($NoPush) { Write-Host " Push : OVERGESLAGEN" -ForegroundColor Yellow }
if (-not $tagOnly) {
Write-Host ""
Write-Host "Gewijzigde bestanden:" -ForegroundColor DarkGray
& git status --short
}
# ── Optioneel: CHANGELOG bijwerken ────────────────────────────────────────────
if ($ChangelogTop -and -not $DryRun -and -not $tagOnly) {
$clog = Join-Path $gitRoot "CHANGELOG.md"
if (Test-Path $clog) {
$date = Get-Date -Format "yyyy-MM-dd"
$header = "# v$Version$date`n`n$Message`n`n---`n`n"
$original = Get-Content $clog -Raw
Set-Content $clog ($header + $original) -NoNewline
& git add CHANGELOG.md
Write-Host "✓ CHANGELOG.md bijgewerkt" -ForegroundColor Green
}
}
# ── Uitvoeren ─────────────────────────────────────────────────────────────────
function Run([string]$Description, [scriptblock]$Action) {
Write-Host "$Description" -ForegroundColor Cyan
if (-not $DryRun) { & $Action }
}
if (-not $tagOnly) {
Run "git add -A" { & git add -A }
Run "git commit" {
# Commit met header "release: vX.Y.Z" + jouw message als body
& git commit -m "release: v$Version" -m $Message
if ($LASTEXITCODE -ne 0) { throw "git commit faalde" }
}
}
Run "git tag -a v$Version" {
& git tag -a "v$Version" -m "v$Version$Message"
if ($LASTEXITCODE -ne 0) { throw "git tag faalde" }
}
if (-not $NoPush) {
Run "git push $Remote HEAD" {
& git push $Remote HEAD
if ($LASTEXITCODE -ne 0) { throw "git push (commit) faalde" }
}
Run "git push $Remote v$Version" {
& git push $Remote "v$Version"
if ($LASTEXITCODE -ne 0) { throw "git push (tag) faalde" }
}
}
# ── Klaar ─────────────────────────────────────────────────────────────────────
Write-Host ""
Write-Host "✓ Release v$Version klaar" -ForegroundColor Green
if (-not $NoPush -and -not $DryRun) {
Write-Host " Forgejo Actions bouwt nu het image (zie repo → Actions)" -ForegroundColor DarkGray
Write-Host " Daarna op je server:" -ForegroundColor DarkGray
Write-Host " SU_VERSION=$Version in .env" -ForegroundColor DarkGray
Write-Host " docker compose pull && docker compose up -d" -ForegroundColor DarkGray
}

View file

@ -18,7 +18,7 @@ from core.modules import Module, CORE, discover
app = Flask(__name__, static_folder="static", template_folder="templates") app = Flask(__name__, static_folder="static", template_folder="templates")
VERSION = os.environ.get("SU_VERSION", "0.3.0") VERSION = os.environ.get("SU_VERSION", "0.3.1")
MODULES: list[Module] = [] MODULES: list[Module] = []
USER_MOD = APP / "modules" USER_MOD = APP / "modules"

View file

@ -759,7 +759,7 @@ tailwind.config = {
<script> <script>
function app() { function app() {
return { return {
version: '0.3.0', version: '0.3.1',
page: location.hash.slice(1) || 'dashboard', page: location.hash.slice(1) || 'dashboard',
isMobile: window.innerWidth < 768, isMobile: window.innerWidth < 768,
sidebarOpen: window.innerWidth >= 768 && localStorage.getItem('sidebar') !== 'closed', sidebarOpen: window.innerWidth >= 768 && localStorage.getItem('sidebar') !== 'closed',