mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-28 22:01:33 +00:00
302 lines
14 KiB
Markdown
302 lines
14 KiB
Markdown
# Docker Development Environment
|
|
|
|
> Docker / Sail setup for NNTmux — a Laravel 12 Usenet indexer.
|
|
|
|
## Prerequisites
|
|
|
|
- Docker & **Docker Compose v2.22+** (the Makefile uses `pull --ignore-buildable`)
|
|
- A GitHub (scopeless) token for Composer private packages
|
|
- [Laravel Sail](https://laravel.com/docs/12.x/sail) (included as a dev dependency)
|
|
|
|
## Quick Start
|
|
|
|
```bash
|
|
# 1. Copy and configure your environment
|
|
cp .env.example .env
|
|
# Edit .env — set DB credentials, COMPOSER_AUTH, and uncomment the
|
|
# "Docker service hostnames" block at the bottom.
|
|
|
|
# 2. Build and start
|
|
make build
|
|
make up
|
|
|
|
# 3. Install NNTmux (first run only)
|
|
make artisan cmd="nntmux:install"
|
|
|
|
# 4. Build frontend assets
|
|
make npm-build
|
|
```
|
|
|
|
## Environment Configuration
|
|
|
|
When running via Docker, uncomment the **Docker service hostnames** block
|
|
at the bottom of `.env` so the app resolves container names:
|
|
|
|
```dotenv
|
|
DB_HOST=mariadb
|
|
REDIS_HOST=redis
|
|
MANTICORESEARCH_HOST=manticore
|
|
ELASTICSEARCH_HOST=elasticsearch
|
|
MAIL_HOST=mailpit
|
|
MAIL_PORT=1025
|
|
```
|
|
|
|
### Search Engine Selection
|
|
|
|
Set `COMPOSE_PROFILES` in `.env` to match your `SEARCH_DRIVER`:
|
|
|
|
| `SEARCH_DRIVER` | `COMPOSE_PROFILES` |
|
|
|------------------|--------------------|
|
|
| `manticore` | `manticore` |
|
|
| `elasticsearch` | `elasticsearch` |
|
|
|
|
Only the selected search service container will start. The other remains
|
|
dormant and consumes no resources.
|
|
|
|
### ManticoreSearch Image Updates
|
|
|
|
Both `docker-compose.yml` and `docker-compose.yml.prod-dist` intentionally use
|
|
the unpinned `manticoresearch/manticore` image. This keeps ManticoreSearch on
|
|
the latest published Docker image whenever images are pulled, but it also means
|
|
production can receive ManticoreSearch changes without a repository diff.
|
|
|
|
Before pulling and restarting production, validate the new image in staging by
|
|
creating indexes, indexing a small batch, and running representative searches,
|
|
filters, sorting, pagination, deletes, suggestions, fuzzy searches, and any raw
|
|
SQL diagnostics/reconciliation commands.
|
|
|
|
Manticore Search 27.1.5 is part of the 25.x-27.x release line that introduced
|
|
built-in authentication/authorization, sharded tables, conversational search,
|
|
vector-search improvements, and replication layout changes. The app does not
|
|
enable Manticore auth by default, but if auth is enabled on the server set either
|
|
`MANTICORESEARCH_USERNAME`/`MANTICORESEARCH_PASSWORD` or
|
|
`MANTICORESEARCH_TOKEN` before running the app, index-creation commands, or raw
|
|
HTTP diagnostics. Roll auth out in staging first; anonymous local Docker usage
|
|
continues to work with these variables blank.
|
|
|
|
Native Ubuntu/Debian package installs are managed by `systemd`, not Docker. If
|
|
the package install fails while starting `manticore.service`, especially with
|
|
`Status: "Replaying binlogs..."` and `accept() failed ... Too many open files`,
|
|
or if `searchd` prints a backtrace during binlog replay, use
|
|
[`docs/manticore-ubuntu-package.md`](docs/manticore-ubuntu-package.md) to raise
|
|
the service file descriptor limit, preserve crash evidence, quarantine bad
|
|
binlogs if needed, and finish `dpkg` configuration.
|
|
|
|
## Make Targets
|
|
|
|
Run `make` or `make help` to see all targets, grouped by section.
|
|
|
|
### Lifecycle
|
|
|
|
| Target | Description |
|
|
|-------------------|-----------------------------------------------------------------|
|
|
| `make up` | Start all services (detached) |
|
|
| `make down` | Stop all services |
|
|
| `make restart` | Restart all services |
|
|
| `make recreate` | Force-recreate containers without rebuilding |
|
|
| `make build` | Build the app image (cached) |
|
|
| `make rebuild` | Pull fresh base images + `--no-cache` build + force-recreate |
|
|
| `make pull` | Pull latest enabled-profile base images (skips buildable ones) |
|
|
| `make update` | Infra-only: pull + `--pull` build + restart |
|
|
| `make upgrade` | App upgrade: `update` + composer + npm + migrate + caches |
|
|
| `make fresh` | **Destroy volumes**, pull, rebuild, recreate (DATA LOSS) |
|
|
|
|
### Development
|
|
|
|
| Target | Description |
|
|
|---------------------|-------------------------------------------------------|
|
|
| `make shell` | Bash shell in the app container |
|
|
| `make root-shell` | Root bash shell in the app container |
|
|
| `make tinker` | Laravel Tinker REPL |
|
|
| `make artisan cmd=` | Run any artisan command |
|
|
| `make migrate` | Run pending migrations |
|
|
| `make migrate-fresh`| Drop all tables and re-migrate (DATA LOSS) |
|
|
| `make seed` | Run database seeders |
|
|
| `make cache-clear` | Clear config / route / view / app caches (and stale `bootstrap/cache` files) |
|
|
| `make optimize` | Dev-safe: warm view cache + spatie/laravel-data |
|
|
| `make optimize-deploy` | Production: also caches config/routes (bakes absolute paths) |
|
|
| `make queue-work` | Foreground queue worker |
|
|
| `make queue-restart`| Signal queue workers to restart |
|
|
| `make tmux-start` | Start the NNTmux tmux processing engine |
|
|
| `make tmux-stop` | Stop the tmux processing engine |
|
|
| `make tmux-attach` | Attach to the running tmux session |
|
|
| `make horizon` | Show Horizon queue status |
|
|
| `make fix-permissions` | Chown project to host UID + register git `safe.directory` |
|
|
| `make fix-permissions` | Chown project to `sail` + register git safe.directory |
|
|
|
|
### Testing & Quality
|
|
|
|
| Target | Description |
|
|
|------------------|------------------------------------------------------|
|
|
| `make test` | PHPUnit tests (`filter=Name` optional) |
|
|
| `make pint` | Pint formatter on dirty files |
|
|
| `make pint-all` | Pint formatter on all files |
|
|
| `make phpstan` | PHPStan static analysis (2G memory limit) |
|
|
| `make rector` | Rector dry-run (no changes) |
|
|
| `make rector-fix`| Apply Rector refactorings |
|
|
|
|
### Frontend & Types
|
|
|
|
| Target | Description |
|
|
|-----------------------|--------------------------------------|
|
|
| `make npm-build` | `npm install` + `npm run build` |
|
|
| `make npm-dev` | Start Vite dev server |
|
|
| `make ts-types` | Regenerate TypeScript types |
|
|
| `make ts-types-check` | CI: fail if generated types drift |
|
|
| `make data-cache` | Cache spatie/laravel-data structures |
|
|
|
|
### Logs & Status
|
|
|
|
| Target | Description |
|
|
|---------------------|------------------------------------------------------------------|
|
|
| `make logs` | Tail all container logs (or `SERVICE=name` for one) |
|
|
| `make tail-laravel` | Tail `storage/logs/laravel.log` inside the app container |
|
|
| `make status` / `ps`| Show running containers |
|
|
| `make top` | Show processes inside each container |
|
|
| `make images` | Show images used by each service |
|
|
| `make health` | Healthcheck status per service |
|
|
|
|
### Cleanup
|
|
|
|
| Target | Description |
|
|
|---------------|---------------------------------------------------------------|
|
|
| `make clean` | Prune stopped containers / dangling images |
|
|
| `make nuke` | **Remove ALL** project containers, images, volumes (DATA LOSS)|
|
|
|
|
### Flags
|
|
|
|
These can be combined with the targets above:
|
|
|
|
| Flag | Effect |
|
|
|----------------|-----------------------------------------------------------------------|
|
|
| `FORCE=1` | Skip confirmation prompts on `fresh`, `nuke`, `migrate-fresh` (CI use)|
|
|
| `MAINTENANCE=1`| Wrap `upgrade` migrations in `artisan down` / `artisan up` |
|
|
| `SERVICE=name` | Restrict `logs` to a specific compose service |
|
|
| `CMD="…"` | Free-form command for `artisan` (alternative to `cmd=`) |
|
|
| `filter=Name` | Pass `--filter=Name` to `make test` |
|
|
|
|
Examples:
|
|
|
|
```bash
|
|
make fresh FORCE=1 # non-interactive teardown + rebuild
|
|
make upgrade MAINTENANCE=1 # zero-downtime-ish upgrade with maint mode
|
|
make logs SERVICE=mariadb # tail only mariadb
|
|
make test filter=ReleaseSearchTest # run a single test
|
|
```
|
|
|
|
> **Note:** `make pull` / `update` / `rebuild` use `docker compose pull --ignore-buildable`,
|
|
> which only pulls images for services in the active `COMPOSE_PROFILES` and skips images
|
|
> that are built locally (e.g. `sail-8.5/app`). Requires Docker Compose v2.22+.
|
|
|
|
You can also use `./sail` directly for anything not covered above —
|
|
unknown commands are passed through to `docker compose`.
|
|
|
|
## Networking
|
|
|
|
Sail creates a Docker network called `sail` with these default port mappings:
|
|
|
|
| Service | Container Port | Host Port (default) |
|
|
|----------------|----------------|------------------------------------------|
|
|
| HTTP (nginx) | 80 | `APP_PORT` (80) |
|
|
| Vite | 5173 | `VITE_PORT` (5173) |
|
|
| MariaDB | 3306 | `FORWARD_DB_PORT` (3306) |
|
|
| Redis | 6379 | `FORWARD_REDIS_PORT` (6379) |
|
|
| Manticore SQL | 9306 | 9306 |
|
|
| Manticore HTTP | 9308 | 9308 |
|
|
| Elasticsearch | 9200 | 9200 |
|
|
| Mailpit SMTP | 1025 | `FORWARD_MAILPIT_PORT` (1025) |
|
|
| Mailpit Web | 8025 | `FORWARD_MAILPIT_DASHBOARD_PORT` (8025) |
|
|
|
|
If a port is already in use on your host, change the corresponding
|
|
`FORWARD_*` / `APP_PORT` variable in `.env`.
|
|
|
|
## Database
|
|
|
|
On first run MariaDB creates a user/database from your `.env`:
|
|
|
|
```dotenv
|
|
DB_USERNAME=
|
|
DB_PASSWORD=
|
|
DB_DATABASE=nntmux
|
|
```
|
|
|
|
Import an existing SQL dump or run `make artisan cmd="nntmux:install"` for
|
|
a fresh installation.
|
|
|
|
## Backups
|
|
|
|
Add this optional service to `docker-compose.yml` for automated MariaDB backups:
|
|
|
|
```yaml
|
|
backup:
|
|
image: fradelg/mysql-cron-backup
|
|
depends_on:
|
|
- mariadb
|
|
restart: always
|
|
volumes:
|
|
- ./docker/backups:/backup
|
|
environment:
|
|
- MYSQL_USER=${DB_USERNAME}
|
|
- MYSQL_PASS=${DB_PASSWORD}
|
|
- MYSQL_DB=${DB_DATABASE}
|
|
- CRON_TIME=0 3 * * *
|
|
- MYSQL_HOST=mariadb
|
|
- MYSQL_PORT=3306
|
|
- TIMEOUT=10s
|
|
- GZIP_LEVEL=9
|
|
- MAX_BACKUPS=5
|
|
- INIT_BACKUP=0
|
|
- EXIT_BACKUP=1
|
|
networks:
|
|
- sail
|
|
```
|
|
|
|
## Production
|
|
|
|
For production deployments use `docker-compose.yml.prod-dist` as a starting
|
|
point. It includes separate `webapp`, `worker`, and `scheduler` services
|
|
and uses the root `Dockerfile` (FrankenPHP-based).
|
|
|
|
```bash
|
|
cp docker-compose.yml.prod-dist docker-compose.yml
|
|
# Edit .env for production settings
|
|
docker compose up -d
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
| Problem | Solution |
|
|
|---------------------------------|-----------------------------------------------------------------------|
|
|
| Permission errors on storage/ | `make fix-permissions` (chowns project to your host UID) |
|
|
| `composer install` permission denied | `make fix-permissions`, then re-run `make composer-install` |
|
|
| `npm`/`ncu` EACCES on host (`package.json`) | `make fix-permissions` chowns to host UID, not container `sail` |
|
|
| `fatal: detected dubious ownership` (git) | `make fix-permissions` registers `safe.directory` in the container |
|
|
| Container `sail` UID ≠ host UID | Set `WWWUSER=$(id -u)` / `WWWGROUP=$(id -g)` in `.env`, then `make rebuild` |
|
|
| Host artisan/npm fails with `/var/www/html/...` paths | Stale `bootstrap/cache/config.php` from a container `config:cache`. Run `make cache-clear` and prefer `make optimize` (dev-safe) over `optimize-deploy` in development |
|
|
| Port already in use | Change `APP_PORT`, `FORWARD_DB_PORT`, etc. in `.env` |
|
|
| Containers won't start | `make logs` to inspect, or `make rebuild` to start fresh |
|
|
| Stale images after upgrade | `make update` (pulls base images + rebuild + restart) |
|
|
| Need a completely clean slate | `make fresh` (destroys all volumes; add `FORCE=1` for non-interactive)|
|
|
| CI / scripted teardown | `make fresh FORCE=1` or `make nuke FORCE=1` to skip prompts |
|
|
| supervisorctl not connecting | `make root-shell` then `supervisorctl status` to verify socket path |
|
|
|
|
## Nginx (GetPageSpeed + Brotli)
|
|
|
|
The app container's nginx is installed from the [GetPageSpeed apt repo](https://extras.getpagespeed.com/ubuntu/)
|
|
(stable branch) instead of the Ubuntu archive. This gives us a current nginx
|
|
build with ABI-matched dynamic modules. The `nginx-module-brotli` package is
|
|
installed and the brotli directives in `docker/8.5/nginx.conf` are enabled by
|
|
default (gzip is kept as a fallback for clients without `br` support).
|
|
|
|
The repo is apt-pinned at priority `1001` via
|
|
`/etc/apt/preferences.d/getpagespeed-nginx.pref` so `nginx` and module
|
|
packages always resolve from GetPageSpeed even if Ubuntu publishes a newer
|
|
version. A `nginx -t` is run during `docker build` to fail fast on any config
|
|
drift.
|
|
|
|
To revert to stock Ubuntu nginx, remove the GetPageSpeed apt key, list, and
|
|
preferences entries from `docker/8.5/Dockerfile`, drop `nginx-module-brotli`
|
|
from the install line, re-comment the brotli block in `docker/8.5/nginx.conf`,
|
|
and run `make rebuild`.
|
|
|