Skip to content

Latest commit

 

History

History
322 lines (251 loc) · 8.54 KB

File metadata and controls

322 lines (251 loc) · 8.54 KB
eyebrow Docs · Recipes
lede Laravel Sail with an OPC UA test server sidecar. Docker Compose, the simplest possible dev loop, and the few gotchas around socket paths in containerised environments.
see_also
href meta
../getting-started/installation.md
5 min
href meta
../testing/integration-tests.md
6 min
href meta
./production-deployment.md
6 min
prev
label href
Using companion specs
./using-companion-specs.md
next
label href
Production deployment
./production-deployment.md

Dev with Sail

Laravel Sail is the lightest local-development environment for Laravel. Add an OPC UA test server as a sidecar and you have an end-to-end dev environment in two Docker images.

Add the OPC UA test server

In docker-compose.yml, add a service:

services:
  laravel.test:
    # ... existing Sail config

  opcua-test:
    image: ghcr.io/php-opcua/uanetstandard-test-suite:latest
    ports:
      - "${OPCUA_PORT:-4840}:4840"   # unsecured
      - "${OPCUA_SECURE_PORT:-4841}:4841"   # secured
    networks:
      - sail
    healthcheck:
      test: ["CMD", "sh", "-c", "nc -z localhost 4840"]
      interval: 5s
      retries: 10

Bring it up:

./vendor/bin/sail up -d

Configure Laravel to point at it

In .env:

OPCUA_ENDPOINT=opc.tcp://opcua-test:4840

Note: the hostname is opcua-test (the Docker service name), not localhost — Sail networks containers together.

For the secured endpoint:

OPCUA_ENDPOINT=opc.tcp://opcua-test:4841
OPCUA_SECURITY_POLICY=Basic256Sha256
OPCUA_SECURITY_MODE=SignAndEncrypt
OPCUA_CLIENT_CERT=/var/www/html/dev-certs/client.pem
OPCUA_CLIENT_KEY=/var/www/html/dev-certs/client.key

Generate dev certs:

mkdir -p dev-certs
./vendor/bin/sail exec laravel.test openssl req -x509 -newkey rsa:2048 \
    -keyout dev-certs/client.key \
    -out dev-certs/client.pem \
    -days 365 -nodes \
    -subj "/CN=Sail Dev/O=Local" \
    -addext "subjectAltName=URI:urn:sail-dev:client"

dev-certs/ is gitignored by default. Don't commit dev keys.

Running the daemon under Sail

The daemon is just a long-running PHP process — it runs inside the laravel.test container.

For interactive dev (start it when you need it):

./vendor/bin/sail artisan opcua:session

For backgrounded dev:

services:
  opcua-daemon:
    image: sail-8.4/app
    extends: laravel.test
    command: php /var/www/html/artisan opcua:session
    depends_on:
      opcua-test:
        condition: service_healthy
    volumes:
      - .:/var/www/html
    networks:
      - sail

Now sail up brings up Laravel, the OPC UA test server, AND the daemon. Three-container dev environment.

Connecting the dots

In .env (managed mode under Sail):

OPCUA_ENDPOINT=opc.tcp://opcua-test:4840
OPCUA_SESSION_MANAGER_ENABLED=true
OPCUA_SOCKET_PATH=/var/www/html/storage/framework/opcua-session-manager.sock

Both laravel.test and opcua-daemon see the same socket file via the shared . volume.

A first test

./vendor/bin/sail artisan tinker
> Opcua::isSessionManagerRunning()
=> true
> Opcua::read('i=2256')->value
=> 0

i=2256 is the standard Server_ServerStatus_State node — value 0 means "Running". If you see this, the dev stack is wired.

Trust-store flow under Sail

The trust store lives at storage/app/opcua/trust/. Under Sail, that's inside the laravel.test container but mapped to your host:

# laravel-opcua does not ship opcua:trust:add — use opcua-cli.
./vendor/bin/sail bash -lc \
    'OPCUA_TRUST_STORE_PATH=storage/app/opcua/trust \
      vendor/bin/opcua-cli trust:add opc.tcp://opcua-test:4841'

The cert lands in storage/app/opcua/trust/<hash>.pem. Both your host and the Sail container see it — convenient for editing during dev.

Auto-publish in dev

For dev work on subscription / event flow:

OPCUA_AUTO_PUBLISH=true

Restart the daemon:

./vendor/bin/sail restart opcua-daemon

Now Opcua::subscribe() fires Laravel events that your dev listeners receive.

Sail + Pest

Run tests as usual:

./vendor/bin/sail test                         # everything except Integration
./vendor/bin/sail test tests/Integration       # Integration with the live test server

The integration tests target opcua-test automatically because that's what .env points at.

Sail + Reverb

For broadcasting dev:

services:
  reverb:
    image: sail-8.4/app
    extends: laravel.test
    command: php /var/www/html/artisan reverb:start
    ports:
      - "${REVERB_PORT:-8080}:8080"
    volumes:
      - .:/var/www/html
    networks:
      - sail
REVERB_HOST=localhost              # browser-visible
VITE_REVERB_HOST=localhost
REVERB_PORT=8080

Run:

./vendor/bin/sail up -d
./vendor/bin/sail npm run dev      # Vite

Browse http://localhost. Real-time tag updates appear in the browser as the test server's CurrentTime ticks (or whatever tags you subscribe to).

Hot-reloading the daemon

PHP doesn't hot-reload. After editing daemon-touching code, kill and restart:

./vendor/bin/sail restart opcua-daemon

For listener changes, you don't need to restart the daemon — listener resolution happens per-event from the application's container, which gets re-bootstrapped each time.

Tearing down

./vendor/bin/sail down -v          # -v drops volumes too

For a clean slate including the trust store:

./vendor/bin/sail down -v
rm -rf storage/app/opcua/trust

CI parity

The same docker-compose.yml runs in CI. The CI workflow:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: docker compose up -d
      - run: docker compose exec -T laravel.test composer install
      - run: docker compose exec -T laravel.test php artisan test
      - run: docker compose down

Local dev and CI use the same fixtures — surprises are rare.

Other Sail-compatible test servers

Image When
ghcr.io/php-opcua/uanetstandard-test-suite:latest Full coverage (8 endpoints)
ghcr.io/php-opcua/extra-test-suite:latest open62541-backed, supports method calls
mcr.microsoft.com/iotedge/opc-plc:latest Microsoft's open-source PLC simulator

For most dev, the uanetstandard-test-suite is the right choice — it exercises every OPC UA feature the package supports.

Where to read next