Install with Docker
Docker runs POSMaster and its database in ready-made containers, so you do not install PHP, Apache or MySQL yourself. It is a good choice for a VPS, a test server, or a computer that already has Docker.
You need Docker with Docker Compose v2 (the docker compose command). On Windows and Mac, install Docker Desktop. On Linux, install Docker Engine and the Compose plugin.
Quick start
Open a terminal in the folder that contains docker-compose.yml, then run these two commands.
- Build and start everything:
docker compose up -d --build
The first build takes a few minutes, because Docker downloads PHP, Apache and MariaDB and installs the PHP extensions.
- Install POSMaster. Pick one:
# Demo shop with sample products and sales
docker compose exec -u www-data app php artisan pos:install --demo
# Or a clean shop (asks for your Super Admin name, email and password)
docker compose exec -u www-data app php artisan pos:install
- Open http://localhost:8080 and sign in.
With --demo the Super Admin is superadmin@posmaster.test with the password password.
Warning:
pos:install --demowipes the database before loading the demo shop. Never run it on a shop with real data.
Note: If the second command says it cannot connect to the database, wait 20 seconds and try again. The database needs a moment to start on the first run. The app waits for it automatically.
Warning: Always run
php artisanin the container with-u www-data, as shown. Without it, files are created as root, the web server can no longer write its cache, and pages show an error.
What Docker starts
docker-compose.yml defines three services:
| Service | What it does |
|---|---|
app |
PHP 8.2 with Apache. Serves POSMaster on port 8080. On start it creates the app key, waits for the database, and creates the storage link. |
scheduler |
Runs php artisan schedule:work. It handles the nightly demo reset when you turn it on. |
db |
MariaDB 10.11 with the utf8mb4 character set and utf8mb4_unicode_ci collation. |
The app is configured through environment variables set in the compose file, so you do not need a .env file inside the container. APP_ENV is production and APP_DEBUG is false. Logs go to the container output.
You do not need to create the app key. The first start creates a random key and keeps it in the storage volume, so it stays the same as long as that volume exists.
Change the settings (.env.docker)
The defaults work for a first try. For anything real, change at least the passwords. Create your own settings file:
cp .env.docker.example .env.docker
Edit .env.docker:
POS_PORT=8080
POS_APP_URL=http://localhost:8080
POS_DB_DATABASE=posmaster
POS_DB_USERNAME=posmaster
POS_DB_PASSWORD=change-me
POS_DB_ROOT_PASSWORD=change-me-too
POS_DEMO_LOCK=false
POS_DEMO_RESET_NIGHTLY=false
Then start with the file:
docker compose --env-file .env.docker up -d --build
| Setting | Meaning |
|---|---|
POS_PORT |
The port on your computer. Use 80 to open the app without a port number. |
POS_APP_URL |
The address people type. Set it to your real domain, for example https://shop.example.com. |
POS_DB_DATABASE, POS_DB_USERNAME, POS_DB_PASSWORD |
The database name, user and password |
POS_DB_ROOT_PASSWORD |
The password of the database root user |
POS_DEMO_LOCK |
true forces demo mode on and hides the switch. See below. |
POS_DEMO_RESET_NIGHTLY |
true resets the demo data every night at 00:00 |
Warning: The database password is saved in the database volume the first time it is created. If you change
POS_DB_PASSWORDlater, the existing database does not follow. Set the passwords before the first start. To change them afterwards you must either change them inside the database or remove the database volume, which deletes all data.
Tip: Use the same
--env-file .env.dockeroption every time you rundocker compose up,downorbuild. Otherwise Compose falls back to the defaults.
Public demo server
To run a public demo that visitors cannot damage:
- Put these in
.env.docker:
POS_DEMO_LOCK=true
POS_DEMO_RESET_NIGHTLY=true
- Start the containers and install the demo:
docker compose --env-file .env.docker up -d --build
docker compose exec -u www-data app php artisan pos:install --demo
With POS_DEMO_LOCK=true, demo mode is always on. Nobody, not even the Super Admin, can switch it off or change protected settings. With POS_DEMO_RESET_NIGHTLY=true, the scheduler service wipes and reloads the demo data at 00:00 every night.
Data and volumes
Docker keeps your data in two named volumes. They survive restarts and rebuilds.
| Volume | Holds |
|---|---|
db |
The MariaDB database files |
storage |
Uploaded pictures, logs, the app key and the cache |
Compose adds your folder name in front, so the real names look like pointofsales_db. List them with docker volume ls.
Warning:
docker compose down -vdeletes the volumes and all your data. Plaindocker compose downis safe.
Look at the logs
# Follow the app log (press Ctrl+C to stop following)
docker compose logs -f app
# Database and scheduler
docker compose logs -f db
docker compose logs -f scheduler
Application errors are written to the app container's output, because the log channel is stderr.
Stop, start and restart
docker compose stop # stop, keep everything
docker compose start # start again
docker compose restart app # restart one service
docker compose down # remove the containers, keep the data
docker compose ps # see what is running
The containers are set to restart: unless-stopped, so they come back after a server reboot.
Back up the database
Create a SQL dump of the database on your computer:
docker compose exec db sh -c 'mariadb-dump -u"$MARIADB_USER" -p"$MARIADB_PASSWORD" "$MARIADB_DATABASE"' > posmaster-backup.sql
This uses the user, password and database name that are already set inside the db container, so you do not have to type them. Put the date in the file name to keep several copies.
Also copy the uploaded pictures:
docker compose cp app:/var/www/html/storage/app/public ./backup-public
Restore a backup
- Make sure the containers are running.
- Load the dump:
docker compose exec -T db sh -c 'mariadb -u"$MARIADB_USER" -p"$MARIADB_PASSWORD" "$MARIADB_DATABASE"' < posmaster-backup.sql
- Copy the pictures back if you need them:
docker compose cp ./backup-public/. app:/var/www/html/storage/app/public
See Update, backup and restore for a full backup plan.
Update to a new version
- Make a backup first (see above).
- Replace the project files with the new version. Keep your
.env.docker. - Rebuild and restart:
docker compose --env-file .env.docker up -d --build
- Run the database migrations and clear the cache:
docker compose exec -u www-data app php artisan migrate --force
docker compose exec -u www-data app php artisan optimize:clear
Your data is safe, because it lives in the volumes and not in the image.
Useful commands
# Open a shell inside the app container
docker compose exec app sh
# Run any artisan command
docker compose exec -u www-data app php artisan about
# Reset the demo data now (only while demo mode is on)
docker compose exec -u www-data app php artisan pos:demo-reset
Troubleshooting Docker
- "Database not reachable." in the app log. The app waited two minutes and the database never answered. Check
docker compose logs db. A wrong password in.env.dockerafter the first start is the usual cause. See Troubleshooting. - Port 8080 is already in use. Set a different
POS_PORT, for example8081, and updatePOS_APP_URLto match. - Pictures do not show. Check that
POS_APP_URLis exactly the address in your browser. - Slow on Windows. Use Docker Desktop with the WSL 2 backend.