# What the setup script does

> Source: https://www.allsweb.com/sixpreflight/docs/setup-script
> Markdown for agents: https://www.allsweb.com/sixpreflight/docs/setup-script.md
> Publisher: AllsWeb (www.allsweb.com)

Part of: SixPreflight documentation

SixPreflight tells you what to change. The setup script is the other half of the same folder — it makes the change for you. Where the dashboard asks you to copy a value and paste it yourself, `setup-6ammart.php` applies the same recommendation directly, and asks first about anything that trades one property for another.

## What it is

A bash script, despite the `.php` extension in its name. That extension is deliberate — it stops a web server from ever handing the file out if someone requests it by URL. PHP takes the file, hits an exit statement on line 3, and returns nothing. Run it with `bash`, never through a browser.

It is the fallback route behind SixPreflight, not the first one. The dashboard still asks you to make each change by hand first, because a person who makes a change understands what they changed. This script exists for when that is not practical — it applies everything it can apply safely, and it asks about anything where a real tradeoff exists.

Every recommendation comes from the same tuning catalog mentioned on [The "What to fix" page](https://www.allsweb.com/sixpreflight/docs/what-to-fix#the-tuning-catalog-behind-it) — around 84 entries across seven layers.

Each one carries a flag saying whether it is safe to apply without asking. About 40 are. The rest are either prompted with the tradeoff stated in one line, or printed as an instruction for you to follow yourself.

No entry in that second group is ever applied silently, not even when you tell the script to skip every other prompt.

## The four modes

The default writes nothing. Running the script by accident cannot change anything on your server.

| Mode | What it does |
|---|---|
| `--dry-run` (default) | Prints every change it would make. Writes nothing — this is what you get with no arguments at all. |
| `--check` | Reports current value against recommended value, as a diff. Writes nothing. |
| `--apply` | Does the work. Asks before anything risky. |
| `--apply --yes` | Accepts every safe-to-automate item without asking. Risky items still ask, every time. |

See what it would do — writes nothing:

```bash
bash preflight/bin/setup-6ammart.php
```

Current vs recommended, as a report:

```bash
bash preflight/bin/setup-6ammart.php --check
```

Do the work, asking where a tradeoff exists:

```bash
bash preflight/bin/setup-6ammart.php --apply
```

One layer only:

```bash
bash preflight/bin/setup-6ammart.php --apply --only laravel --only 6ammart
```

Everything except the database:

```bash
bash preflight/bin/setup-6ammart.php --apply --skip mysql
```

It must run as root, since it edits `php.ini`, `my.cnf`, sysctls and systemd units. Anything that touches the application itself — running `artisan` or `composer` — is dropped to the web user instead, because a cache file written by root is one the web user can no longer rebuild later.

## The three safety rules

:::checks
- Every write is gated behind one function that returns false in dry-run and check modes, before any file is even opened
- Every file is backed up before it is edited, preserving mode and owner, so a run can always be undone
- Application commands like artisan and composer never run as root — they run as the web user
:::

## The seven layers

They run in a fixed order — a layer that cannot break the site runs before one that can.

| Layer | What it covers |
|---|---|
| `php` | OPcache, JIT, memory and execution limits, upload sizes, `display_errors`, `disable_functions`. |
| `php-fpm` | Pool sizing — process manager mode and worker count, measured against cores and real memory per worker. |
| `os` | Swap presence, file-descriptor limits, `vm.overcommit_memory`. Live and reversible in one command. |
| `mysql` | InnoDB buffer pool and log file size, `sql_mode`, character set, binary logging. |
| `nginx` | Deny blocks for files above the web folder, static-expires rules, upload limits, gzip, TLS versions. |
| `laravel` | Route cache, storage ownership, `.env` file mode, `APP_DEBUG`, and the queue worker. |
| `6ammart` | Application settings — the scheduler cron, push notification settings, ghost modules, timezone, mail config, the websocket server. |

### One nginx safeguard worth knowing about

6amMart's own deny-list for files above the web root missed several real paths: both installer SQL dumps, a leftover zip archive, internal markdown files, and a `bootstrap/app.php` that was being executed directly by the web server and disclosing an absolute path in the error it returned.

So the script probes each path by request rather than trusting the deny-list on paper. It adds a block only for the ones that actually answer, then re-fetches the same paths afterward to confirm the block wins.

That last step is the point: a rule can be present and valid in the config and still lose to another rule that matches the same path first.

The document root itself is not changed. 6amMart runs correctly whether the vhost is rooted at the project folder or at `public/`, so restructuring a working vhost is not something this script does — only the deny blocks that decide which files a request can actually fetch.

## The queue worker and scheduler

This is where the script earns its keep, because getting either of these wrong is completely silent — nothing errors, nothing logs, and the shop keeps looking healthy.

**The queue worker.** `QUEUE_CONNECTION` and a running worker are really one setting split across two places. With a queue configured and no worker, jobs pile into a table and nothing ever drains them — no push notification, no order mail. The script checks the pair together rather than each half on its own, writes a supervised systemd unit if none exists, and — if jobs are already stuck in the table — counts them and warns you before starting the worker, because hours of stale notifications arriving all at once is worse than none arriving.

**The scheduler cron.** Store and rider disbursements, subscription reminders and the monthly order reminder all run from Laravel's scheduler. Without the crontab line, none of them ever happen, and nothing is written anywhere to say why. The script adds the line to the web user's crontab specifically — never root's — because `artisan` run as root leaves root-owned files that the web user can no longer rebuild.

## What it will never do

These are deliberate refusals, not gaps — each one is a case where the obvious automatic fix leaves a site that keeps serving pages while something quietly breaks.

| It will not | Why |
|---|---|
| Run `config:cache` | This codebase reads some keys at runtime that would go null once the config is cached — caching or clearing it can break a working install either way. |
| Run `key:generate` | Rotating `APP_KEY` makes every encrypted column and every session permanently unreadable. |
| Run `composer install` | A production reinstall can remove a package a module needs at runtime. |
| Flush failed jobs | The payload of a failed job is the only record of what broke. |
| Touch `public/storage` | 6amMart does not use the symlink a storage-link command would create. |
| Restart the database | Brief downtime — deserves its own decision, not an automatic one. |
| Overwrite a unit file it did not write | An existing file may be someone's deliberate configuration. |

## Undoing a run

Every `--apply` run writes a restore script and prints its path at the end. It restores the files that run changed, from the backups that run took.

```bash
bash /root/preflight-restore-20260807-101530.sh
```

It restores files only — a live database setting changed with `SET GLOBAL`, a systemd unit that was created, or a crontab line that was added are not files, and are listed individually in the run's own output instead.

## Reading the summary

| Count | Meaning |
|---|---|
| ok | Already at the recommended value. Nothing was done. |
| applied | Changed by this run — or, in dry-run, what would change. |
| manual | Deliberately left to a person, with the instruction printed. Not a failure. |
| failed | Attempted and did not verify. The script exits with an error if this is above zero. |
| skip | Not applicable to this box, or filtered out by `--only` / `--skip`. |

Run `--check` again afterward. The honest verification of a run is a fresh read of the server, not the run's own report of what it did.
