harbor/casa-app-workflow.md

5.1 KiB

CasaOS New App Deployment Workflow

Target: casa VM (192.168.122.33) on pre

Prerequisites

  • SSH access: ssh pre then ssh casaos (or ssh -J pre casaos)
  • Sudo password: same as user password
  • Cloudflare API token and zone ID in settings/credentials.env
  • NPM access on linode via API

Step 1: Research the Docker Image

  • Find the official or linuxserver.io image
  • Note: default port, required volumes, environment variables
  • Check dashboard-icons for app icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/webp/<app-name>.webp

Step 2: Check Casa for Port Conflicts

ssh pre "ssh casaos 'echo happy2026 | sudo -S ss -tlnp | grep LISTEN'"

Current port map:

Port Service
80 CasaOS gateway
3000 ConvertX
8080 OmniTools
8443 Code Server
8888 Dozzle

Step 3: Create Docker Compose

ssh pre "ssh casaos 'mkdir -p ~/docker/<app-name>'"

Template (~/docker/<app-name>/docker-compose.yml):

name: <app-name>
services:
  <app-name>:
    image: <image>:<tag>
    container_name: <app-name>
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/Chicago
    labels:
      icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/webp/<app-name>.webp
    volumes:
      - /DATA/AppData/<app-name>:/config
    ports:
      - <host-port>:<container-port>
    restart: unless-stopped
x-casaos:
  author: self
  category: self
  hostname: <app-name>.snsnetlabs.com
  icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/webp/<app-name>.webp
  index: /
  is_uncontrolled: false
  port_map: "<host-port>"
  scheme: https
  store_app_id: <app-name>
  title:
    custom: ""
    en_us: <App Display Name>

Step 4: Deploy Container

ssh pre "ssh casaos 'echo happy2026 | sudo -S mkdir -p /DATA/AppData/<app-name> && \
  echo happy2026 | sudo -S chown -R 1000:1000 /DATA/AppData/<app-name> && \
  cd ~/docker/<app-name> && echo happy2026 | sudo -S docker compose up -d'"

Step 5: Register with CasaOS Dashboard

ssh pre "ssh casaos 'echo happy2026 | sudo -S mkdir -p /var/lib/casaos/apps/<app-name> && \
  echo happy2026 | sudo -S cp ~/docker/<app-name>/docker-compose.yml /var/lib/casaos/apps/<app-name>/'"

Step 6: Create Cloudflare A Record

curl -s -X POST "https://api.cloudflare.com/client/v4/zones/d4c9b425bad556070dc80848cb58e3ad/dns_records" \
  -H "Authorization: Bearer AYLGpIUaw-6GvlzAltkttKp-nh3JWEVXtWuJbGvl" \
  -H "Content-Type: application/json" \
  --data '{"type":"A","name":"<app-name>.snsnetlabs.com","content":"172.238.163.85","ttl":1,"proxied":false}'

Step 7: Create NPM SSL Certificate

# From linode (via pre):
TOKEN=$(curl -s -X POST http://localhost:81/api/tokens \
  -H "Content-Type: application/json" \
  -d '{"identity":"samueljamesinc@gmail.com","secret":"Happy2025!"}' | python3 -c "import sys,json; print(json.load(sys.stdin)['token'])")

curl -s -X POST http://localhost:81/api/nginx/certificates \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "letsencrypt",
    "nice_name": "<app-name>.snsnetlabs.com",
    "domain_names": ["<app-name>.snsnetlabs.com"],
    "meta": {
      "dns_challenge": true,
      "dns_provider": "cloudflare",
      "dns_provider_credentials": "dns_cloudflare_api_token=AYLGpIUaw-6GvlzAltkttKp-nh3JWEVXtWuJbGvl"
    }
  }'
# Note the returned cert ID

Step 8: Create NPM Proxy Host

curl -s -X POST http://localhost:81/api/nginx/proxy-hosts \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "domain_names": ["<app-name>.snsnetlabs.com"],
    "forward_host": "192.168.122.33",
    "forward_port": <host-port>,
    "forward_scheme": "http",
    "access_list_id": 0,
    "certificate_id": <cert-id>,
    "ssl_forced": false,
    "caching_enabled": true,
    "block_exploits": false,
    "allow_websocket_upgrade": true,
    "http2_support": false,
    "hsts_enabled": false,
    "hsts_subdomains": false,
    "meta": {
      "dns_challenge": true,
      "dns_provider": "cloudflare",
      "dns_provider_credentials": "# Cloudflare API token\ndns_cloudflare_api_token=AYLGpIUaw-6GvlzAltkttKp-nh3JWEVXtWuJbGvl"
    }
  }'

Step 9: Verify

curl -s -o /dev/null -w "HTTP %{http_code}\n" -L https://<app-name>.snsnetlabs.com

Dashboard Icons

Source: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/webp/<name>.webp

Search available icons: https://github.com/homarr-labs/dashboard-icons

Formats available: webp (preferred), png, svg

Traffic Flow

Internet → <app>.snsnetlabs.com
  → Cloudflare DNS (A record → 172.238.163.85 / linode)
  → linode NPM (HTTPS termination, Let's Encrypt cert via CF DNS challenge)
  → http://192.168.122.33:<port> (via NetBird tunnel to casa VM)

Deployed Apps

App Port Domain NPM ID Cert ID
CasaOS 80 casaos.snsnetlabs.com 39 48
ConvertX 3000 convertx.snsnetlabs.com 47 60
OmniTools 8080 omnitools.snsnetlabs.com 44 58
Code Server 8443 code.snsnetlabs.com 45 55
Dozzle 8888 dozzle.snsnetlabs.com 46 59