.. include:: /Includes.rst.txt .. _backup: ======= Backups ======= Prerequisites: a **backup encryption password** is set in Settings. .. important:: ZIP AES-256 encrypts file *contents*, not archive metadata. Entry names, sizes and the directory tree remain readable without the password. Keep backup directories **outside the web root** (default :file:`var/t3vault/backups`). Never publish :file:`.t3vault.tar` or ZIP parts under :file:`public/`. :file:`config.local.php` (standalone password, signing secret, backup password) is **not** included. TYPO3 :file:`settings.php` / :file:`LocalConfiguration.php` are stored with DB credentials and ``encryptionKey`` removed — reconfigure them on restore. Manual backups from **New Backup** open a dialog to include or exclude components (database, configuration, packages, Composer files, FAL/media, uploads). The job label reflects the selection (e.g. database-only is shown as a database backup, not a full site backup). Only a complete set (database + configuration + Composer / ``typo3conf``) enables a full site restore; the restore installer warns and skips inapplicable steps for partial packages. Scheduled tasks of type ``full`` still back up all components. .. figure:: /Images/screenshot-new-backup.png :alt: New Backup dialog with checkboxes for database, configuration, packages, Composer files and media :class: with-shadow :zoom: lightbox Manual backups let you include or exclude components before the job starts. .. _backup-types: Backup types ============ ``full`` Default. Everything needed to reinstall elsewhere (or a selected subset when started from the New Backup dialog). **Composer layout** (:file:`config/` + :file:`public/`): * :file:`database.zip` (AES-256; entry :file:`database.sql.gz`) * :file:`config/` (settings, additional, sites) * :file:`packages/` and other local Composer path repositories (e.g. :file:`extensions/` from :file:`composer.json`) * :file:`composer.json` / :file:`composer.lock` * :file:`public/fileadmin/` and other local FAL storages (without :file:`_processed_/` / :file:`_temp_/`) * optional :file:`uploads/`, :file:`index.php`, :file:`.htaccess` **Classic layout** (:file:`typo3conf/` in the document root): * :file:`database.zip` (AES-256; entry :file:`database.sql.gz`) * :file:`typo3conf/` (without temp/autoload caches) * :file:`fileadmin/`, optional :file:`uploads/` (without :file:`_processed_/` / :file:`_temp_/`) * :file:`index.php`, :file:`.htaccess` * Core (:file:`typo3/`, :file:`typo3_src/`) and :file:`typo3temp/` are **not** included ``fileadmin`` Media only (ZIP parts of fileadmin / FAL; without :file:`_processed_/` / :file:`_temp_/`). ``database`` Encrypted database dump only (:file:`database.zip` + :file:`MANIFEST.json`). Useful for frequent scheduled tasks when a full site backup is not required every night. Each completed backup also contains :file:`MANIFEST.json` with layout-specific restore hints and environment metadata (PHP / DB / TYPO3 versions). .. _backup-tasks: Scheduled backup tasks ====================== Backup tasks define **what** to back up, **when**, and **how long** to keep archives. Configure them in the UI (**Backup tasks**) or via the API (``GET``/``POST`` ``/tasks``). Definitions are stored in :file:`tasks.json` inside the T3Vault data directory (0600). .. figure:: /Images/screenshot-tasks.png :alt: Backup tasks dialog listing scheduled full-site and database jobs :class: with-shadow :zoom: lightbox Scheduled tasks define what to back up, when to run, and how long to keep archives. Each task has: * ``type`` — ``database``, ``fileadmin`` or ``full`` * ``schedule`` — ``hourly`` (minute of hour) / ``daily`` / ``weekly`` / ``monthly`` (with ``at`` time) or a five-field ``cron`` expression * ``retention`` — one or more tiers ``{ every: { value, unit }, keep }`` with ``unit`` in ``hour|day|week|month|year`` Retention uses **independent historical slots** per tier, measured from the newest non-pinned backup of that task: * The **finest** tier (smallest ``every``) covers ages ``[0, keep·E)`` in ``keep`` slots of length ``E`` (includes the newest backup). * **Coarser** tiers start one full period back: slots ``[E, 2·E)`` … ``[keep·E, (keep+1)·E)``. So “1× month / keep 1” retains a backup about 30–60 days old, and “1× year / keep 1” about 365–730 days old (fixed durations: month = 30 days, year = 365 days). Each slot keeps the newest backup in that age interval; the union of all tiers survives. Manual backups (no ``taskId``) and pinned backups are never deleted by retention. Run due tasks from cron (synchronous, no HTTP self-invocation loop): .. code-block:: bash php t3vault/cli/t3vault-run.php due php t3vault/cli/t3vault-run.php task php t3vault/cli/t3vault-run.php retention php t3vault/cli/t3vault-run.php list Or via the TYPO3 console (recommended on Composer installs): .. code-block:: bash vendor/bin/typo3 t3vault:run due vendor/bin/typo3 t3vault:run task vendor/bin/typo3 t3vault:run retention vendor/bin/typo3 t3vault:run list **TYPO3 Scheduler** (ext:scheduler suggested): * Dedicated task **“T3Vault: run due backup tasks”**, or * Task type **Execute console commands** → command ``t3vault:run`` (optional argument ``due``, which is the default). On the local DDEV project, ``scheduler:run`` is invoked every minute via Supercronic (``.ddev/web-build/typo3.cron``). After creating a Scheduler task in the backend, due T3Vault backups run automatically while ``ddev start`` is active — no host crontab needed. Manual “Run now” in the UI starts the job via the normal web process chain. Backups created by a task carry ``taskId`` / ``taskName`` / ``mode`` in the plan and manifest so retention only touches that task’s archives. What is never packed ==================== * **Symlinks leaving the backup scope.** Because archiving follows symlinks, a link inside :file:`fileadmin/` that points to :file:`~/.ssh/id_rsa`, :file:`/etc/passwd` or an :file:`.env` outside the project would otherwise end up in the archive. Such links are skipped and listed as ``skippedSymlinks`` in the backup plan. Links that resolve back into the project are kept, so Composer path repositories in :file:`vendor/`, :file:`public/_assets/` and the classic :file:`typo3/` links keep working. * **System directories configured as FAL storage.** A ``sys_file_storage`` row with a base path such as :file:`/etc`, :file:`/root`, :file:`/usr` or a bare home directory is ignored. Regular storages outside the project root (for example :file:`/srv/shared-media`) are still backed up as external parts. .. _backup-process: How processing works ==================== 1. Start a backup from the UI (type ``full``, ``fileadmin`` or ``database``), or let a scheduled task / the CLI runner start it. 2. A JSON plan is written under the backup directory. 3. **Web path:** the server continues batches via self-invocation (CURL), so closing the browser does not stop the job — useful on shared hosting without cron. **CLI path** (:file:`t3vault/cli/t3vault-run.php`): one process runs the plan to completion without HTTP continuation. 4. When finished, integrity sealing runs (hashes + OpenTimestamps). Job status ``completed`` is independent of whether the stamp already reached Bitcoin blockchain confirmation (see :ref:`integrity`). Optional batch options (API / advanced): ==================== =========================================== Option Default meaning ==================== =========================================== ``maxZipSizeMb`` Target size per ZIP part (default 500) ``filesPerBatch`` Files per batch iteration (default 50) ``maxTimePerBatch`` Seconds per batch (default 20) ==================== =========================================== .. _backup-layout: Directory layout ================ .. code-block:: text var/t3vault/backups/ └── backup_YYYYMMDD_HHMMSS_/ ├── backup-plan.json ├── backup-plan.json.state.json # while running ├── backup.log ├── database.zip # AES-encrypted SQL dump (full backups) ├── MANIFEST.json ├── *_part_*.zip # AES-encrypted ├── integrity.json ├── integrity.json.hmac # optional ├── integrity.json.ots └── integrity-meta.json :file:`backup-plan.json` may also hold optional user fields ``name`` (label, max. 120 characters) and ``note`` (free text, max. 2000 characters). Edit them from the backup list (pencil icon). They are not part of the integrity seal, so changing them does not invalidate the archive signature. An empty value removes the field. Without a custom ``name``, the UI shows the backup type label. .. _backup-errors: Error messages and references ============================= API responses keep infrastructure detail out: instead of an exception message with absolute paths, a failing request answers with a generic message and a reference such as ``ref: 9f2ac41b77e0``. The full detail — exception class, message, file and line — is written to .. code-block:: text var/t3vault/state/error.log Search that file for the reference to see what actually happened. The file is created with ``0600`` in the private directory, outside the web root. .. _backup-download: Download ======== From the backup list you can download: * :file:`.t3vault.tar` — archive of the backup directory * Installer helpers for restore on a target server * **DDEV project** script (:file:`t3vault-ddev.sh`) for local Composer-based reproduction A browser download cannot send the ``Authorization`` header, so each download is authorised by a separate short-lived token in the URL (60 s; 120 s for the installer). The token is bound to one purpose, to one backup, and — on first use — to the requesting client. Repeat requests from the same client still work (redirects, resumed transfers), while the same URL from anywhere else is refused. The generated DDEV script therefore carries its own archive token (one hour), because it runs later and from another client than the browser. .. _backup-import: Importing backups ================= An upload (:file:`.t3vault.tar` or loose artifacts) is content from outside, so it is checked before it appears in the backup list. **Request limits.** At most ``uploadMaxFiles`` files, ``uploadMaxFileBytes`` per file and ``uploadMaxTotalBytes`` in total (see :ref:`configuration-keys`). The import is also refused when the target volume has less than roughly twice the payload free, because a TAR import stages the archive and then writes the extracted artifacts. Only one import runs at a time. **Structural validation.** Every ZIP part is inspected with the same rules the restore installer applies: absolute entry paths, ``..`` segments, backslashes and symlink entries are rejected, as is an implausible compression ratio. A rejected upload is deleted immediately and answered with a log reference — no half-imported directory stays behind. **Trust marking.** A backup created here is sealed: :file:`integrity.json` lists the artifact hashes and :file:`integrity.json.hmac` binds that list to this installation's signing secret. An import is therefore rated: =============== ============================================================== Rating Meaning =============== ============================================================== *verified* Hashes match :file:`integrity.json` **and** the HMAC verifies with the local secret — sealed here, unchanged *unverified* Anything else: no :file:`integrity.json`, altered artifacts, a seal from another installation, or no local signing secret =============== ============================================================== A foreign archive cannot verify here — that is expected, not an attack, and it is reported as such. The list and the details dialog show the rating with its reason, and the generated :file:`RESTORE.md` of an unverified import carries a warning: restoring an archive of unknown origin introduces its code and data into the target system. :file:`integrity-meta.json` from an upload is discarded. It records the result of a verification run on the *source* system and must not be shown as this installation's verification state.