Gemini_Generated_Image_529gir529gir529g

Storj’s $50 Minimum Fee Killed It for Me — Here’s What I Switched To

Migrating from Storj.io to Z1 Storage on TrueNAS SCALE

Here’s the updated post with that corrected throughout:


Ditching Storj: How I Moved My TrueNAS Backups to a Local SA Alternative for a Fraction of the Price

If you’ve been using Storj for cloud backups, you’ve probably received the email by now. From 1 July 2026, Storj is introducing a $50 per month minimum fee — regardless of how much storage you actually use. For homelab users and small self-hosters backing up less than 7TB, that’s a significant and unwelcome change.

This post covers how I migrated my TrueNAS SCALE backup setup away from Storj to Z1 Storage, a South African S3-compatible object storage provider — and why it ended up being a better fit than the more commonly recommended Backblaze B2.


What Changed with Storj

Storj’s new pricing structure, effective 1 July 2026, introduces two tiers (Standard at $7/TB and Advanced at $10/TB) and eliminates the old segment fees. On paper that sounds reasonable — but the $50/month minimum is the dealbreaker for most homelab users. If your backup footprint is under 7TB, you’re paying more than your actual usage warrants, with no credit for the difference.

Accounts that don’t opt in before the deadline will be frozen and data deleted within 45 days, so this isn’t something you can ignore.


Why Not Backblaze B2?

Backblaze B2 is the most commonly recommended Storj alternative — no minimum fee, $6/TB/month, and free egress via the Cloudflare Bandwidth Alliance. For many users it’s the right choice.

However, Backblaze only operates datacenters in the US and EU. If you’re based in South Africa, you’re routing every backup upload across an international link. For small incremental backups that’s probably fine, but when a local alternative exists at a similar price point, it’s worth considering.


Enter Z1 Storage

Z1 Storage is a South African S3-compatible object storage provider with datacenters in Johannesburg and Cape Town. It’s priced at R0.30/GB per month (roughly R300/TB), includes free ingress, and egress equal to your stored data per month at no charge. There’s no minimum monthly fee.

It’s fully S3-compatible — meaning rclone, TrueNAS Cloud Sync tasks, BackWPup, and virtually any other S3-aware tool works with it out of the box. For a sub-1TB backup footprint you’re looking at well under R200/month, billed in Rands with no USD/ZAR exchange rate exposure.


The Migration: TrueNAS SCALE

My setup consisted of several TrueCloud Backup Tasks (Storj’s Restic-based integration) and one Cloud Sync task. The key thing to understand is that TrueCloud Backup Tasks are Storj-specific — you can’t simply swap the credential to Z1 Storage. They need to be replaced with standard Cloud Sync tasks.

Step 1: Add Z1 as a Cloud Credential

Go to Credentials → Backup Credentials → Cloud Credentials → Add and fill in:

  • Provider: Amazon S3
  • Endpoint URL: https://s3.z1storage.com
  • Access Key ID: your Z1 Storage access key
  • Secret Access Key: your Z1 Storage secret key
  • Region: leave blank, check Disable Endpoint Region

Click Verify Credential before saving. The endpoint needs the full https:// prefix — s3.z1storage.com alone or with :443 appended will throw a validation error.

Step 2: Disable Old TrueCloud Tasks

Toggle off all existing TrueCloud Backup Tasks in Data Protection. Don’t delete them yet — keep them until Z1 Storage is confirmed working.

Step 3: Create Your Buckets

I created a dedicated bucket in Z1 Storage for each dataset I was backing up, rather than using subfolders inside a single bucket. This keeps things clean and makes it easy to see per-dataset usage at a glance in the Z1 Storage console. For example:

  • personal-storage → one bucket
  • immich-library → one bucket
  • audiobookshelf → one bucket
  • Each WordPress site → its own bucket

It’s a personal preference — one bucket with subfolders works just as well technically — but separate buckets make storage reporting and cleanup much more straightforward.

Step 4: Create Cloud Sync Tasks

For each dataset, create a new Cloud Sync Task under Data Protection with:

  • Direction: PUSH
  • Transfer Mode: SYNC
  • Credential: Z1 Storage
  • Bucket: the dedicated bucket for that dataset
  • Folder: / (root of the bucket)

Under Advanced Options, set Transfers to High Bandwidth (16) and ensure Use –fast-list is ticked. This significantly improves throughput on datasets with large numbers of small files — particularly relevant for photo libraries.

Step 5: Run and Verify

Run each task manually first and verify in the Z1 Storage File Explorer that files are landing in the correct buckets. The initial upload will take longer than subsequent runs — after that, only new or changed files are transferred.

One gotcha: Z1 Storage occasionally returns a 502 Bad Gateway during the final cleanup phase of a sync, even after all files have transferred successfully. If this happens, simply rerun the task — it completes the verification pass quickly and exits cleanly.


WordPress Backups with BackWPup

For WordPress sites, BackWPup (free) supports S3-compatible storage natively. I created a dedicated Z1 Storage bucket per WordPress site, keeping each site’s backups completely isolated. In your job’s To: S3 Service tab, configure it as follows:

  • S3 Service: Custom
  • S3 Server URL: https://s3.z1storage.com
  • Region: us-east-1 (dummy value — Z1 Storage doesn’t require it but the field can’t be left blank)
  • Signature: v4
  • Access Key / Secret Key: your Z1 Storage credentials
  • S3 Bucket: the dedicated bucket for that WordPress site
  • Max backups to retain: 14–15

Hit Save & Test Connection and you’re done.


Cost Comparison

ProviderPriceMinimum FeeLocation
Storj$7/TB$50/monthGlobal
Backblaze B2$6/TBNoneUS / EU
Z1 StorageR0.30/GBNoneSouth Africa

For a ~500GB backup footprint, Z1 Storage works out to approximately R150/month — no surprises, no minimums, billed locally.


Final Thoughts

The Storj pricing change is a real problem for anyone running sub-7TB homelab backups. If you’re in South Africa, Z1 Storage is worth serious consideration — local latency, Rand-denominated billing, full S3 compatibility, and no minimum fee make it a compelling fit for exactly this use case.

The migration from TrueCloud to Cloud Sync tasks takes an hour or two, and the initial upload is the only slow part. Once that’s done, incremental daily backups are fast and cheap.

874c482b-17cb-4c23-9011-9e94b379e367

Ditch the App Password: WordPress + Microsoft 365 Email Done Right

Background

I recently set up a WordPress site for a small business that uses Microsoft 365 for email. The obvious first attempt was to use WP Mail SMTP with basic SMTP auth — set the host to smtp.office365.com, port 587, STARTTLS, drop in an app password, and call it done. That didn’t work.

The SMTP debug log told the story clearly:

535 5.7.139 Authentication unsuccessful, user is locked by your organization's security defaults policy.

Microsoft 365 tenants have Security Defaults enabled by default, which blocks basic/legacy authentication — including SMTP AUTH with app passwords — across the whole tenant. Even after disabling Security Defaults and enabling per-mailbox SMTP AUTH, the propagation delay and Microsoft’s ongoing deprecation of basic auth makes this an unreliable path. OAuth 2.0 is the right solution.


What you’ll need

  • A WordPress site
  • A Microsoft 365 account with a licensed mailbox
  • An admin account on the Microsoft 365 tenant (Global Administrator role)
  • Access to the Microsoft Entra admin centre

In my case the business had a licensed user mailbox for day-to-day email and a shared mailbox for general enquiries (e.g. [email protected]). The goal was to send WordPress emails from the shared mailbox. More on how that works below.


Step 1 — Install FluentSMTP

FluentSMTP is a free, open-source WordPress plugin that supports Microsoft 365 OAuth 2.0 at no cost — unlike WP Mail SMTP and Post SMTP, which gate the Microsoft 365 OAuth option behind a paid plan.

Install it from the WordPress plugin directory:

  1. Go to Plugins → Add New
  2. Search for FluentSMTP
  3. Install and activate
  4. Go to Settings → FluentSMTP
  5. Select Microsoft as your email provider

Before doing anything else, copy the App Callback URL shown on the settings page — you’ll need it in the next step. Leave this tab open.


Step 2 — Register an app in Microsoft Entra

FluentSMTP authenticates via an Azure app registration. You need to create one in the Microsoft Entra admin centre.

  1. Go to entra.microsoft.com and sign in with your admin account
  2. Navigate to Identity → Applications → App registrations
  3. Click + New registration
  4. Fill in the form:
    • Name: anything descriptive, e.g. WordPress Mail
    • Supported account types: select “Accounts in any organizational directory (Any Azure AD directory – Multitenant) and personal Microsoft accounts” — this is required by FluentSMTP
    • Redirect URI: set the dropdown to Web and paste the App Callback URL from FluentSMTP
  5. Click Register
  6. On the overview page, copy the Application (client) ID

⚠️ Pitfall: wrong account type

If you select single-tenant instead of multitenant, the OAuth redirect will fail with AADSTS50194: Application is not configured as a multi-tenant application and the access token box in FluentSMTP will come back empty. If this happens, go to Authentication in your app registration and change the supported account types, then try again.


Step 3 — Create a client secret

  1. In your app registration, click Certificates & secrets in the left sidebar
  2. Click + New client secret
  3. Give it a description and set expiry to 24 months
  4. Click Add
  5. Copy the Value immediately — it is only shown once and will be masked on your next visit

⚠️ Pitfall: secret expiry

The client secret will expire after 24 months and WordPress emails will silently stop sending. Set a calendar reminder for around 22 months from now to come back and renew it under Certificates & secrets.


Step 4 — Add API permissions

The app needs explicit Microsoft Graph permissions to send mail.

  1. In your app registration, click API permissions
  2. Click + Add a permission → Microsoft Graph → Delegated permissions
  3. Search for and tick each of the following:
    • Mail.Send
    • Mail.Send.Shared (needed if sending from a shared mailbox)
    • offline_access (needed for token refresh)
  4. Click Add permissions
  5. Click Grant admin consent for [your organisation] and confirm

All permissions should show a green Granted status in the configured permissions list.


Step 5 — Configure FluentSMTP and authenticate

  1. Go back to Settings → FluentSMTP in WordPress
  2. Fill in:
    • Sender Name: your business name
    • Sender Email: the address emails should come from
    • Application Client ID: the Application ID from Step 2
    • Application Client Secret: the Value from Step 3
  3. Click Authenticate with Office 365 & Get Access Token

A Microsoft login popup will appear. A few important things here:

  • Sign in with an account that has Global Administrator rights on the tenant
  • On the consent screen, tick “Consent on behalf of your organization” before clicking Accept — if you skip this, other users on the tenant won’t be covered
  • Make sure you are doing this in the same browser profile that is logged into Entra — if WordPress is open in one profile and Entra in another, it will authenticate the wrong account

After accepting, you’ll be redirected back to a page showing your access token. Copy it, paste it into the Access Token field in FluentSMTP, and click Save Connection Settings.


A note on shared mailboxes

If you want WordPress to send from a shared mailbox (e.g. [email protected]) rather than a licensed user mailbox, this is fully supported — but the OAuth authentication still happens via a licensed user account. You cannot authenticate directly as a shared mailbox since it has no password or OAuth credentials of its own.

The correct approach is:

Microsoft 365 will honour the shared mailbox as the from address as long as the licensed user has Send As permissions on the shared mailbox. You can verify this in the Microsoft 365 admin centre under Teams & groups → Shared mailboxes → [your mailbox] → Send As permissions. This is also why you need Mail.Send.Shared in your API permissions.


Step 6 — Test it

  1. Go to the Email Test tab in FluentSMTP
  2. Set From to your sender address
  3. Set Send To to an address you can check
  4. Click Send Test Email

If it goes through, you’re done. FluentSMTP hooks into WordPress’s core wp_mail() function, which means every plugin that sends email through WordPress — WPForms, WooCommerce, comment notifications, password resets — will automatically use this setup without any additional configuration.


Troubleshooting summary

ErrorCauseFix
535 5.7.139 Authentication unsuccessful, user is locked by your organization's security defaults policySecurity Defaults enabled on tenantDisable Security Defaults in Entra under Identity → Overview → Properties
AADSTS50194 — empty access token boxApp registered as single-tenantChange supported account types to Multitenant in Authentication settings
Need admin approval screenUser account is not a Global AdminClick “Have an admin account?” and sign in with an admin account
Not Found on test emailMissing API permissionsAdd Mail.Send, Mail.Send.Shared, offline_access and grant admin consent
Forbidden on test emailWrong account authenticated or consent not granted for organisationRe-authenticate, ensure same browser profile, tick “Consent on behalf of your organization”

Once it’s working, WordPress email is one less thing to worry about. The OAuth token refreshes automatically via the offline_access permission — the only maintenance required is renewing the client secret every 24 months.

unnamed

Why Invoice Ninja Kept Logging Me Out — And How CrowdSec Was the Culprit

I set up Invoice Ninja for my business invoicing needs. After logging in, refreshing the page would immediately kick me back to the login screen. After a deep troubleshooting session, the culprit turned out to be a CrowdSec AppSec rule designed for Langflow AI — misfiring on Invoice Ninja’s /api/v1/refresh endpoint. Here’s exactly how I found it and fixed it

Gemini_Generated_Image_1omwip1omwip1omw

Migrating from Nginx Proxy Manager to NPMPlus with CrowdSec: A Complete Walkthrough

I replaced my standard Nginx Proxy Manager instance with NPMPlus (an enhanced fork) and integrated CrowdSec for automated threat detection and blocking — including Cloudflare Turnstile captcha challenges. The whole stack runs in Docker, managed via Dockge, and sits behind itself as a reverse proxy. Here’s exactly how I did it, including the gotchas I hit along the way