Install PHP Ledger on a VPS
Follow a verifiable release-to-first-posting sequence on a server whose operating system and database are already maintained.
Start with a supported, prepared server
This procedure starts after an operator has installed a supported operating system, PHP and MySQL.
Use a patched PHP 8.3 runtime with the required extensions and MySQL 8.4 with InnoDB. PHP 8.2 remains the package floor. Do not assume the database installed by an operating system’s default package command is the tested MySQL release: it may be another version or MariaDB. Verify the actual server. This guide does not prescribe a distribution package repository, firewall policy or certificate provider. Those choices belong to the server operator and must be complete before application acceptance.
Record the person responsible for operating-system updates, database access, certificates, monitoring and recovery. A VPS gives you control over these jobs; it does not perform them automatically. Start in an isolated staging environment with synthetic data. Measure memory, disk and response times under the intended workload. No small-server capacity guarantee follows from a successful first login. Keep enough storage for the extracted release, its predecessor and a private backup.
Step 1: verify and extract the package
Use the customer release ZIP and its checksum, preserving the supplied directory layout.
sha256sum -c phpledger-0.4.0-preview.zip.sha256
unzip phpledger-0.4.0-preview.zip -d /srv/phpledger-releases
cd /srv/phpledger-releases/phpledger-0.4.0-preview
php -v
php -mThese shell commands assume the two downloaded files are in the current directory and the operator can write to the chosen release directory. Run each command separately and stop on failure. A successful checksum establishes agreement with the accompanying checksum file; obtain both from the project’s release location. The customer package includes production dependencies. A GitHub source archive is a different artifact and should not be treated as an installed customer package.
Keep the versioned directory name so that the running code can be identified later. Do not overwrite an existing release during extraction. Copying new code into a directory being served can expose a mixture of files while requests continue. A new release directory also makes it easier to retain the previous code beside the matching database backup.
Step 2: configure a dedicated database
Create an empty database and private configuration using the package’s installation instructions.
The migration account needs the documented table, trigger and view privileges within the application database. It should not share credentials with another website. Arrange a stable view definer: migration 016 creates source views whose definer must remain valid after installation. Removing a temporary migration account without checking the resulting views can break ordinary source reads even when the tables still exist. A restricted runtime account must be able to read the required views and their intended data.
cp www/phpledger/includes/config.local.example.php www/phpledger/includes/config.local.php
chmod 640 www/phpledger/includes/config.local.phpEdit the private copy with the intended host, port, database and unique nonempty credentials. File ownership and group membership must allow the PHP process to read it; mode 640 is not sufficient if the group is wrong. Configuration-file values override environment values, so inspect an existing configuration before relying on environment changes. Never paste the file into a support ticket. Keep application code read-only to the web process where the host permits it.
Step 3: serve only the public directory
Configure HTTPS and PHP handling, then point the virtual host at the application’s public directory.
DocumentRoot /srv/phpledger-releases/phpledger-0.4.0-preview/www/phpledger/public
<Directory /srv/phpledger-releases/phpledger-0.4.0-preview/www/phpledger/public>
Options -Indexes
AllowOverride None
Require all granted
FallbackResource /index.php
</Directory>This Apache fragment belongs inside an already configured HTTPS virtual host with working PHP handling. It does not install a certificate or connect Apache to PHP-FPM. The fallback sends application routes to the front controller while existing static files remain accessible. Confirm the PHP-FPM version as well as the shell version; separate pools can use different binaries. The package root, vendor, includes and installation tools must remain outside public routing.
apachectl configtest
sudo systemctl reload apache2The reload command assumes a systemd distribution whose service is named apache2. Use your distribution’s actual service name and only reload after the configuration test succeeds. Test a public asset, the login route and denied access to private paths. Disabling directory listings alone does not protect known private filenames. Document the active virtual host and release path for the next operator.
Which environment should the hosted installation use?
Set PL_ENV=production for both web and CLI PHP, and leave hosted-demo mode disabled.
Apply the environment through the server or hosting provider’s private configuration mechanism. Do not copy development credentials or the public demo’s reset scheduler into customer hosting. Confirm the effective setting before running installation commands. The optional read integrations need their separately documented public URL and private OAuth-key setup; ordinary browser installation does not configure those automatically.
Step 4: apply and verify the schema
Run preflight before migration and again afterward, retaining the resulting version and schema evidence.
php www/phpledger/install/preflight.php
php www/phpledger/install/migrate.php
php www/phpledger/install/preflight.phpFor a new database, the first preflight should identify an empty or recognized pending state. The supplied migration chain then creates the schema. The final check should report current schema. The 0.4.0-preview chain has 26 migration receipts, including nine additive migrations numbered 017–025. Stop if any command reports an unknown checksum, an interrupted receipt or an unexpected database. Never delete receipts or weaken immutability triggers to make installation continue.
An existing populated database needs the upgrade procedure instead of this empty-install shortcut. Stop writers and scheduled jobs, preserve a matched backup and rehearse migrations first. The currency backfill protects original posted values while adding domestic metadata. If interrupted, preserve its restrictive guard and recover using the reviewed procedure or the matched backup. Database DDL is not made safely reversible by wrapping the whole installer in a transaction.
Step 5: create the initial owner privately
Pass the password through standard input rather than placing it in command arguments or shell history.
set +x
IFS= read -r -s -p 'Initial user password: ' PL_INITIAL_PASSWORD
printf '\n'
printf '%s\n' "$PL_INITIAL_PASSWORD" | php www/phpledger/install/create-admin.php --email='owner@example.com' --name='Owner' --password-stdin
unset PL_INITIAL_PASSWORDThis example uses Bash and a fictional email address. Replace the address with the intended owner’s address and enter the password only at the hidden prompt. Do not run it under shell tracing or capture its private input in logs. Standard input reduces command-history exposure but does not replace a trusted terminal and sensible host access. Review the command result, then sign in over HTTPS and verify the intended company and book.
Step 6: accept a complete accounting path
Check a small synthetic posting and its reports, not only server connectivity.
In a new fictional book, a receipt of 1,000 and an expense of 125 through the same bank account should leave 875 in that account, assuming no other entries. Confirm the source records, dated journal lines and trial balance agree. A saved draft should not change posted reports. Check that another user cannot access a company without membership and the necessary permission. Follow the first-week guide for a fuller exercise.
The health endpoint proves database connectivity, not successful migrations, permissions, financial correctness or restored view access. Record the release version, runtime versions and actual smoke-check results. Keep any existing OAuth keys with the private configuration when preserving an installation; replacing them casually can invalidate integration credentials. Do not enable external dispatch merely because an event queue table exists. The foundation package includes no installed connector or automatic outbound delivery.
Step 7: establish the recovery handoff
Leave a tested backup, a named operator and an upgrade window before admitting real records.
- Store a private database backup with its matching release and configuration.
- Restore that set into an isolated environment and rerun preflight.
- Verify view reads, source records, reports and synthetic posting behavior.
- Record the recovery duration and the person who can repeat it.
Keep backup retention separate from the live disk. A backup that disappears with the VPS is a weak recovery plan. Set a review date for runtime support, certificates and storage growth. Decide how users will be told when writes are paused for an upgrade and who confirms the system can reopen.
When is a VPS the wrong choice?
Choose operational help when nobody can own server maintenance and recovery.
What should you do next?
A managed service may be a better fit than an unattended server. Hosting expertise also cannot supply missing application workflows: the starter includes core AR/AP, optional one-location Inventory/Purchasing and manual tax, but not regional filing, payroll or advanced warehouse operations. Evaluate those requirements separately from whether the installation runs.
Questions before you continue
Check these boundaries before applying the procedure to a business installation.
Does this install the whole operating system?
No. It starts with a maintained server, supported PHP and MySQL, HTTPS and an operator who manages them.
Can I roll back by changing the code directory?
After a schema change, restore the matched database and release together. A code-only rollback can leave an incompatible state.
Sources and next steps
Technical references and project behavior were checked on 16 September 2026; hosting access remains plan-specific.
- Package installation instructions
- Package upgrade and recovery instructions
- Apache front-controller fallback
- PHP-FPM installation reference
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.
