Claude
Skills
Sign in
Back

setup-infra

Included with Lifetime
$97 forever

Set up the Weslink local development environment with shared Docker infrastructure (Traefik, PostgreSQL, Redis, MeiliSearch, Mailpit, MinIO), native PHP-FPM + nginx, HTTPS via mkcert, and shell aliases. Use when a developer says 'setup local dev', 'einrichten', 'install infra', or 'ich will das lokale Setup'.

Backend & APIs

What this skill does


# Weslink Local Development Setup

This skill guides the installation of the complete local development stack. Read project config from `references/projects.json` using the Read tool.

## Architecture

```
Browser (HTTPS)
  -> Traefik (Docker, SSL) :443
    -> nginx (local) :8000-8003 -> PHP-FPM (local) :9090
    -> soketi (Docker) :6001       # WebSockets (kibi only)
    -> livekit (Docker) :7880      # Video Calls (kibi only)

Shared Docker Services:
  PostgreSQL :5432 | Redis :6379 | MeiliSearch :7700
  Mailpit :8025    | MinIO :9000 | Traefik Dashboard :8080
```

## Prerequisites

- macOS with Homebrew
- Docker (OrbStack recommended, or Docker Desktop)
- Git
- The project repositories already cloned

## Installation Steps

Execute each step, verify it works, then move on. Ask the user before running destructive commands.

### Step 1: Homebrew Packages

```bash
brew install [email protected] nginx dnsmasq mkcert
```

After installation, link [email protected] as the active PHP version:
```bash
brew unlink php && brew link [email protected] --force
```

### Step 2: Remove Valet (if installed)

Check first:
```bash
which valet 2>/dev/null && echo "Valet installed" || echo "No Valet"
```

If installed:
```bash
valet stop 2>/dev/null
composer global remove laravel/valet
sudo brew services stop nginx
sudo brew services stop php
sudo killall php-fpm 2>/dev/null
sudo killall nginx 2>/dev/null
```

Also check for Laravel Herd (blocks port 443, conflicts with Traefik):
```bash
# If Herd is installed, uninstall via: Herd app -> Settings -> Uninstall
```

### Step 3: mkcert Root CA

```bash
mkcert -install
```

Only needed once. Installs the local CA in the system keychain.

### Step 4: dnsmasq

```bash
mkdir -p $(brew --prefix)/etc/dnsmasq.d
echo "address=/.test/127.0.0.1" > $(brew --prefix)/etc/dnsmasq.d/test.conf
echo "listen-address=127.0.0.1" >> $(brew --prefix)/etc/dnsmasq.d/test.conf
grep -q "conf-dir=$(brew --prefix)/etc/dnsmasq.d" $(brew --prefix)/etc/dnsmasq.conf 2>/dev/null || \
    echo "conf-dir=$(brew --prefix)/etc/dnsmasq.d/,*.conf" >> $(brew --prefix)/etc/dnsmasq.conf
sudo mkdir -p /etc/resolver
echo "nameserver 127.0.0.1" | sudo tee /etc/resolver/test
sudo brew services start dnsmasq
```

Verify: `dig demo.kibi.test @127.0.0.1 +short` should return `127.0.0.1`.

### Step 5: Infrastructure Directory

Create `~/dev/infrastructure/` with the following structure. Read `references/projects.json` for project details and ports.

**Files to create:**

1. `~/dev/infrastructure/docker-compose.yml` - All shared services (Traefik, PostgreSQL, Redis, MeiliSearch, Mailpit, MinIO, Infra Dashboard) on the `shared-infra` Docker network
2. `~/dev/infrastructure/pgsql/init/01-create-databases.sh` - Creates all project databases on first PostgreSQL start
3. `~/dev/infrastructure/traefik/dynamic/tls.yml` - Points to the wildcard TLS certificate
4. `~/dev/infrastructure/traefik/dynamic/default.yml` - Catch-all route to the `infra-dashboard` container (priority 1), shows a dashboard for any unknown `.test` domain
5. `~/dev/infrastructure/traefik/dynamic/<project>.yml` - One routing config per project (routes domain to `host.docker.internal:<port>`)
6. `~/dev/infrastructure/dashboard/index.html` - Static catch-all dashboard page (displays available projects, active worktrees via Traefik API, and service links)
7. `~/dev/infrastructure/bin/infra` - CLI helper script (up, down, status, logs, cert-regen)
8. `~/dev/infrastructure/bin/wt` - Global worktree management script

**Key details:**
- PostgreSQL uses `pgvector/pgvector:pg16` (superset, works for all projects)
- All services are on the `shared-infra` Docker network
- Traefik uses file-based provider for routing (watches `traefik/dynamic/` directory)
- Traefik redirects HTTP to HTTPS automatically
- The `infra` and `wt` scripts must be `chmod +x`

**Generate TLS certificates:**
```bash
cd ~/dev/infrastructure/certs
mkcert -cert-file _wildcard.test.pem -key-file _wildcard.test-key.pem \
    "*.test" \
    "kibi.test" "*.kibi.test" \
    "bessler.test" "*.bessler.test" \
    "scada.test" "*.scada.test" \
    "contradoo.test" "*.contradoo.test"
```

**Traefik routing for projects with tenant subdomains (kibi):**
- Soketi WebSocket: `HostRegexp + PathPrefix(/app)` -> soketi:6001 (priority 100)
- MinIO proxy: `HostRegexp + PathPrefix(/storage/minio)` -> minio:9000 with path rewrite (priority 100)
- LiveKit: `Host(livekit.kibi.test)` -> livekit:7880
- Catch-all: `HostRegexp(^(.+\.)?kibi\.test$)` -> host.docker.internal:8000 (priority 10)

**Traefik routing for simple projects (bessler, scada, contradoo):**
- Single router: `Host(project.test)` -> host.docker.internal:<port>

### Step 6: PHP-FPM Configuration

**6.1 Disable Xdebug** (3-5x performance impact):
```bash
mv /opt/homebrew/etc/php/8.4/conf.d/20-xdebug.ini \
   /opt/homebrew/etc/php/8.4/conf.d/20-xdebug.ini.disabled 2>/dev/null
```

**6.2 Disable Valet FPM pool** (if exists):
```bash
mv /opt/homebrew/etc/php/8.4/php-fpm.d/valet-fpm.conf \
   /opt/homebrew/etc/php/8.4/php-fpm.d/valet-fpm.conf.disabled 2>/dev/null
```

**6.3 Install all required PHP extensions:**

The Docker containers use these extensions: pgsql, sqlite3, gd, curl, imap, mbstring, xml, zip, bcmath, soap, intl, readline, ldap, msgpack, igbinary, redis, memcached, pcov, imagick. Most are included with [email protected] via Homebrew. Missing ones need pecl:

```bash
pecl install redis igbinary msgpack
```

memcached needs a manual build:
```bash
cd /tmp && pecl download memcached && tar xzf memcached-*.tgz && cd memcached-*/
phpize && ./configure --with-php-config=/opt/homebrew/opt/[email protected]/bin/php-config \
  --with-zlib-dir=/opt/homebrew/opt/zlib --with-libmemcached-dir=/opt/homebrew \
  --enable-memcached-igbinary=yes --enable-memcached-msgpack=yes \
  --enable-memcached-json=yes --enable-memcached-session=yes --enable-memcached-sasl=yes
make -j$(sysctl -n hw.ncpu) && make install
echo "extension=memcached.so" > /opt/homebrew/etc/php/8.4/conf.d/20-memcached.ini
```

Note: imap and swoole are difficult to compile on macOS but are not actually used by any project. Skip them.

**6.3b Disable pcov by default (enables JIT):**
```bash
mv /opt/homebrew/etc/php/8.4/conf.d/20-pcov.ini /opt/homebrew/etc/php/8.4/conf.d/20-pcov.ini.disabled
```
pcov can be toggled on/off with the `pcov:on` / `pcov:off` shell aliases (see Step 11).

**6.4 Create performance config** at `/opt/homebrew/etc/php/8.4/conf.d/99-performance.ini`:
```ini
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=32
opcache.max_accelerated_files=20000
opcache.revalidate_freq=0
opcache.validate_timestamps=1
opcache.enable_file_override=1
opcache.jit=1255
opcache.jit_buffer_size=128M
realpath_cache_size=4096K
realpath_cache_ttl=600
memory_limit=512M
```

**6.5 Change FPM listen port** (9000 is used by MinIO):
```bash
sed -i '' 's/listen = 127.0.0.1:9000/listen = 127.0.0.1:9090/' \
    /opt/homebrew/etc/php/8.4/php-fpm.d/www.conf
```

**6.6 Fix FPM user:**
```bash
sed -i '' "s/^user = _www/user = $(whoami)/" /opt/homebrew/etc/php/8.4/php-fpm.d/www.conf
sed -i '' "s/^group = _www/group = staff/" /opt/homebrew/etc/php/8.4/php-fpm.d/www.conf
```

**6.7 Start PHP-FPM:**
```bash
/opt/homebrew/opt/[email protected]/sbin/php-fpm \
    --daemonize \
    --fpm-config /opt/homebrew/etc/php/8.4/php-fpm.conf
```

Verify: `lsof -i :9090 -P | head -3` should show php-fpm.

### Step 7: nginx Configuration

**7.1 Replace nginx.conf** at `/opt/homebrew/etc/nginx/nginx.conf`:
- Remove all Valet includes
- Set `error_log /tmp/nginx-error.log` and `pid /tmp/nginx.pid` (avoids permission issues)
- Set `access_log /tmp/nginx-access.log` in the http block
- Remove/comment the `user` directive
- Keep `include servers/*`

**7.2 Create server configs** in `/opt/homebrew/etc/nginx/servers/`:
One config per project. Each listens on its port, serves static files directly, proxies PHP to `127.0.0.1:9090` via FastCGI.

Important FastCGI params to include:
```nginx
fastcgi_param HTTPS "on";
fas

Related in Backend & APIs