Docker
Run WemX with Docker Compose, with the web server, queue worker, scheduler and database included.
The WemX repository ships with a production-ready Docker setup. One docker compose up gives you:
| Container | What runs inside |
|---|---|
app | Nginx, PHP-FPM 8.3, the queue worker and the scheduler, managed by Supervisor |
db | MariaDB 11.4 |
All data lives in named Docker volumes, so you can rebuild or update the containers without losing anything.
WemX v3 is in beta and needs a license key. Get a free key at app.wemx.net.
Requirements
- Docker Engine 24+ with the Compose plugin (
docker compose version) - 1 GB of RAM or more
- A domain name and a reverse proxy for HTTPS in production (see HTTPS)
Installation
Get the code.
git clone https://github.com/wemxnet/wemx.git
cd wemxCreate your configuration. Copy the example and edit it:
cp docker/wemx.env.example docker/wemx.env
nano docker/wemx.envAt a minimum, set:
APP_URL: the address you'll open WemX on, for examplehttps://billing.example.comDB_PASSWORDandMARIADB_PASSWORD: the same long, random passwordMARIADB_ROOT_PASSWORD: a different long, random passwordFORCE_HTTPS=trueif WemX will be served over HTTPS
Build and start the containers.
docker compose up -d --buildThe first build takes a few minutes. It installs the PHP and Node dependencies and compiles the frontend assets. Follow the logs with:
docker compose logs -f appRun the web installer. Open your APP_URL (by default http://localhost:8080). The installer checks the requirements, then asks for your database. The values from wemx.env are already filled in, so choose MySQL and continue. Then create your admin account and enter your license key.
Restart once after installing. This makes the queue worker and scheduler pick up the new configuration straight away:
docker compose restart appWemX is ready. Continue with First steps.
How it works
Configuration and the .env file
WemX reads its configuration from two places:
- Container environment variables from
docker/wemx.env. These always win. - The
.envfile, which the web installer and the license page write to. It's stored on thewemx-configvolume at/config/.envand linked into the application.
On first start the container creates /config/.env and generates a unique APP_KEY. This key encrypts your gateway and server credentials, so back it up:
docker compose cp app:/config/.env ./wemx-env-backupVolumes
| Volume | Mounted at | Contains |
|---|---|---|
wemx-config | /config | The .env file, including APP_KEY |
wemx-storage | storage/ | Logs, cache and uploaded files |
wemx-extensions | extensions/ | Extensions installed from the marketplace |
wemx-assets | public/assets/ | Theme assets and images uploaded in the admin area |
wemx-db | /var/lib/mysql | The MariaDB database |
On every start the container refreshes the extensions and theme assets that ship with the image, and leaves everything you installed or uploaded alone.
Background processes
The app container runs the queue worker and scheduler for you, so there's no cron or systemd setup. The admin dashboard warns you if the queue worker stops.
To run them in separate containers instead, set WEMX_RUN_QUEUE=false or WEMX_RUN_SCHEDULER=false and start extra containers from the same image with php artisan queue:work or php artisan schedule:work as the command. They need the same volumes and environment.
Database migrations
Once WemX is installed, the container runs php artisan migrate --force on every start, so new database tables are created automatically after an update. Set WEMX_AUTO_MIGRATE=false to do this yourself.
HTTPS and reverse proxies
The app container serves plain HTTP on port 8080 on the host (change it with WEMX_HTTP_PORT). In production, put a reverse proxy in front of it to handle TLS, and set FORCE_HTTPS=true and an https:// APP_URL in wemx.env. WemX already trusts forwarded headers from proxies.
Caddy obtains certificates automatically:
billing.example.com {
reverse_proxy 127.0.0.1:8080
}server {
listen 443 ssl http2;
server_name billing.example.com;
# ssl_certificate / ssl_certificate_key …
client_max_body_size 32m;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Remove the ports section from the app service, attach it to your Traefik network, and add labels:
services:
app:
labels:
- traefik.enable=true
- traefik.http.routers.wemx.rule=Host(`billing.example.com`)
- traefik.http.routers.wemx.entrypoints=https
- traefik.http.routers.wemx.tls.certresolver=letsencrypt
- traefik.http.services.wemx.loadbalancer.server.port=80
networks: [proxy, default]
networks:
proxy:
external: trueUpdating
In Docker, update by rebuilding the image rather than with the in-app updater. Changes made by the updater inside a container are lost when the container is recreated.
# 1. Back up the database
docker compose exec db sh -c 'mariadb-dump -u root -p"$MARIADB_ROOT_PASSWORD" "$MARIADB_DATABASE"' > wemx-backup.sql
# 2. Get the new version and rebuild
git pull
docker compose up -d --buildMigrations run automatically on start-up. To pin a release, check out its tag first (for example git checkout v3-beta-0.1.1) and pass the version to the build so it shows in the admin area:
docker compose build --build-arg WEMX_VERSION=v3-beta-0.1.1 && docker compose up -dUseful commands
docker compose ps # status and health
docker compose logs -f app # application, queue and scheduler logs
docker compose exec -u www-data app php artisan … # run any Artisan command
docker compose exec -u www-data app php artisan extension:list
docker compose down # stop (data is kept in volumes)docker compose down -v deletes all volumes, including your database and APP_KEY. Only use it to start over.
Using an external database
To use a managed MySQL or PostgreSQL server instead of the bundled MariaDB, remove the db service and the depends_on block from docker-compose.yml, and point the DB_* variables in wemx.env at your server, for example DB_CONNECTION=pgsql and DB_PORT=5432.
Troubleshooting
| Problem | Fix |
|---|---|
Styles or links point to https:// while testing on http://localhost | Set FORCE_HTTPS=false and restart. |
| Payment gateways redirect to the wrong address | Make sure APP_URL matches the public URL exactly, then restart. |
| Queue worker is not running on the dashboard | Run docker compose logs app and look for queue errors. Before installation the worker restarts until the database tables exist, which is expected. |
| Uploads fail for large files | Raise client_max_body_size in docker/nginx.conf and the upload limits in docker/php.ini, then rebuild. |
| "Cannot locate .env file" during installation | The wemx-config volume isn't mounted. Check the volumes section of the app service. |