feat(docker): multi-stage Dockerfiles with npmmirror registry

Rewrites dashboard and finder Dockerfiles to use a clean multi-stage
build (deps → builder → runner) that installs npm packages inside
Alpine Linux, avoiding the SWC musl binary issue when building from
Windows host. Uses registry.npmmirror.com for reliable installs from
restricted networks (Iran).

- docker/api/Dockerfile: .NET 10 multi-stage build
- docker/web/Dockerfile: Node 20-alpine multi-stage, npmmirror
- docker/finder/Dockerfile: Node 20-alpine multi-stage, npmmirror
- docker/website/Dockerfile: marketing website build
- scripts/: PowerShell helper scripts for local dev

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-05-27 21:33:29 +03:30
parent 45cd028d1c
commit 03376b3ea1
20 changed files with 5519 additions and 0 deletions
+150
View File
@@ -0,0 +1,150 @@
# Running Meezi fully in Docker
## Quick start
```powershell
cd F:\Projects\Meezi
copy .env.example .env # if not done yet
powershell -File scripts\docker-up-full.ps1
```
Or manually:
```powershell
docker compose up -d --build
```
| Service | URL |
|-----------|-----|
| Dashboard | http://localhost:3101/fa/login |
| API | http://localhost:5080/swagger |
| Health | http://localhost:5080/health |
Demo OTP phone: `09121234567`
## If API build fails pulling .NET images
Default bases are **MCR** (official):
- `mcr.microsoft.com/dotnet/sdk:10.0`
- `mcr.microsoft.com/dotnet/aspnet:10.0`
Override in `.env` if needed:
```env
DOTNET_SDK_IMAGE=mcr.microsoft.com/dotnet/sdk:10.0
DOTNET_ASPNET_IMAGE=mcr.microsoft.com/dotnet/aspnet:10.0
```
### `insufficient_scope` / `pull access denied` on `docker.io/dotnet/sdk:10.0`
That usually means **Docker Hub auth**, not a missing .NET 10 tag. Do **not** rely on `dotnet/sdk:10.0` on Docker Hub unless pulls work on your machine.
1. **Clear bad Hub login** (fixes many `insufficient_scope` errors):
```powershell
docker logout
docker pull mcr.microsoft.com/dotnet/sdk:10.0
docker pull mcr.microsoft.com/dotnet/aspnet:10.0
```
2. **VPN** — then pre-pull MCR and build:
```powershell
docker pull mcr.microsoft.com/dotnet/sdk:10.0
docker pull mcr.microsoft.com/dotnet/aspnet:10.0
docker compose up -d --build
```
3. **Registry mirror** — Docker Desktop → Settings → Docker Engine, merge [`docker/daemon-registry-mirror.example.json`](../docker/daemon-registry-mirror.example.json), Apply & Restart.
4. **Pre-pull all images with VPN**, then build offline:
```powershell
docker pull mcr.microsoft.com/dotnet/sdk:10.0
docker pull mcr.microsoft.com/dotnet/aspnet:10.0
docker pull postgres:16-alpine
docker pull redis:7-alpine
docker pull node:20-alpine
docker compose up -d --build
```
## NuGet restore fails inside Docker (`SSL_ERROR_SSL`, `bad record mac`)
Example during `dotnet restore`:
```text
Failed to download package 'Microsoft.CodeAnalysis.CSharp.4.14.0' from 'https://api.nuget.org/...'
Decrypt failed with OpenSSL error - SSL_ERROR_SSL
error:0A000119:SSL routines::decryption failed or bad record mac
```
This is **not a Meezi code bug** — TLS to `api.nuget.org` is being corrupted or cut off inside the build container (unstable VPN, antivirus HTTPS scan, filtered ISP, Docker Desktop network glitch).
**Try in order:**
1. **Restart Docker Desktop** fully (Quit → start again). After `Ctrl+C` mid-build, the engine often returns `500 Internal Server Error` until restarted.
2. **VPN on** for the whole build (connect *before* `docker compose build`, keep it on until restore finishes).
3. **Pre-restore on the host** (uses Windows network, often more reliable), then rebuild:
```powershell
cd F:\Projects\Meezi
dotnet restore src\Meezi.API\Meezi.API.csproj
docker compose build api
docker compose up -d
```
4. **Disable HTTPS inspection** in antivirus / corporate proxy for Docker Desktop and `docker.exe`.
5. **Retry** — `docker compose build api --no-cache` once network is stable.
The API `Dockerfile` uses `nuget.config` retries, `NUGET_CERT_REVOCATION_MODE=offline`, and a NuGet cache mount to make repeat builds easier.
## Docker Desktop `500 Internal Server Error` on `docker compose up`
```text
unable to get image 'meezi-web': request returned 500 Internal Server Error
... dockerDesktopLinuxEngine ...
```
The Linux engine crashed or is stuck (common after aborting a long build).
```powershell
# 1) Quit Docker Desktop from the tray (not only close the window)
# 2) Optional — reset WSL backend (Docker Desktop → WSL2):
wsl --shutdown
# 3) Start Docker Desktop, wait until it says "Running"
docker version
docker compose build
docker compose up -d
```
If `docker version` hangs, Docker is still broken — reboot Windows or **Troubleshoot → Reset to factory defaults** in Docker Desktop (last resort).
## Why the API image does not run `apt-get`
Older Dockerfiles installed `curl` for healthchecks, which downloads Ubuntu packages during **build** (`archive.ubuntu.com`). That often fails in Iran without VPN.
The API image now uses a **TCP healthcheck** on port 8080 instead — no extra OS packages.
## Commands
```powershell
docker compose ps
docker compose logs -f api
docker compose down
docker compose down -v # also removes DB volume
```
## Infra-only fallback (host API)
Only if Docker cannot build .NET images at all:
```powershell
docker compose up -d postgres redis
cd src\Meezi.API
$env:RUN_MIGRATIONS="true"
dotnet run
```