> ## Documentation Index
> Fetch the complete documentation index at: https://docs.erp.arukz.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Run ARUKZ ERP on Docker

> Run your own copy of ARUKZ ERP in one Docker container with nginx, PHP-FPM, MySQL, a queue worker and the scheduler, and install it on a new database.

You can run a copy of ARUKZ ERP in one Docker container that holds nginx, PHP-FPM, MySQL, a queue worker and the scheduler under Supervisor, with a TLS proxy in front. The container runs your checkout of the code; a new database is set up with `erp:install` and the module install commands. Most customers do not need any of this: ARUKZ runs the hosted service at [erp.arukz.com](https://erp.arukz.com), with backups and upgrades included.

> [!NOTE]
>
> The ARUKZ ERP source is proprietary to ARUKZ DIGITAL (Aureus ERP's parts are MIT-licensed). These steps are for developers working on the code and for anyone running a copy under an agreement with ARUKZ.

## What you need

* Docker with Compose, on a Linux server with at least 4 GB of memory.
* A checkout of the repository, with `composer install` and `npm ci && npm run build` already run in it (the container serves `vendor/` and `public/build/` from the checkout).
* A domain name and a reverse proxy that terminates HTTPS (Caddy, nginx, a load balancer or a tunnel). The image has no TLS of its own.

## The container

The runtime image is `webkul/aureuserp:latest`: Ubuntu 24.04 with PHP 8.4, nginx, PHP-FPM and MySQL 8.0. Your checkout is mounted over the application folder, and the repository's own Supervisor file replaces the image's so the queue worker gets enough memory. `docker-compose.prod.yml` in the repository is the file ARUKZ uses; a minimal version for your own server:

```yaml theme={"theme":{"light":"github-light","dark":"github-dark"}}
services:
  erp:
    image: webkul/aureuserp:latest
    restart: unless-stopped
    ports:
      - "127.0.0.1:18180:80"          # your TLS proxy forwards to this
    env_file: .env
    volumes:
      - .:/var/www/aureuserp
      - erp-mysql-data:/var/lib/mysql
      - ./docker/production/supervisord.conf:/etc/supervisor/conf.d/aureus.conf:ro
      - ./docker/production/healthcheck.sh:/usr/local/bin/arukz-healthcheck:ro
      - ./docker/production/db-credentials.sh:/usr/local/bin/arukz-db-credentials:ro
    healthcheck:
      test: ["CMD", "/usr/local/bin/arukz-healthcheck"]
      interval: 60s
      start_period: 120s

volumes:
  erp-mysql-data:
```

With `DB_HOST` left at `127.0.0.1`, MySQL runs inside the container and its data stays in the named volume. Point `DB_HOST` at another server to use an external MySQL 8 instead.

## Settings

Copy `.env.example` to `.env` and set at least these:

| Setting | Example | Why |
| - | - | - |
| `APP_KEY` | `php artisan key:generate --show` | Encrypts sessions and stored secrets; keep it stable and backed up |
| `APP_URL` | `https://erp.example.in` | The public address |
| `APP_ENV` | `production` | Forces HTTPS links; use `local` only for testing over plain HTTP |
| `APP_TRUSTED_HOSTS` | `erp.example.in` | The host names the app answers; others are refused |
| `DB_DATABASE`, `DB_USERNAME`, `DB_PASSWORD` | | The database |
| `MAIL_MAILER` and `MAIL_*` | `smtp` | With the default `log`, password resets never reach anyone |
| `SAAS_PATH_ROUTING` | `true` | Each company signs in at `/<company>/admin` |
| `SAAS_SUBDOMAIN_ROUTING` | `false` | Turn on only with wildcard DNS and a wildcard certificate |
| `API_RATE_LIMIT`, `SANCTUM_TOKEN_EXPIRATION` | `120`, `43200` | API requests a minute per user; token lifetime in minutes (30 days) |
| `SAAS_BACKUPS_KEEP`, `SAAS_OPS_EMAIL` | `14` | Nightly backups kept; who is emailed when a backup fails |

Config is cached in production, so a changed `.env` does nothing until the caches are rebuilt.

## Install on a new database

Run these inside the container as `www-data`, the user PHP-FPM runs as. They are the steps of `docker/k8s/release.sh`, which ARUKZ's Kubernetes setup runs on every deploy.

**1. Install the ERP**

`erp:install` migrates, seeds and creates the first admin. It runs `migrate` without `--force`, so run it with `APP_ENV=local`:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
docker compose exec -u www-data erp sh -c 'cd /var/www/aureuserp && php artisan config:clear && \
  APP_ENV=local php artisan erp:install --force --no-interaction \
  --admin-name="Administrator" --admin-email="you@example.in" --admin-password="choose-a-strong-one"'
```

**2. Install the ARUKZ modules and roles**

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
docker compose exec -u www-data erp sh -c 'cd /var/www/aureuserp && php artisan migrate --force && \
  for m in compliance documents procurement ai accounting-controls gst-returns banking approvals stock-ledger msme einvoice tds opening-data; do php artisan "$m:install" --no-interaction; done && \
  php artisan shield:generate --all --option=permissions --panel=admin && \
  php artisan saas:refresh-admin-role && php artisan saas:starter-roles && php artisan saas:bootstrap-workspace'
```

**3. Add the plans and a platform operator**

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
docker compose exec -u www-data erp php /var/www/aureuserp/artisan db:seed --class='Database\Seeders\SaasSeeder' --force
docker compose exec -u www-data erp php /var/www/aureuserp/artisan saas:platform-admin you@example.in
```

The platform operator role can only be granted from the command line; no screen gives it. Revoke it with `--revoke`.

**4. Warm the caches and reload**

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
docker compose exec -u www-data erp sh -c 'cd /var/www/aureuserp && php artisan optimize && php artisan filament:optimize'
docker compose restart erp
```

Then open `https://<your domain>/saas/register` to create the first company, or create one as the platform operator from **SaaS Platform → Tenants → Onboard New Tenant**.

## After an upgrade

Pull the new code, run `composer install` and `npm ci && npm run build` if their lock files changed, then repeat `migrate --force`, the module install loop, `shield:generate`, `saas:refresh-admin-role`, and the cache step. [Operations](https://docs.erp.arukz.com/developers/operations.md) explains why the caches and the PHP-FPM reload matter.

## Known limits

* The **sample factory** needs Faker, a development package. A `composer install --no-dev` leaves it out, and loading the sample factory then fails.
* **Backups** (`saas:backup`, nightly at 01:30) are written to `storage/app/backups` on the same server. Copy them somewhere else; see [Operations](https://docs.erp.arukz.com/developers/operations.md).
* **Company subdomains** need wildcard DNS and a wildcard certificate; company paths (`/<company>/admin`) need neither.

To run on Kubernetes instead, see [Kubernetes](https://docs.erp.arukz.com/developers/kubernetes.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.