Lutish RemoteFtp — User Guide
Lutish RemoteFtp moves XenForo attachments to your own FTP / SFTP servers. Files are served from your CDN, sensitive types go through XF permission checks, and your web server stays lean.Quick Start
- Add a server— Admin → FTP Servers → Add Server
- Fill in host, credentials, remote path, and which extensions this server handles.
- Secure Link Extensions — list extensions that need permission enforcement and signed URLs (e.g.
rar, zip, 7z). - Save → click Test Connection.
- Done. New uploads now route to your FTP server automatically.
Transfer Modes
| Mode | Behavior |
|---|---|
| Async (default) | Upload finishes instantly. File transfers to FTP in a background queue. |
| Sync | User waits for the FTP transfer to complete before upload succeeds. |
Secure Link (Optional)
For NGINXsecure_link_md5 — set a shared secret per server and list extensions that need signed URLs. Attachments with those extensions:- Show as XF-native links (
/attachments/file.zip.123/) - XF checks permissions (daily limits, forum access)
- On pass → 301 redirect to CDN with
?sgn=…&ex=…token (72h expiry)
Queue Management
Background jobs run automatically on page loads. To force processing:
Code:
php cmd.php xf:run-jobs
Common Tasks
| Task | Where |
|---|---|
| Add / edit FTP servers | Admin → FTP Servers |
| Test connection | Server edit page → Test Connection |
| View migration & upload errors | Admin → RemoteFtp → Error Log |
| Migrate BD attachments | CLI: lutish:remotestorage-sync |
| Migrate local files to FTP | CLI: lutish:local-to-ftp |
| Toggle sync / async per server | Server edit → Upload Mode |
| Set secure link per server | Server edit → Secure Link Extensions + Secret |
CLI Commands
Migrate from [bd] Attachment Store
Code:
php cmd.php lutish:remotestorage-sync [--from=N] [--to=N] [--batch-size=N] [--dry-run]
| Option | Description |
|---|---|
--from=N | Start data_id (inclusive). Default: first unsynced record. |
--to=N | End data_id (inclusive). Default: last unsynced record. |
--batch-size=N | Records per batch. Default: 100. |
--dry-run | Preview only — no changes made. |
Code:
# Migrate everything
php cmd.php lutish:remotestorage-sync
# Custom range
php cmd.php lutish:remotestorage-sync --from=1000 --to=5000
# Preview
php cmd.php lutish:remotestorage-sync --dry-run
Migrate Local Attachments to FTP
Code:
php cmd.php lutish:local-to-ftp --server-id=N [--from=N] [--to=N] [--batch-size=N] [--force] [--dry-run]
.jpg → .webp).| Option | Description |
|---|---|
--server-id=N | Target FTP server ID (required). |
--from=N | Start data_id (inclusive). Default: first unsynced. |
--to=N | End data_id (inclusive). Default: last unsynced. |
--batch-size=N | Records per batch. Default: 50. |
--force | Re-upload even if already migrated (use after clearing FTP files). |
--dry-run | Preview only — no uploads, no DB changes. |
Code:
# Migrate to server #1
php cmd.php lutish:local-to-ftp --server-id=1
# Force re-upload
php cmd.php lutish:local-to-ftp --server-id=1 --force
Debug Upload Routing
Code:
php cmd.php lutish-remoteftp:debug-upload [--extension=ext]
Code:
# Test default extension (jpg)
php cmd.php lutish-remoteftp:debug-upload
# Test a specific extension
php cmd.php lutish-remoteftp:debug-upload --extension=webp
php cmd.php lutish-remoteftp:debug-upload -e zip
NGINX Secure Link Configuration
When using Secure Link extensions, configure NGINX to validate signed URLs:Basic Configuration
Code:
location / {
secure_link $arg_sgn,$arg_ex;
secure_link_md5 "YOUR_SECRET$uri$arg_ex";
if ($secure_link = "") { return 403; }
if ($secure_link = "0") { return 410; }
}
With IP Binding
Code:
secure_link_md5 "YOUR_SECRET$uri$arg_ex$remote_addr";
Cloudflare / Reverse Proxy
Code:
set $real_ip $http_x_forwarded_for;
if ($real_ip = "") { set $real_ip $remote_addr; }
secure_link $arg_sgn,$arg_ex;
secure_link_md5 "YOUR_SECRET$uri$arg_ex$real_ip";
sgn, ex) with your admin settings — these are configurable per server.