---
name: zimaos-app-install
description: Neue App/Container auf ZimaOS sauber per Docker Compose installieren — mit x-casaos-Block, korrekten Pfaden und ohne Legacy-Probleme.
version: 1.0.0
author: Hermes Agent (from Claude handover 2026-06-04)
license: MIT
metadata:
  hermes:
    tags: [zimaos, docker, compose, casaos, install, convention]
    related_skills: [zimaos-administration, zimaos-quirks, casaos-app-troubleshoot]
---

# ZimaOS App Install

Jede neue App auf ZimaOS **immer** per Docker Compose installieren — niemals `docker run`. Diese Konvention verhindert Legacy-Container, kaputte Icons, Random-Namen, und unkontrollierte Stacks.

## Schritt 1: Pfade festlegen

| Was | Pfad |
|-----|------|
| Compose-File | `/var/lib/casaos/apps/<AppName>/docker-compose.yml` (PascalCase) |
| App-Daten (config/cache) | `/DATA/AppData/<appname>/` (lowercase) |
| Große Files (media) | `/media/HDD_1TB/<AppName>/` |
| Icons (optional) | `/DATA/AppData/icons/<appname>.svg` |

`/var/lib/casaos/apps/<AppName>/` und `/DATA/.casaos/apps/<AppName>/` sind **die gleiche inode** — beides funktioniert.

## Schritt 2: Compose-File schreiben

**Pflichtfelder im Compose:**

```yaml
name: <appname-kleinbuchstaben>   # Verhindert random docker-Namen wie "noble_andres"

services:
  <service>:
    container_name: <AppName>      # Sauberer Name statt "<app>-<service>-1"
    image: <image:tag>
    restart: unless-stopped
    # Volumes mit klaren Pfaden — KEINE Leerzeichen!
    volumes:
      - /DATA/AppData/<appname>:/data
    ports:
      - "127.0.0.1:XXXX:XXXX"      # Nur localhost wenn möglich
```

## Schritt 3: x-casaos-Block

**Immer** einen `x-casaos:` Block ans Ende des Compose-Files — sonst zeigt CasaOS die App als "ausgegraut/uncontrolled".

```yaml
x-casaos:
  architectures:
    - amd64
    - arm64
  author: "Author Name"
  category: "Utilities"
  hostname: ""
  icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/<name>.svg"
  index: /
  main: <hauptservice-name>           # Bei Single-Service: der eine Service-Name
  port_map: "<external-port>"
  scheme: http
  store_app_id: <appname-kleinbuchstaben>
  title:
    custom: "Pretty Display Name"
```

**Icon-Optionen (nach Präferenz):**
1. `https://cdn.jsdelivr.net/gh/selfhst/icons/svg/<name>.svg` — externe CDN-Icons
2. `data:image/svg+xml;base64,...` — Base64-Daten-URL (self-hosted, kein extra Webserver nötig)
3. Keine lokale URL auf einen App-Port (z.B. `http://192.168.178.171:3000/icon.svg`) — bricht wenn der Container down ist

**Bei Multi-Service-Stacks:** `main: <hauptservice>` setzen, damit CasaOS weiß welcher Container die Hauptrolle hat.

## Schritt 4: Starten

```bash
# Verzeichnis anlegen
mkdir -p /var/lib/casaos/apps/<AppName>

# Compose-File schreiben
# ...

# Starten
cd /var/lib/casaos/apps/<AppName>
sudo docker compose up -d

# CasaOS-UI über Änderung informieren (BEIDE Dienste!)
sudo systemctl restart zimaos-app-management
sudo systemctl restart zimaos-gateway
```

## Legacy-Fix: Wenn App als "container" statt "v2app" erscheint

Ursache: `zimaos-app-management` findet die Compose-Datei nicht unter `/DATA/AppData/<app>/casaos-compose.yml` und registriert die App als `container`-Typ (Legacy, kein Icon, kein Port).

**Fix:**
```bash
# 1. Container stoppen und löschen
docker stop <container_name> && docker rm <container_name>

# 2. Vom korrekten CasaOS-Pfad neu deployen
cd /var/lib/casaos/apps/<AppName>
sudo docker compose up -d

# 3. App-Management + Gateway neustarten
sudo systemctl restart zimaos-app-management
sudo systemctl restart zimaos-gateway
```

**Verifikation:**
```bash
PORT=$(sudo ss -tlnp | grep zimaos-app-man | awk '{print $4}' | cut -d: -f2 | head -1)
curl -s http://127.0.0.1:$PORT/v2/app_management/web/appgrid | python3 -c "
import sys,json
data = json.load(sys.stdin)
for d in data.get('data',data):
    if '<appname>' in str(d).lower():
        print(d.get('app_type'))  # Muss 'v2app' sein
"
```

## Anti-Patterns (NICHT tun)

- **`docker run -d ...`** → Erzeugt Legacy-Container ohne Compose, ohne x-casaos, ohne Icons
- **Leerzeichen in Volume-Pfaden** → `/media/HDD 1TB/...` (bricht Shell-Scripting). Nutze `/media/HDD_1TB/...`
- **Compose ohne `name:`** → Docker generiert Random-Namen wie `noble_andres`
- **Compose ohne `container_name:`** → Hässliche Namen wie `<app>-<service>-1`
- **Compose ohne `x-casaos:`** → CasaOS zeigt App als "uncontrolled/ausgegraut"
- **Icon-URL auf lokalen App-Port** → Icon verschwindet wenn Container down, und CasaOS kann die App als "Legacy" einstufen
- **`hostname` auf feste IP gesetzt** (z.B. `172.29.0.1`) → App erscheint als "Legacy" im Dashboard. Immer `hostname: ""` verwenden.
- **Compose-File am falschen Pfad** (`/DATA/AppData/<app>/casaos-compose.yml` statt `/var/lib/casaos/apps/<AppName>/docker-compose.yml`) → `zimaos-app-management` findet die Datei nicht, registriert die App als `container`-Typ (Legacy) statt `v2app`. Immer vom Standard-CasaOS-Pfad deployen.

## Verifikation

```bash
# Container läuft?
docker ps --filter "name=<AppName>"

# Compose wird von CasaOS erkannt?
docker compose ls | grep <appname>

# In CasaOS UI prüfen: App sollte Icon + Namen zeigen, nicht "Legacy" oder ausgegraut
```
