tearoom1/kirby-ftp-backup

Kirby plugin that creates content backups and uploads them to a FTP server.

Maintainers

Package info

github.com/tearoom1/kirby-ftp-backup

Documentation

Type:kirby-plugin

pkg:composer/tearoom1/kirby-ftp-backup

Fund package maintenance!

tearoom1

Buy Me A Coffee

Statistics

Installs: 73

Dependents: 0

Suggesters: 0

Stars: 13

Open Issues: 2

1.4.0 2026-03-23 15:30 UTC

README

A Kirby CMS plugin that creates backups of your site content and uploads them to an FTP server.

Screenshot

Features

  • Create ZIP backups of your site content
  • Automatic upload to FTP server
  • Configurable backup retention
  • Panel interface for manual backups and downloads
  • Scheduled backups via cron job

Installation

Manual Installation

  1. Download or clone this repository
  2. Place the folder kirby-ftp-backup in your site's /site/plugins directory

Composer Installation

composer require tearoom1/kirby-ftp-backup

Configuration

All configuration is handled through Kirby's option system. Add the following to your site/config/config.php file:

'tearoom1.kirby-ftp-backup' => [
    // Plugin Control
    'enabled' => true,                           // Enable/disable the entire plugin
    'ftpEnabled' => true,                        // Enable/disable FTP uploads (backups still created locally)

    // FTP Connection Settings
    'ftpProtocol' => 'ftps',
    'ftpHost' => 'your-ftp-host.com',
    'ftpPort' => 21,
    'ftpUsername' => 'your-username',
    'ftpPassword' => 'your-password',
    'ftpDirectory' => 'backups',
    'ftpPassive' => true,
    'ftpPrivateKey' => 'path/to/private/key.pem',
    'ftpPassphrase' => 'your-passphrase',
    'ftpTimeout' => 30,
    'ftpKeepAlive' => 0,

    // Backup Settings
    'backupDirectory' => 'content/.backups',  // Local directory to store backups
    'backupRetention' => 10,                 // Number of backups to keep when using simple retention strategy
    'deleteFromFtp' => true,                  // Whether to delete old backups from FTP
    'filePrefix' => 'backup-',               // Prefix for backup filenames
    'retentionStrategy' => 'simple',         // Backup retention strategy: 'simple' or 'tiered'
    'tieredRetention' => [
        'daily' => 10,    // Keep all backups for the first 10 days
        'weekly' => 4,    // Then keep 1 per week for 4 weeks
        'monthly' => 6    // Then keep 1 per month for 6 months
    ],

    // File Filtering (regex patterns without delimiters, case-insensitive)
    'includePatterns' => [],                 // If not empty, only files matching these patterns are included
    'excludePatterns' => [],                 // Files matching these patterns are always excluded
]

Configuration Options

Option Type Default Description
enabled boolean true Enable/disable the entire plugin
ftpEnabled boolean true Enable/disable FTP uploads (backups still created locally)
ftpProtocol string 'ftp' FTP protocol: 'ftp', 'ftps' or 'sftp'
ftpHost string '' FTP server hostname
ftpPort integer 21 FTP server port
ftpUsername string '' FTP username
ftpPassword string '' FTP password
ftpDirectory string '/' Remote directory to store backups
ftpPassive boolean true Use passive mode
ftpPrivateKey string '' Path to private key file
ftpPassphrase string '' Passphrase for private key
ftpTimeout integer 30 Socket response timeout in seconds (see Advanced Options)
ftpKeepAlive integer 0 SFTP only. SSH keepalive interval in seconds, 0 = disabled (see Advanced Options)
backupDirectory string 'content/.backups' Either absolute or relative (to Kirby base) path for local backups
backupRetention integer 10 Number of backups to keep when using simple retention strategy
deleteFromFtp boolean true Whether to delete old backups from FTP server
filePrefix string 'backup-' Prefix for backup filenames
retentionStrategy string 'simple' Backup retention strategy: 'simple' or 'tiered'
tieredRetention array see below Settings for tiered retention strategy
includePatterns array [] Regex patterns (no delimiters, case-insensitive) - if not empty, only matching files are included
excludePatterns array [] Regex patterns (no delimiters, case-insensitive) - matching files are always excluded
urlExecutionEnabled boolean false Enable URL-based backup execution
urlExecutionToken string '' Security token required for URL-based backup execution

Plugin Control Options

Disable Entire Plugin

To completely disable the plugin (no backups will be created):

'tearoom1.kirby-ftp-backup' => [
    'enabled' => false,
]

When disabled:

  • Panel UI will not be accessible
  • API routes will return error responses
  • CLI commands will not execute
  • URL-based execution will be blocked

Disable FTP Only

To create backups locally but skip FTP uploads:

'tearoom1.kirby-ftp-backup' => [
    'ftpEnabled' => false,
]

When FTP is disabled:

  • Backups are still created and stored locally
  • No FTP connection or upload attempts
  • Local retention policies still apply
  • Panel UI remains functional for viewing/downloading local backups

This is useful when:

  • You want local backups only
  • FTP server is temporarily unavailable
  • Testing backup creation without uploading
  • Migrating between FTP servers

Retention Strategies

The plugin supports two retention strategies for managing old backups:

Simple Retention

Keeps a fixed number of most recent backups, discarding older ones. This is controlled by the backupRetention option.

'backupRetention' => 10, // Keep 10 most recent backups

Tiered Retention

A more sophisticated approach that keeps backups with decreasing frequency as they age:

'retentionStrategy' => 'tiered',
'tieredRetention' => [
    'daily' => 10,    // Keep all backups for the first 10 days
    'weekly' => 4,    // Then keep 1 per week for 4 weeks
    'monthly' => 6    // Then keep 1 per month for 6 months
]

This strategy:

  1. Keeps all backups from the last X days
  2. Then keeps one backup per week for Y weeks
  3. Then keeps one backup per month for Z months
  4. Deletes anything older

This provides a good balance between recent recovery points and long-term archiving.

File Filtering

You can control which files are included in backups using regex patterns. This is useful for excluding large media files, temporary files, or other content you don't need to back up.

How it works

  1. Default behavior: All files are included
  2. Include patterns: If specified, only files matching these patterns are included
  3. Exclude patterns: Files matching these patterns are always excluded (applied after include patterns)
  4. Case-insensitive: All patterns are automatically case-insensitive

Examples

Exclude specific file types:

'excludePatterns' => [
    '\.mp4$',           // Exclude video files
    '\.zip$',           // Exclude zip files
    '/cache/',          // Exclude cache directory
    '\.tmp$',           // Exclude temporary files
]

Include only specific file types:

'includePatterns' => [
    '\.txt$',           // Only text files
    '\.md$',            // And markdown files
]

Exclude large media files but keep images:

'includePatterns' => [
    '\.(jpg|jpeg|png|gif|svg)$',  // Only image files
    '\.txt$',                      // And text files
    '\.md$',                       // And markdown files
],
'excludePatterns' => [
    '/originals/',                 // Exclude originals folder
]

Complex filtering:

'includePatterns' => [
    '\.(txt|md|json|yml)$',       // Include text-based files
],
'excludePatterns' => [
    '/\._',                       // Exclude macOS resource forks
    '/\.DS_Store$',               // Exclude .DS_Store files
    '/thumbs\.db$',               // Exclude Windows thumbnails
]

Note: Patterns are standard regex patterns without delimiters. The plugin automatically adds # delimiters and makes all patterns case-insensitive.

Panel Interface

The plugin adds a "FTP Backup" area to your Kirby Panel:

  • View all available backups
  • Create new backups manually with live progress indication
  • Cancel a running backup
  • Download existing backups
  • View backup statistics (count, total size, latest backup)
  • View FTP server stats and file listing

Automatic Backups with Cron

To set up automatic backups, add a cron job to your server. The cron job should run the included run.php script:

php /path/to/site/plugins/kirby-ftp-backup/run.php

Optionally the path to the kirby root directory can be passed as the first argument:

php /path/to/site/plugins/kirby-ftp-backup/run.php /path/to/root

The root directory is the one with the kirby folder inside.

Example Crontab Entry

To run a backup every day at 2 AM:

0 2 * * * php /path/to/site/plugins/kirby-ftp-backup/run.php

Replace /path/to/site with the actual path to your Kirby installation.

Using the Run Script

The run.php script handles:

  • Creating a new backup
  • Uploading the backup to the configured FTP server
  • Cleaning up old backups based on the retention setting
  • Outputs logs to the console

URL-Based Backup Execution

As an alternative to cron jobs, you can trigger backups via HTTP requests. This is useful for:

  • External monitoring services
  • Webhook-based automation
  • Manual triggering from remote systems
  • URL based cronjob execution

Configuration

First, enable URL execution and set a secure token in your config.php:

'tearoom1.kirby-ftp-backup' => [
    // ... other settings ...
    'urlExecutionEnabled' => true,
    'urlExecutionToken' => 'your-secure-random-token-here',
]

Usage

Once configured, you can trigger a backup by making a GET request to:

https://yoursite.com/ftp-backup/execute?token=your-secure-random-token-here

Security Features

  • Token Authentication: Requires a matching token to execute
  • Enable/Disable Toggle: Can be completely disabled via configuration
  • Timing-Safe Comparison: Uses hash_equals() to prevent timing attacks
  • Plain Text Response: Returns simple status messages for easy monitoring

Example Response

On success:

Backup created successfully: backup-2025-09-26-140236.zip
File uploaded to FTP server

On error:

Error creating backup: FTP connection failed

Advanced Options

ftpTimeout

How long to wait for the server to respond to each individual packet, in seconds. This is not a total transfer timeout — large files will transfer for as long as needed as long as the connection stays active. The default of 30 seconds is appropriate for most servers. Increase it only if uploads fail on very slow or high-latency connections.

ftpKeepAlive (SFTP only)

Sends an SSH keepalive packet every N seconds to prevent firewalls or load balancers from dropping idle connections during large uploads. Disabled by default (0).

Note: Some OpenSSH servers respond to keepalives with a hostkeys-00@openssh.com global request that phpseclib cannot handle mid-transfer, which can interrupt the upload. Only enable this if you have confirmed that idle-timeout drops are the cause of your upload failures.

Security Considerations

  • Store your FTP credentials securely in your config.php file
  • Make sure your config.php file is not accessible from the web
  • Consider using SFTP or FTP with SSL for secure transfers
  • Regularly verify that your backups are being created and can be restored

Troubleshooting

If you encounter issues:

  1. Check that your FTP credentials and server settings are correct
  2. Verify that the FTP directory exists and has write permissions
  3. Check your server's PHP error logs for any PHP errors
  4. Make sure the local backup directory is writable by PHP
  5. Check if you have the required PHP extensions (zip, ftp)
  6. If uploads fail on slow or high-latency connections, increase ftpTimeout — see Advanced Options
  7. If you get a 504 Gateway Timeout when creating backups from the Panel, increase your web server's proxy/fastcgi read timeout to match or exceed max_execution_time in your php.ini

Requirements

  • Kirby 4+
  • PHP 7.4+
  • PHP ZIP extension
  • PHP FTP extension

Tests

The tests can be run with:

composer update
composer test

Make sure to cleanup the vendor after running tests, to remove dev dependencies.

composer dist

License

This plugin is licensed under the MIT License

Credits

  • Developed by Mathis Koblin
  • Assisted by AI Claude Sonnet 4.6

"Buy Me A Coffee"