# Android Cast — production infrastructure

<!-- doc-meta:start -->
| Field | Value |
|---|---|
| Author | Anton Afanasyeu |
| Revision | R1 |
| Creation date | 2026-05-26 |
| Last modification date | 2026-05-26 |
| Co-authored |  |
| Severity | medium |
| State | in progress |
| Document type | technical |
<!-- doc-meta:end -->

\newpage
\newpage

---


**Read this first** after a context reset, before changing nginx, deploy paths, or URLs.

| Doc | When |
|-----|------|
| [docs/README.md](README.md) | **Documentation index** — TOC for all guides |
| **This file** | Topology, hosts, ports, sshfs, agent rules |
| [examples/app_hub/DEPLOY.md](../examples/app_hub/DEPLOY.md) | Hub landing only (BE `listen 80`) |
| [examples/crash_reporter/backend/README.md](../examples/crash_reporter/backend/README.md) | PHP, MariaDB, tickets, ingest |
| [docs/GIT_FLOW.md](GIT_FLOW.md) | Branches, `next`, no direct commits to `master` |
| [docs/TICKETS_ROADMAP.md](TICKETS_ROADMAP.md) | Tickets, Gitea, alpha delegation |

---

---

---

---

---

---


---


---

---


---

## Table of contents

<!-- toc -->
- [1. Topology](#1-topology)
- [2. Port 8089 — not the androidcast vhost](#2-port-8089-not-the-androidcast-vhost)
- [3. Public URLs](#3-public-urls)
- [4. Disk layout (BE)](#4-disk-layout-be)
- [5. Nginx — source of truth in repo](#5-nginx-source-of-truth-in-repo)
  - [BE apps.conf today (typical)](#be-appsconf-today-typical)
  - [Hub location (correct)](#hub-location-correct)
  - [Reload (BE only for hub deploy)](#reload-be-only-for-hub-deploy)
- [6. Local sshfs workspace (not in git)](#6-local-sshfs-workspace-not-in-git)
- [7. FE nginx — two server names](#7-fe-nginx-two-server-names)
- [8. Verify](#8-verify)
- [9. Backend app (crashes / tickets)](#9-backend-app-crashes-tickets)
- [10. Rules for agents](#10-rules-for-agents)
- [11. Changelog (infra doc)](#11-changelog-infra-doc)
<!-- /toc -->

**Documentation index:** [README.md](README.md)

---

## 1. Topology

```text
Internet / LAN
    │
    ▼
┌─────────────────────────────────────┐
│  FE — Gentoo HVM                    │
│  Public: https://apps.f0xx.org      │
│  TLS termination, nginx reverse proxy│
└──────────────┬──────────────────────┘
               │  proxy_pass http://artc0.intra.raptor.org:80
               │  (default location /)
               ▼
┌─────────────────────────────────────┐
│  BE — Alpine VM 10.7.16.128         │
│  nginx: /etc/nginx/conf.d/apps.conf│
│  PHP-FPM unix socket                │
│  MariaDB: androidcast_crashes       │
└─────────────────────────────────────┘
```

| Role | Host | Notes |
|------|------|--------|
| **FE** | Gentoo, `apps.f0xx.org` | Almost all app traffic → BE **:80** |
| **BE** | Alpine `artc0.intra.raptor.org` | App vhost lives in **`listen 80`** for FE traffic |
| **Jump SSH** | `f0xx.org:222` → Alpine `:22` | `~/.ssh/config` host **`alpine-be`** |
| **Git origin** | `git://f0xx.org/android_cast` | Integration branch **`next`** |

---

## 2. Port 8089 — not the androidcast vhost

**Do not** configure or document the project hub or crash console on **`:8089`** for this installation.

| Port | Service |
|------|---------|
| **80** | **Canonical** androidcast vhost on BE (hub + crashes when FE uses `location /` or explicit `:80` upstream) |
| **443** | BE TLS (used by some FE `proxy_pass` rules, e.g. `apps.f0xx.org` → `https://artc0:443/.../crashes/`) |
| **8089** | **Other** stack (e.g. **Janus** `/janus/`) — **not** androidcast nginx vhost |

Wrong FE pattern (remove if present on **`artc0.f0xx.org`**):

```nginx
proxy_pass https://artc0.intra.raptor.org:8089/app/androidcast_project/;  # BAD for hub
```

Correct public path for hub:

`https://apps.f0xx.org/app/androidcast_project/` → FE `location /` → `http://artc0.intra.raptor.org:80` → BE `listen 80` locations.

---

## 3. Public URLs

| URL | Component |
|-----|-----------|
| `https://apps.f0xx.org/app/androidcast_project/` | Static hub (`examples/app_hub/index.html`) |
| `https://apps.f0xx.org/app/androidcast_project/crashes/` | PHP crash + tickets console |
| `https://apps.f0xx.org/app/androidcast_project/build/` | PHP APK builder console |
| `https://apps.f0xx.org/app/androidcast_project/crashes/api/upload.php` | Device crash upload (no session) |

Legacy hostname **`f0xx.org`** may still appear in app `settings.json` examples; production ingest/scripts prefer **`apps.f0xx.org`**.

---

## 4. Disk layout (BE)

Web root prefix:

`/var/www/localhost/htdocs/apps/app/androidcast_project/`

| Path on BE | Repo |
|------------|------|
| `.../androidcast_project/android_cast/` | Full git tree (crash backend, app sources) |
| `.../androidcast_project/index.html` | `examples/app_hub/index.html` (copy or symlink) |
| `.../androidcast_project/ota-artifacts/v0/` | OTA publish tree (`/v0/ota/` on public URL) |
| `.../android_cast/examples/crash_reporter/backend/public/` | PHP document root for crashes |

`config.php` **`base_path`** must be exactly:

`/app/androidcast_project/crashes`

---

## 5. Nginx — source of truth in repo

| File | Purpose |
|------|---------|
| **`examples/crash_reporter/backend/nginx.apps-port80.fragment`** | **Replace** BE `server { listen 80; ... }` — hub + crashes + build |
| `examples/crash_reporter/backend/nginx.apps-builder.frag` | Build-only blocks (also included on BE 443 via `apps_builder.frag`) |
| `examples/crash_reporter/backend/nginx.fe-apps.f0xx.org.snippet` | FE hub/crashes → `http://artc0:80` (preserve URI) |
| `examples/crash_reporter/backend/nginx.apps.conf.fragment` | Reference blocks (443-oriented comments) |
| `examples/crash_reporter/backend/nginx.vm.conf` | Full VM example |

### BE `apps.conf` today (typical)

- **`listen 80`** — often **empty** (only generic `\.php$`) → **public hub 502** until port-80 fragment is applied.
- **`listen 443 ssl`** — may already contain hub + crashes (direct HTTPS to VM).

FE **`apps.f0xx.org`** uses `proxy_pass http://artc0.intra.raptor.org:80` for `/` — so **hub must be on BE port 80**, not only 443.

### Hub location (correct)

Use **directory** `alias`, not `alias` to a single file:

```nginx
location /app/androidcast_project/ {
    alias /var/www/localhost/htdocs/apps/app/androidcast_project/;
    index index.html;
}
```

### Reload (BE only for hub deploy)

```bash
ssh alpine-be 'sudo nginx -t && sudo rc-service nginx reload'
```

---

## 6. Local sshfs workspace (not in git)

Edit live configs from the dev machine via mounts under repo **`tmp/`**:

| Mount | Remote |
|-------|--------|
| `tmp/FE_gentoo/etc/nginx/` | Gentoo FE nginx |
| `tmp/BE_alpine/etc/nginx/conf.d/apps.conf` | Alpine BE apps vhost |
| `tmp/BE_alpine/var/www/localhost/htdocs/apps/...` | BE web tree |

Treat `tmp/` as **local mirrors** — sync/reload on the real host after edits.

---

## 7. FE nginx — two server names

Mounted copy: `tmp/FE_gentoo/etc/nginx/nginx.conf`.

| `server_name` | `location /` | androidcast crashes | Hub `/app/androidcast_project/` |
|---------------|--------------|---------------------|--------------------------------|
| **`apps.f0xx.org`** | → `http://artc0:80` | Must **not** → `https://artc0:443/...` (static download) | Hub/crashes blocks must use **`http://artc0:80`** — see `nginx.fe-apps.f0xx.org.snippet` |
| **`/v0/ota/`** on FE | → **`http://artc0:80`** | BE :80 serves static tree | In consolidated **`/etc/nginx/apps.conf`** — see `patches/fe-nginx-APPLY.md` |
| **`artc0.f0xx.org`** | → `http://artc0:80` | Legacy → **:8089** | Legacy → **:8089** — **remove** hub block; prefer apps.f0xx.org |

**Agent default:** fix **BE `listen 80`** first. Change FE only when user asks or to delete wrong **8089** hub overrides on `artc0.f0xx.org`.

---

## 8. Verify

```bash
# BE directly (simulates FE Host header)
curl -sS -o /dev/null -w "%{http_code}\n" -H "Host: apps.f0xx.org" \
  "http://artc0.intra.raptor.org/app/androidcast_project/"

curl -sS -o /dev/null -w "%{http_code}\n" -H "Host: apps.f0xx.org" \
  "http://artc0.intra.raptor.org/app/androidcast_project/crashes/"

# Public
curl -sS -o /dev/null -w "%{http_code}\n" \
  "https://apps.f0xx.org/app/androidcast_project/"
```

Expect **200** (or **302** → crashes only if you intentionally redirect root).

---

## 9. Backend app (crashes / tickets)

- PHP 8.1+ FPM on Alpine; MariaDB DB **`androidcast_crashes`**.
- Migration **`003_tickets.sql`** as **MySQL root** if UI says table missing (app user cannot DDL).
- `Database::requireTicketsTable()` must open PDO before `SHOW TABLES` (fixed in repo).
- Ingest smoke tickets: `php scripts/ingest_alpha_smoke_tickets.php --url=https://apps.f0xx.org/app/androidcast_project/crashes`

---

## 10. Rules for agents

1. **KISS** — prefer **one** BE change (`listen 80` fragment) over FE + BE + 8089 guesses.
2. **Never** point androidcast hub/crashes docs at **:8089** for this install.
3. **Do not** use `alias` to `index.html` as a file path (breaks trailing slash / CSS).
4. **Do not** commit `tmp/` sshfs trees, `*.log`, or workspace files unless user asks.
5. **Do not** commit to `master`/`next` directly — use `feature/*` → merge to `next` ([GIT_FLOW](GIT_FLOW.md)).
6. User may be unwell / slow to deploy — give **short** copy-paste steps, not long runbooks.

---

## 11. Changelog (infra doc)

| Date | Note |
|------|------|
| 2026-06-04 | Edge probes: `examples/network/wan-snapshot.sh`, `monstro-netdiag.sh` (conntrack/iptables/CPU) |
| 2026-05-21 | Documented BE-only hub on port 80; 8089 = Janus only; FE `apps` vs `artc0` split |
