215 lines
11 KiB
Markdown
215 lines
11 KiB
Markdown
# Design: Native MariaDB Port Takeover for alt-mariadb on Port 3306
|
|
|
|
Date: 2026-07-05
|
|
Status: Approved by user, ready for implementation planning
|
|
|
|
## Goal
|
|
|
|
Let `install_db.sh` install `alt-mariadb` on the standard MySQL/MariaDB port (3306) by
|
|
first moving DirectAdmin's existing CustomBuild-managed native MariaDB off that port, so
|
|
that any tool or script that assumes the default port can reach `alt-mariadb` without
|
|
custom port configuration.
|
|
|
|
## Background
|
|
|
|
`install_db.sh` currently requires `alt-mariadb`'s port as a mandatory CLI argument
|
|
(defaulting nowhere, e.g. `install_db.sh 10.11 33033`), and its own `validate_paths()`
|
|
explicitly rejects a port that matches DirectAdmin's native engine's port. Native MariaDB
|
|
(installed and managed by CustomBuild) occupies 3306 today.
|
|
|
|
Earlier in this project's design work, a different port-3306 proposal was considered and
|
|
rejected: pointing DirectAdmin's own `mysql.conf` *at* `alt-mariadb` itself. That failed
|
|
because DirectAdmin's legacy-code-base license enforces a hard MariaDB-version ceiling
|
|
(10.6) at login time, independent of CustomBuild settings, and `alt-mariadb` intentionally
|
|
runs newer versions.
|
|
|
|
This design is different and does not hit that problem: DirectAdmin keeps talking to the
|
|
*same* native engine, on the *same* version — only the TCP port that engine listens on
|
|
changes. The freed port 3306 then goes to `alt-mariadb`.
|
|
|
|
The user confirmed empirically, on the actual target server, that setting
|
|
`mysql_inst=no` in CustomBuild's `options.conf` and then changing the native port in
|
|
`/etc/my.cnf` survives a `./build rewrite_confs` run — i.e., once MySQL/MariaDB is marked
|
|
as externally-managed, CustomBuild's config-regeneration sweep no longer touches it. This
|
|
is the key fact that makes a manual, persistent port change safe here (CustomBuild's
|
|
per-service `rewrite_confs` logic is gated on it considering that service "managed").
|
|
|
|
## Scope
|
|
|
|
- Applies only to a **fresh `alt-mariadb` install** (`install_db.sh`'s normal use case) —
|
|
not to migrating an already-running `alt-mariadb` instance to a new port. Native MariaDB
|
|
is always already running at the time `install_db.sh` runs (DirectAdmin itself is
|
|
already installed), so the "live service surgery" risk is entirely on the native side,
|
|
never the `alt-mariadb` side.
|
|
- Runs only on **AlmaLinux 8 or 9**. CloudLinux, Rocky, CentOS, plain RHEL, and AlmaLinux
|
|
outside 8/9 are explicitly refused before anything is touched — a stricter, separate
|
|
check from `install_db.sh`'s own permissive `detect_os()`, because this script touches a
|
|
live, DA-critical service rather than just installing an additional one.
|
|
- This is a materially one-way decision: `mysql_inst=no` has no clean, officially
|
|
documented path back to CustomBuild-managed MySQL once other things start depending on
|
|
the new arrangement. The design rolls back cleanly on failure *during the takeover
|
|
itself*, but is not meant to be casually reversed afterward.
|
|
|
|
## CLI change to `install_db.sh`
|
|
|
|
`PORT` becomes optional. Usage becomes `install_db.sh <MARIADB_VERSION> [PORT]`:
|
|
|
|
- `install_db.sh 10.11` — `PORT` defaults to `3306`, triggering the native takeover.
|
|
- `install_db.sh 10.11 3306` — same as above; the trigger is the *resolved* port value,
|
|
not whether it was typed explicitly.
|
|
- `install_db.sh 10.11 33033` — explicit non-3306 port, no takeover, today's behavior is
|
|
unchanged.
|
|
|
|
`apply_cli_args` changes from requiring exactly 2 arguments to accepting 1 or 2 (still
|
|
requires at least `MARIADB_VERSION`). Usage text and examples must reflect the new
|
|
optional-port form.
|
|
|
|
## Architecture
|
|
|
|
A new, independent script, `scripts/setup/native_mariadb_port_takeover.sh`, holds all
|
|
logic for moving native MariaDB off 3306. `install_db.sh` calls it once, early in
|
|
`main()`, only when the resolved `PORT` is `3306` — before `load_da_credentials`, so that
|
|
by the time DA's credentials are read, `mysql.conf` already reflects the *new* native port
|
|
and the existing "alt port must differ from DA's port" check in `validate_paths()` passes
|
|
naturally with no changes needed there.
|
|
|
|
This mirrors how every other multi-step, risk-bearing operation in this plugin is
|
|
isolated into its own file (`da_restore_native_staging_to_alt_mysql.sh`,
|
|
`alt_mysql_native_backup_restore.sh`, `mysql_upgrade.sh`) rather than growing the already
|
|
large `install_db.sh` further, and keeps this logic independently testable with fake
|
|
command stubs.
|
|
|
|
## Configuration
|
|
|
|
Top-of-file variables in the new script, in the same "hand-editable config block"
|
|
convention already used by `install_db.sh` (e.g. `MARIADB_TARBALL_URL`):
|
|
|
|
- `NATIVE_MY_CNF` (default `/etc/my.cnf`)
|
|
- `NATIVE_MY_CNF_D` (default `/etc/my.cnf.d`)
|
|
- `NATIVE_MYSQL_CONF` (default `/usr/local/directadmin/conf/mysql.conf`)
|
|
- `NEW_NATIVE_PORT` (default `3307`)
|
|
|
|
## Sequencing
|
|
|
|
### Step 0: OS guard
|
|
|
|
Read `/etc/os-release`. Require `ID=almalinux` and `VERSION_ID` starting with `8` or `9`.
|
|
Anything else: `die()` immediately, before any other action.
|
|
|
|
### Step 1: Baseline check
|
|
|
|
Read DA's current native port/socket/credentials from `NATIVE_MYSQL_CONF` (reuse the
|
|
`mysql.conf` parsing convention already used elsewhere in this plugin). Confirm the native
|
|
engine is actually reachable right now using those credentials — abort before touching
|
|
anything if it isn't (this script must not appear to "fix" an unrelated pre-existing
|
|
problem). Also read the *current* `mysql_inst=` value from CustomBuild's `options.conf`
|
|
and record it (`mariadb` or `mysql`) — this is what rollback restores.
|
|
|
|
### Step 2: Idempotency check
|
|
|
|
If the current native port (from Step 1) is already something other than 3306, log
|
|
"already done" and exit 0. Nothing further to do.
|
|
|
|
### Step 3: Preflight the new port
|
|
|
|
Confirm `NEW_NATIVE_PORT` is not already bound by anything (reuse `install_db.sh`'s
|
|
`port_is_listening` pattern). Refuse before making any change if it is.
|
|
|
|
### Step 4: Disable CustomBuild's MySQL management
|
|
|
|
Run `da build set mysql_inst no` — DirectAdmin's supported CLI, not a raw edit of
|
|
`options.conf`. Skip if Step 1 already found it set to `no` (idempotency).
|
|
|
|
### Step 5: Locate, back up, and rewrite the active `port=` directive(s)
|
|
|
|
Scan `NATIVE_MY_CNF` and every `NATIVE_MY_CNF_D/*.cnf` for a `port=` line inside a
|
|
`[mysqld]`/`[mariadb]`/`[server]` section (later-loaded `my.cnf.d` files override
|
|
`my.cnf`'s own value for the same directive — both must be checked, not just one). Back up
|
|
every file before editing it (timestamped copy, matching `install_db.sh`'s
|
|
`backup_existing_file` convention). If no explicit `port=` line exists anywhere (implicit
|
|
default), add one to `[mysqld]` in `NATIVE_MY_CNF`. If matches exist, rewrite each to
|
|
`NEW_NATIVE_PORT`.
|
|
|
|
### Step 6: Update `mysql.conf`
|
|
|
|
Rewrite only the `port=` field in `NATIVE_MYSQL_CONF` to `NEW_NATIVE_PORT`, via a targeted
|
|
line replacement — not full-file regeneration — so `user=`/`passwd=`/`host=`/`socket=` are
|
|
left untouched exactly as they were.
|
|
|
|
### Step 7: Restart native MariaDB
|
|
|
|
Restart the native MariaDB service (reuse `mysql_service_name()`-style detection). Verify
|
|
it is listening on `NEW_NATIVE_PORT` and specifically **not** on 3306.
|
|
|
|
### Step 8: Restart DirectAdmin
|
|
|
|
Restart the `directadmin` service so DA's core picks up the new port immediately, rather
|
|
than relying on an unconfirmed lazy-reload behavior. This causes a brief (seconds-long)
|
|
panel interruption — expected, not a failure.
|
|
|
|
### Step 9: Verify DA's own connectivity
|
|
|
|
Confirm DA's credentials (from the now-updated `mysql.conf`) can connect to the native
|
|
engine on `NEW_NATIVE_PORT`. This is the real pass/fail gate for the whole operation.
|
|
|
|
Only if Step 9 succeeds does `install_db.sh` continue installing `alt-mariadb`, now
|
|
targeting port 3306 (already free).
|
|
|
|
## Error handling and rollback
|
|
|
|
Any failure at Step 4 or later triggers rollback of everything done so far, in reverse
|
|
order, before the script aborts non-zero:
|
|
|
|
- Restore every file backed up in Step 5 from its timestamped copy.
|
|
- Run `da build set mysql_inst <original_value>` (the value captured in Step 1) to restore
|
|
CustomBuild management.
|
|
- Attempt to restart native MariaDB back on 3306; verify it's reachable again via the
|
|
*original* credentials/port.
|
|
- If DirectAdmin was already restarted (Step 8+), restart it again so it re-picks-up the
|
|
reverted config, then verify reachability.
|
|
|
|
The script logs clearly what it reverted and always exits non-zero on any rollback path.
|
|
`install_db.sh` must not proceed to installing `alt-mariadb` if this script exits non-zero,
|
|
for any reason. One exception: if Step 9 fails only because DirectAdmin itself won't
|
|
restart cleanly (unrelated to the port change), the script should say so explicitly rather
|
|
than reporting it as a takeover failure.
|
|
|
|
## Testing
|
|
|
|
Matching this repo's established convention (plain bash test scripts under `tests/`, fake
|
|
command stubs via `PATH`/env-var injection, no external test framework): a new
|
|
`tests/native_mariadb_port_takeover_test.sh` fakes `da`, `systemctl`, and the
|
|
`mysql`/`mariadb` client binaries as stub scripts that log their invocations, plus fixture
|
|
copies of `/etc/my.cnf`, `/etc/my.cnf.d/*.cnf`, and `mysql.conf` under a temp directory (all
|
|
overridable via the script's own env vars, same pattern as `alt_mysql_native_backup_restore.sh`'s
|
|
tests). Scenarios:
|
|
|
|
- Happy path: native on 3306 → ends up on 3307, `mysql.conf` updated, exit 0.
|
|
- Idempotency: native already on 3307 → no-op, exit 0, no file changes.
|
|
- OS guard: non-AlmaLinux or AlmaLinux outside 8/9 → refuses immediately, no files touched.
|
|
- Preflight rejection: `NEW_NATIVE_PORT` already in use → refuses before any change.
|
|
- Rollback: simulate failure at each of Steps 5 through 9 in turn → confirm every backed-up
|
|
file is restored and `da build set mysql_inst <original>` is called with the correct
|
|
original value in each case.
|
|
|
|
## Out of scope
|
|
|
|
- Migrating an already-running `alt-mariadb` instance to a new port (not needed — this
|
|
server has no `alt-mariadb` installed yet).
|
|
- Any OS other than AlmaLinux 8/9.
|
|
- A documented path back to CustomBuild-managed MySQL/MariaDB after this runs.
|
|
- Changing `/etc/services` or CSF/firewall rules (native MariaDB is not intended to be
|
|
remotely reachable; out of scope unless that changes).
|
|
|
|
## Risks / open items for implementation planning
|
|
|
|
- The exact `[mysqld]`/`[mariadb]`/`[server]` section name in use on this server's
|
|
`/etc/my.cnf.d/*.cnf` files should be confirmed empirically during implementation (grep
|
|
the actual files) rather than assumed, since MariaDB accepts more than one section name
|
|
for the same server-level directives.
|
|
- `da build set mysql_inst no` and its reverse are assumed to be synchronous, side-effect-free
|
|
writes to `options.conf` with no network/build side effects; this should be confirmed
|
|
empirically (e.g. by diffing `options.conf` before/after and confirming no other files
|
|
change) during the first implementation task, consistent with how this project has
|
|
handled other empirically-verified-not-documented DirectAdmin behaviors.
|