E-commerce AWS

Open Source Point of Sale 3.4.1 on AWS User Guide

| Product: Open Source Point of Sale 3.4.1 on Ubuntu 24.04 on AWS

Overview

This guide covers launching and using the Open Source Point of Sale 3.4.1 on Ubuntu 24.04 AMI from cloudimg on Amazon EC2. It is one version of the cloudimg e-commerce platforms listing on AWS Marketplace; you pick it as the software version when you subscribe and launch.

Open Source Point of Sale (OSPOS) is a web based point of sale and inventory management system for shops, cafes and small chains. It runs the till in a browser (barcode scanning, taxes, discounts, cash rounding and several payment types, receipts and invoices) and keeps items, item kits, stock locations, receivings, customers, suppliers, gift cards, expenses and cash ups in one place, with sales, inventory, tax and payment reports.

What the cloudimg image adds:

  • Ready to sign in. The database schema is loaded and fully migrated to 3.4.1 at build time, so the first page you open is the login page, not an installer or a migration prompt.
  • No default login. Upstream OSPOS seeds the well known admin / pointofsale login. On this image that password is replaced before the application ever runs, the image ships with the admin account disabled, and first boot gives it a password unique to your instance.
  • Secrets unique to your instance. The OSPOS admin password, the MariaDB password OSPOS uses and the application encryption key are generated on first boot and written to /root/opensourcepos-credentials.txt (root only). The image ships with the database account locked and no password or key in the configuration, and nginx and PHP-FPM refuse to start until first boot has finished.
  • HTTPS from the first boot. nginx serves OSPOS on port 443 with a certificate generated on your instance, port 80 redirects to HTTPS, requests for a host name the instance does not serve are dropped, and the session cookie is Secure and HttpOnly.
  • Only the application on the web. nginx serves the public/ directory only and runs exactly one PHP file, the application's front controller. Any other .php file, including anything uploaded, answers 404, and uploads are served as images only. OSPOS 3.4.1 ships with its own cross site request forgery filter switched off, so nginx refuses form posts that come from another web site.
  • Hardened defaults. MariaDB listens on 127.0.0.1 only. nginx, PHP-FPM, MariaDB and the first boot service are blocked from the instance metadata service, the AMI requires IMDSv2, and PHP is handed the configured host name and the real client address from the connection (never values a client sends).
  • Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.

What is on the image: Open Source Point of Sale 3.4.1 (the official release opensourcepos.3.4.1.5f395d.zip, checksum verified), nginx, PHP 8.3 FPM with OPcache, MariaDB, Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent.

Default user: ubuntu · Architecture: x86_64 · Recommended instance type: m5.large

Prerequisites

  • An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet with a route to the internet (or a private route you use for management).
  • A security group that allows TCP 22 (SSH) from your admin network, and TCP 443 (OSPOS) and TCP 80 (redirects to HTTPS) from the networks your tills and staff work from. Never open 3306.

Step 1: Launch the instance

In the AWS Marketplace listing choose Continue to Subscribe, then Continue to Configuration, pick Open Source Point of Sale 3.4.1 on Ubuntu 24.04 as the software version and your Region, then Launch through EC2. Choose m5.large, your key pair and a security group as above. The database lives on the root volume, so for production give the root volume room to grow (20 GiB or more).

With the AWS CLI (replace the values in angle brackets):

aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
  --instance-type m5.large --key-name <your-key-pair> \
  --security-group-ids <your-security-group> --subnet-id <your-subnet> \
  --block-device-mappings 'DeviceName=/dev/sda1,Ebs={VolumeSize=20,VolumeType=gp3}' \
  --metadata-options HttpTokens=required,HttpEndpoint=enabled \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=ospos}]'

First boot takes well under a minute after the instance is running.

Step 2: Connect to your instance

Version SSH user
Open Source Point of Sale 3.4.1 on Ubuntu 24.04 ubuntu
ssh -i <your-key.pem> ubuntu@<public-ip>

Step 3: Check the services

First boot sets the passwords, the encryption key and the certificate, then nginx and PHP-FPM start:

systemctl is-active nginx php8.3-fpm mariadb opensourcepos-firstboot
sudo test -f /var/lib/cloudimg/opensourcepos-firstboot.done && echo FIRSTBOOT_DONE

All four units are active and the first boot marker is present:

active
active
active
active
FIRSTBOOT_DONE

Only SSH and nginx listen on network ports; MariaDB listens on the loopback address and PHP-FPM uses a local socket:

sudo ss -lntp | awk 'NR>1 {print $4, $6}' | grep -v '127.0.0.5' | sort
0.0.0.0:22 users:(("sshd",...))
0.0.0.0:443 users:(("nginx",...))
0.0.0.0:80 users:(("nginx",...))
127.0.0.1:3306 users:(("mariadbd",...))
[::]:22 users:(("sshd",...))
[::]:443 users:(("nginx",...))
[::]:80 users:(("nginx",...))

Step 4: Get your URL and passwords

sudo cat /root/opensourcepos-credentials.txt

The file is readable by root only:

# Open Source Point of Sale 3.4.1 - generated on first boot by opensourcepos-firstboot.service
# These credentials are unique to this instance; none was baked into the image. Keep this file secret.

OSPOS_URL=https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/
OSPOS_ADMIN_USER=admin
OSPOS_ADMIN_PASSWORD=<OSPOS_ADMIN_PASSWORD>

MARIADB_DATABASE=ospos
MARIADB_USER=ospos
MARIADB_PASSWORD=<MARIADB_PASSWORD>

# The application encryption key (also in /var/www/opensourcepos/.env); OSPOS encrypts stored integration secrets with it.
OSPOS_ENCRYPTION_KEY=<OSPOS_ENCRYPTION_KEY>

# The certificate is self signed (minted on this instance); port 80 redirects to https.
# Change the name OSPOS is served as:  sudo opensourcepos-set-hostname <your-dns-name>
# MariaDB listens on 127.0.0.1 only; on-box maintenance: sudo mariadb
# User guide: https://www.cloudimg.co.uk/guides/open-source-point-of-sale-3-4-1-on-ubuntu-24-04-aws/

The URL uses the instance's public DNS name from the EC2 instance metadata. The certificate also names the public and private IP addresses, so https://<public-ip>/ works too, although OSPOS sends you to the configured name after you sign in. If you stop and start the instance without an Elastic IP, the boot service picks up the new address and issues a new certificate for it. To serve OSPOS under your own DNS name, see Step 8.

You only need the MariaDB password for your own tools; OSPOS already has it in /var/www/opensourcepos/.env. Keep the encryption key with your backups: OSPOS uses it for the integration secrets you save (for example the SMTP password and the Mailchimp API key).

Step 5: Sign in

Open the OSPOS_URL in your browser. The certificate is self signed, so your browser asks you to confirm it the first time (or install your own, Step 8). Sign in as admin with the password from Step 4:

The OSPOS login page with the Username and Password fields, the Go button and the Open Source Point of Sale footer

The home page has a tile for each module. The footer shows the version and the link to the project, which the OSPOS licence requires to stay on every page:

The OSPOS home page with the Customers, Items, Item Kits, Suppliers, Reports, Receivings, Sales, Gift Cards, Messages, Expenses, Cashups and Office modules and the opensourcepos.org 3.4.1 footer

You can also check the sign in from the instance. This script signs in through the real login form over HTTPS with the instance's password, then shows that a blank password, the upstream default pointofsale and common weak passwords are refused with OSPOS's "Invalid username and/or password" error:

sudo opensourcepos-cred-roundtrip.sh
OK per-instance admin signs in over HTTPS; blank, admin/pointofsale and weak guesses refused

Step 6: Set up your store

The image ships the upstream starting data: one employee, admin, whose person record is the placeholder John Doe, and the store details Open Source Point of Sale, 123 Nowhere street. There are no items, customers, suppliers or sales. Work through these first:

  1. Office, then Configuration, Information tab: your company name, address, phone, e-mail and logo.
  2. The General, Tax and Localization tabs: default tax rates, currency symbol, number and date formats and the time zone. Then Receipt, Invoice and Barcode for printed output.

The Configuration Information tab with the Company Name, Company Logo, Address, Website, Email and Phone fields and the General, Tax, Localization, Barcode, Stock, Receipt, Invoice, Reward, Table and Setup tabs

  1. Office, then Employees: edit the admin employee's name and e-mail, and add an employee for each person with only the modules they need.
  2. Items: add items one at a time with New Item, or load them from a spreadsheet with CSV Import. Item Kits bundle several items under one price.

The Items module with New Item, CSV Import, Bulk Edit and Generate Barcodes and an empty item table

  1. Sales is the register: scan or search for items, choose a customer if needed, take payment and print the receipt.

The Sales register with Register Mode, Find or Scan Item or Receipt, New Item, the cart, Select Customer and the total

Reports covers sales, items, customers, employees, payments, taxes, discounts and inventory, as graphs, summaries or detail:

The Reports module with the Graphical, Summary, Detailed and Inventory report lists

Step 7: E-mail (optional)

OSPOS can e-mail receipts and invoices. Set your SMTP relay under Office, Configuration, Setup & Conf, Email. Amazon SES works as the relay (port 587 with STARTTLS); allow outbound 587 in your security group or network ACLs if you restrict egress.

Step 8: Your own DNS name and certificate

Point a DNS record at the instance (an Elastic IP keeps the address stable), then set the name OSPOS is served as. This mints a new self signed certificate for the name, updates nginx, the host name OSPOS accepts (app.allowedHostnames in /var/www/opensourcepos/.env) and the URL in /root/opensourcepos-credentials.txt, and keeps the name across reboots:

sudo opensourcepos-set-hostname <your-domain>

To use a certificate from a public or internal certificate authority instead (for example one issued by Let's Encrypt for <your-domain>), copy it over the generated pair and reload nginx (running opensourcepos-set-hostname again replaces it with a self signed one):

sudo install -m 0644 <your-domain>.crt /etc/ssl/opensourcepos/opensourcepos.crt
sudo install -m 0600 <your-domain>.key /etc/ssl/opensourcepos/opensourcepos.key
sudo nginx -t && sudo systemctl reload nginx

Step 9: Security checks

nginx serves the application and its static files only. The configuration file, the application and vendor code and any PHP file other than the front controller answer 404, the licence stays readable, and plain HTTP redirects to HTTPS:

H=$(sudo grep '^OSPOS_URL=' /root/opensourcepos-credentials.txt | cut -d= -f2- | sed -E 's#https://([^/]+)/#\1#')
for p in /login /.env /app/Config/App.php /vendor/autoload.php /uploads/item_pics/test.php /license/LICENSE; do
  curl -sk -o /dev/null -w "%{http_code}  $p\n" --resolve "$H:443:127.0.0.1" "https://$H$p"
done
curl -s -o /dev/null -w 'http:// -> %{http_code} %{redirect_url}\n' --resolve "$H:80:127.0.0.1" "http://$H/"
[ "$(curl -sk -o /dev/null -w '%{http_code}' --resolve "$H:443:127.0.0.1" "https://$H/.env")" = "404" ]
200  /login
404  /.env
404  /app/Config/App.php
404  /vendor/autoload.php
404  /uploads/item_pics/test.php
200  /license/LICENSE
http:// -> 301 https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/

A form post from another web site is refused, and a request for a host name the instance does not serve gets no answer (curl reports 000):

H=$(sudo grep '^OSPOS_URL=' /root/opensourcepos-credentials.txt | cut -d= -f2- | sed -E 's#https://([^/]+)/#\1#')
curl -sk -o /dev/null -w 'cross-site post -> %{http_code}\n' --resolve "$H:443:127.0.0.1" -H 'Origin: https://evil.example' --data 'username=admin&password=x' "https://$H/login"
curl -sk -o /dev/null -w 'unknown host -> %{http_code}\n' --resolve "evil.example:443:127.0.0.1" https://evil.example/ || true
cross-site post -> 403
unknown host -> 000

OSPOS reports version 3.4.1 and every database migration has run:

grep "application_version =" /var/www/opensourcepos/app/Config/App.php
sudo mariadb -N -B ospos -e "SELECT COUNT(*) FROM ospos_migrations;"
    public string $application_version = '3.4.1';
40

The certificate was generated on this instance and names its own addresses:

H=$(sudo grep '^OSPOS_URL=' /root/opensourcepos-credentials.txt | cut -d= -f2- | sed -E 's#https://([^/]+)/#\1#')
echo | openssl s_client -connect 127.0.0.1:443 -servername "$H" 2>/dev/null | openssl x509 -noout -subject -ext subjectAltName
subject=CN = ec2-<public-ip-dashed>.compute-1.amazonaws.com, O = cloudimg
X509v3 Subject Alternative Name:
    DNS:ec2-<public-ip-dashed>.compute-1.amazonaws.com, IP Address:<public-ip>, IP Address:<private-ip>, IP Address:127.0.0.1, DNS:localhost

None of the services can reach the instance metadata service:

systemctl show nginx php8.3-fpm mariadb opensourcepos-firstboot -p Id -p IPAddressDeny
IPAddressDeny=fd00:ec2::254/128 169.254.169.254/32 168.63.129.16/32
Id=nginx.service

IPAddressDeny=fd00:ec2::254/128 169.254.169.254/32 168.63.129.16/32
Id=php8.3-fpm.service

IPAddressDeny=fd00:ec2::254/128 169.254.169.254/32 168.63.129.16/32
Id=mariadb.service

IPAddressDeny=fd00:ec2::254/128 169.254.169.254/32 168.63.129.16/32
Id=opensourcepos-firstboot.service

nginx hands PHP the configured host name and the client address from the connection, never values a client sends, and OSPOS accepts only the configured host name:

grep -E 'fastcgi_param (HTTP_HOST|HTTPS|HTTP_X_FORWARDED_FOR|HTTP_X_REAL_IP|HTTP_CLIENT_IP) ' /etc/nginx/sites-available/cloudimg-opensourcepos
sudo grep -E '^(CI_ENVIRONMENT|app\.allowedHostnames|app\.forceGlobalSecureRequests|cookie\.secure) ' /var/www/opensourcepos/.env
        fastcgi_param HTTP_HOST $ospos_host;
        fastcgi_param HTTPS on;
        fastcgi_param HTTP_X_FORWARDED_FOR $remote_addr;
        fastcgi_param HTTP_X_REAL_IP $remote_addr;
        fastcgi_param HTTP_CLIENT_IP $remote_addr;
CI_ENVIRONMENT = production
app.forceGlobalSecureRequests = true
app.allowedHostnames = 'ec2-<public-ip-dashed>.compute-1.amazonaws.com'
cookie.secure = true

Step 10: Changing passwords

  • OSPOS admin password: sign in as admin, open Office, Employees, edit the admin employee, open the Login tab, enter a new password twice and submit. Then update or delete OSPOS_ADMIN_PASSWORD in /root/opensourcepos-credentials.txt so it does not hold an old password.
  • Give each person their own employee login with only the modules they need, rather than sharing admin.
  • MariaDB password: only change it together with database.default.password in /var/www/opensourcepos/.env.
  • Encryption key: do not change encryption.key in .env once you have saved integration secrets; OSPOS could no longer read them.

Step 11: Backup and maintenance

The store database lives in MariaDB (/var/lib/mysql), item pictures and the company logo live under /var/www/opensourcepos/public/uploads, and the configuration (with the encryption key) is /var/www/opensourcepos/.env. The simplest backup is an EBS snapshot of the root volume. For a consistent file level copy while OSPOS is running:

sudo mariadb-dump --single-transaction --routines --triggers ospos | gzip > <backup-dir>/ospos-$(date +%F).sql.gz
sudo tar -czf <backup-dir>/ospos-files-$(date +%F).tar.gz -C /var/www/opensourcepos .env public/uploads

Operating system security updates install automatically; run sudo apt-get update && sudo apt-get upgrade to apply everything else. nginx, PHP-FPM and MariaDB restart cleanly and OSPOS keeps all of its data.

Component Path
OSPOS /var/www/opensourcepos (web root public/)
Configuration /var/www/opensourcepos/.env (mode 0640)
Item pictures and logo /var/www/opensourcepos/public/uploads
Sessions, logs and cache /var/www/opensourcepos/writable
Database MariaDB database ospos (/var/lib/mysql)
nginx site /etc/nginx/sites-available/cloudimg-opensourcepos
Certificate and key /etc/ssl/opensourcepos/
Boot service /usr/local/sbin/opensourcepos-firstboot.sh
Host name helper /usr/local/sbin/opensourcepos-set-hostname
Credentials /root/opensourcepos-credentials.txt (mode 0600)

Step 12: Security recommendations

  • Allow port 22 from your admin network only, and ports 80 and 443 only from the networks your tills and staff work from. Never open 3306.
  • Use your own DNS name and a certificate your browsers trust (Step 8).
  • Give each person their own employee login, and change the admin password if it may have been shared (Step 10).
  • Keep the operating system patched, and snapshot the root volume regularly.

Support and licensing

Open Source Point of Sale is open source under the MIT licence, with the project's additional condition that the footer signature (version, commit and the opensourcepos.org link) stays visible and unmodified on every page; this image ships it unchanged. There is no per user or per till licence fee. The AMI price covers cloudimg's hardening, first boot setup and support.

  • Email: support@cloudimg.co.uk
  • Website: https://www.cloudimg.co.uk
  • Support: 24/7, with a 24 hour response SLA