Use PHP Ledger locally with Docker
Docker provides the project’s local development and test environment. Keep that boundary explicit when evaluating the preview.
What does the repository Compose stack provide?
The supplied Compose stack is a local development and test environment, not a maintained production appliance.
Docker is useful when you want a repeatable local PHP and MySQL environment without installing those services directly on your workstation. The repository defines web, database, static website and isolated test services. Their existence does not mean that production HTTPS, remote backups, operating-system maintenance or a hosted support agreement are included. For a customer installation, use the packaged release instructions and an operator-managed server.
Begin with a trusted checkout of the intended revision. Keep synthetic data in development. A bind mount exposes the local source tree to the container, so changing a file can change the running application immediately. This is helpful for development but differs from a reviewed release directory. Record the commit being tested and keep unrelated working changes out of claims about a release. A test that passed on one revision does not automatically cover later edits.
Step 1: check Docker and the checkout
Confirm the Compose command is available and identify the exact code before starting services.
docker compose version
git status --short
git rev-parse HEADRun these commands from the repository root. They read the local state; they do not prepare a production installation. On a workstation, Docker Desktop or a compatible Docker Engine setup must already be running. Review the project’s Compose file before using it on a shared machine, especially published ports and mounted directories. Local services should not be exposed to the public internet as a shortcut for remote access.
If a local environment file already exists, preserve it. For a genuinely new checkout, copy the supplied environment example and privately set the required database passwords. Use separate randomly generated development values. Do not publish an expanded Compose configuration or paste an environment file into an issue: either may reveal secrets. Container environment settings and PHP’s private configuration file are separate layers, and a private PHP configuration can override the environment.
Step 2: start the local services
Build the development stack, then check its actual PHP runtime and application prerequisites.
docker compose up -d --build
docker compose ps
docker compose exec -T web php -v
docker compose exec -T web php www/phpledger/install/preflight.phpRun each command separately and inspect its result. An image build may require downloading base images or dependencies if they are not cached. Container startup is not application installation: a database can be healthy while the schema is still empty. The preflight command checks the application’s prerequisites and recognized migration state. Stop if it identifies an unexpected database or unsupported schema rather than assuming a restart will repair it.
The checkout’s local application endpoint uses port 18200, and the static website service uses port 18201. These are different surfaces. A working marketing homepage does not establish that the accounting application can connect, authenticate or post. Confirm the ports in the checked-out Compose file if you use another revision. Do not change a production reverse proxy merely to mirror these development addresses.
Step 3: install the application schema
Apply migrations to the intended local application database and verify that the schema is current.
docker compose exec -T web php www/phpledger/install/migrate.php
docker compose exec -T web php www/phpledger/install/preflight.phpThe installer keeps migration receipts and checks their expected definitions. Repeating a successful migration run skips matching work. An interrupted or mismatched receipt requires investigation; deleting it is not a normal retry procedure. The development database volume survives ordinary container recreation, so rebuilding an image does not make that database empty and does not replace migration checks.
Before using these commands against an existing development database, decide whether its synthetic data needs a backup. Do not point the test harness at the development application database. Do not resolve installation problems by changing database connection settings until they happen to reach a server: identify which server, database and account are intended first. This becomes especially important when several project stacks run on the same workstation.
Step 4: create the local owner and check posting
Use the package’s standard-input password option through the web container, then inspect a complete synthetic transaction.
set +x
IFS= read -r -s -p 'Initial user password: ' PL_INITIAL_PASSWORD
printf '\n'
printf '%s\n' "$PL_INITIAL_PASSWORD" | docker compose exec -T web php www/phpledger/install/create-admin.php --email='owner@example.test' --name='Local Owner' --password-stdin
unset PL_INITIAL_PASSWORDThis is a Bash example with a fictional email address. The hidden prompt keeps the password out of command arguments; use a trusted terminal with tracing disabled. Open the local login route, sign in and create or select the intended fictional company. Do not assume an existing sample company starts at zero. Use a new empty company for exercises whose expected balances rely on an empty book.
A synthetic receipt of 1,000 and expense of 125 should leave 875 in the selected bank account if those are its only entries. Review the sources and trial balance as well as the screen confirmation. Save a draft and confirm it does not change posted reports. These checks establish a small exercised path; they do not amount to accounting review or prove every feature works.
Step 5: use the isolated test profile
Run the repository checks against the dedicated test service, keeping its data separate from application records.
docker compose --profile test run --rm test composer checkThe check command runs the project’s configured lint, static analysis, sample validation and tests. Review its exit status and complete summary. The test database is intentionally disposable and restricted by the harness’s environment checks. Never override those checks to run the suite against a business database. When dependencies or the Dockerfile change, rebuild the appropriate image so that its vendor tree matches the lock file being evaluated.
| Component | Purpose | Operational consequence |
|---|---|---|
| Source checkout | Editable application and website files | A local edit can change the running code |
| Application database volume | Persistent development records | Rebuilding a container does not erase its schema |
| Private application volume | Private runtime material | Preserve required keys when preserving an installation |
| Test database | Synthetic disposable test state | Keep it isolated from development and business data |
| Static website service | Marketing pages | Its availability says nothing about accounting posting |
When is Docker the wrong deployment route?
Use the customer package when you need the documented hosted installation rather than a development stack.
What should you do next?
Container familiarity does not remove the need for backup ownership, TLS, patching and release control. The repository stack should not be advertised as a production-ready appliance. If you adapt it for hosting, that adaptation needs its own deployment review and recovery evidence. In particular, a volume is storage, not an off-server backup, and a successful image build does not demonstrate that a populated database can be upgraded safely.
For local learning, the stack is useful because the environment can be inspected and tests can run without business records. Keep its purpose explicit. When moving from an experiment to a business pilot, select a reviewed release, perform a fresh installation or supported upgrade, and follow the same acceptance and restoration checks as any other hosting route.
Questions before you continue
Check these boundaries before applying the procedure to a business installation.
Is this a production Docker appliance?
No. The repository supplies a local development and test stack; a hosted container deployment needs separate operational review.
Does rebuilding reset the database?
No. Persistent database volumes remain across ordinary container recreation. Apply the versioned migrations to the intended database.
Sources and next steps
Technical references and project behavior were checked on 16 September 2026; hosting access remains plan-specific.
- Docker Compose getting started
- Repository Compose services
- Development and test commands
- Package installation instructions
The linked project files describe the current preview. Follow the instructions inside your exact downloaded package if a later release changes a command. Technical testing does not establish statutory compliance or independent accounting acceptance. See the project and preview limits.
