For the complete documentation index, see llms.txt. This page is also available as Markdown.

Via Docker Compose

Run UXWizz, its database, and scheduled tasks with Docker Compose.

You need:

  • A server with Docker and the Compose plugin, using Linux containers.

  • Terminal access with permission to create containers and volumes. These commands use Bash and OpenSSL.

  • A hostname and an HTTPS reverse proxy for public access.

Video walkthrough

Create the Compose files, start UXWizz and add the tracking code

Watch the Docker Compose installation video. English captions are also available.

Running UXWizz via docker compose

  1. Create a private working directory outside your web root:

    umask 077
    mkdir uxwizz
    cd uxwizz
  2. Copy and run this command to create .env with random passwords and an application key:

    Create .env
    (
      umask 077
      set -euC
      db_password=$(openssl rand -hex 32)
      root_password=$(openssl rand -hex 32)
      app_key=$(openssl rand -base64 32)
      printf 'UXWIZZ_DB_PASSWORD=%s\nUXWIZZ_DB_ROOT_PASSWORD=%s\nUXWIZZ_APP_KEY=%s\n' \
        "$db_password" "$root_password" "$app_key" > .env
    )

    The command keeps the values private and stops if .env already exists. Do not share this file in support messages.

  3. Save this as compose.yml in the same directory:

Copy the complete compose.yml file
  1. Validate the configuration, then start the services:

    All three services should be running. The database should show healthy.

config --quiet checks for missing settings without printing secrets.

Accessing UXWizz

Connect your hostname

  1. Configure your HTTPS reverse proxy. Replace stats.example.com with your hostname.

    Setting
    Value

    Public address

    https://stats.example.com

    Forward to

    http://127.0.0.1:8000

    Keep port 8000 private. All public traffic must pass through your proxy. Configure it to:

    • Replace forwarded client-IP and protocol headers with values it determines.

    • Preserve the Host header and forward Authorization.

  2. Add these lines to .env, using your hostname:

  3. Apply the changes:

    Use up -d after editing .env; restart does not load new values.

My reverse proxy runs in another container

Connect the proxy to the same Docker network as webserver. Forward requests to http://webserver:80 instead of the host address above.

Inside a container, 127.0.0.1 points to that container itself.

I only want to try UXWizz locally

Skip the hostname and proxy settings. Open http://localhost:8000/server/install.php in a browser on the Docker host.

Use a separate test password. Set up HTTPS before making UXWizz publicly accessible.

Complete setup

  1. Open the setup page, using your hostname:

  2. Create an administrator password of at least 12 characters, then sign in as admin. The database is already configured.

  3. Add the tracking code to your website.

  4. Visit your website and check that the visit appears in Visitors.

Check scheduled tasks

Open Settings → Scheduled Tasks. Check Next run for active tasks, then check Runs after a task is due.

An empty history is normal until an enabled task is due. The scheduler starts checking after browser setup is complete.

Troubleshooting and updates

Run these commands on the server:

  • Database connection error: check the shared application credentials. Changing .env does not change passwords inside an existing MariaDB volume. Restore the correct settings or have the database administrator rotate them deliberately.

  • No task history: complete setup and check Next run in Settings → Scheduled Tasks. If an active task is overdue, inspect scheduler logs. A stopped container needs server access.

  • Permission error: check the affected volume and PHP ownership. Do not use world-writable permissions.

  • Address already in use: choose an unused UXWIZZ_HTTP_PORT and update the reverse-proxy target.

Stop or update UXWizz

Use docker compose stop to pause the services. Use docker compose down to remove the containers while keeping named volumes.

Do not add -v: it deletes the stored data.

Back up .env, the html volume, and a consistent database backup before updating. Keep the Compose project name and volume names. Update application files through Settings → Updates; pulling a new image does not replace files already in html. Do not switch an existing standalone container to Compose without a planned migration.

Advanced: change the default settings

Add only the settings you need to .env:

Setting
Default
When to change it

UXWIZZ_HTTP_PORT

8000

The host port is already in use. Update your proxy target too.

UXWIZZ_IMAGE_TAG

10

You need a specific published image tag.

UXWIZZ_DB_NAME

uxwizz

You need another database name.

UXWIZZ_DB_USER

uxwizz

You need another database user.

Database settings initialize a new database only. Editing .env does not rename an existing database or change its users and passwords.

Tip: Using Bind Volumes

To use host folders with the Compose setup above, follow the steps below. Run the commands beside compose.yml, in a dedicated directory outside your web root. This needs server access.

Prepare the application folder for a new installation

Create an empty application folder:

Then add the mounts in the next section. On first startup, the webserver image copies the application into the empty ./html bind mount. Manual copying is optional for this new application folder. Separate PHP/Apache configuration mounts need the preparation described below.

For an existing named volume, use the migration steps below. Use a new empty folder for a new installation; do not delete files from an existing folder.

Optional: copy the application before first startup

Use this if you need the application files on the host before the first startup. Run it instead of the mkdir command above, using the same image tag as your Compose file:

The final check must succeed. The /. copy includes hidden files such as .htaccess. If html already exists, the commands stop without changing it. Inspect that folder before continuing.

The temporary container is never started. docker rm -v "$seed" removes only that container and its unused anonymous volume. If copying fails, keep the partial folder for diagnosis and remove the temporary container when finished.

Use the folder in Compose

Replace html:/var/www/html with ./html:/var/www/html in both services. Keep the other service settings:

This is a fragment to merge into your existing file, not a complete Compose file. The scheduler must see the same application files as the web server.

Check browser setup and Settings → Scheduled Tasks as described above. The image sets application ownership to www-data and directory/file modes to 0750/0640 on startup. This also changes the host folder's ownership and permissions on Linux.

Move an existing installation from a named volume

Migration steps and rollback

Use the existing container's files, including its configuration and installed marker. Do not seed an existing installation from a clean image.

  1. Back up the application volume, .env, and database. Confirm you can restore them. Plan a short tracking interruption.

  2. Stop application writes and copy the files from the stopped web container:

  3. Check that the copy includes the original configuration and server/storage/installed.php. Keep the original named volume and its declaration for rollback.

  4. Change the HTML mount in both services, validate Compose, and start them as above. Confirm sign-in, existing reports, a new visit, and task history. If setup asks you to create a new administrator, stop: the existing installation was not copied correctly.

  5. If the checks fail, stop both services, restore their original named-volume mounts, and start them again. Keep the failed copy for diagnosis. Visits received after the switch may need recovery; do not merge the two folders blindly.

Bind-mount PHP, Apache, or database files

Prepare custom configuration and database mounts

You can also keep these files on the host. Prepare each source before adding its mount.

Copy the supplied PHP settings and default Apache site from another temporary, unstarted webserver container:

Then add the mounts you need to webserver.volumes:

Also mount the PHP file in scheduler if its CLI settings need to match. For an existing deployment, copy its actual configuration instead of the image defaults. Apache's sites-enabled directory can contain symlinks; copy each enabled site's target as a regular file so links do not point to missing host files. Do not mount a missing php.ini path: Docker's short mount syntax can create a directory where PHP expects a file.

Validate edited configuration before restarting:

For a new, empty database only, create ./mysql_data and replace mysql_data:/var/lib/mysql in db.volumes with ./mysql_data:/var/lib/mysql. MariaDB initializes that directory and may change its ownership. For an existing database, use a verified database backup and restore procedure, or an administrator's offline physical migration for the exact database version. Copying a running database's files is not a consistent backup.

See Docker's bind-mount reference for host-path behavior and platform-specific permissions.

Last updated

Was this helpful?