phpFox ships with a subscription and membership payment layer that sits inside AdminCP → Membership → Subscriptions and the payment gateway module under AdminCP → Apps → Installed. On a managed shared platform the site talks to external processors such as PayPal and Stripe over outbound HTTPS, then waits for those processors to call back into your domain to confirm the transaction. Two directions of traffic must both work: phpFox reaching out to the gateway, and the gateway reaching in to a listener URL. When a membership upgrade silently fails, the broken link is almost always one of those two paths, and the fix lives entirely inside your hosting account rather than at the server level.
This walkthrough assumes you are an unprivileged cPanel Jupiter or DirectAdmin Evolution user on LiteSpeed with CloudLinux PHP Selector available. Every adjustment below is made through the control panel UI, .htaccess, .user.ini, phpMyAdmin, or the phpFox AdminCP. Confirm first that your phpFox build actually has the gateway enabled: if AdminCP → Apps shows no active PayPal, Stripe, or Authorize.Net package, there is no payment workflow to troubleshoot and the symptoms you see are a configuration gap, not a delivery failure.
Why checkout starts but the subscription never activates
The classic phpFox symptom is a user who clicks through to PayPal, pays successfully, lands back on your site, yet keeps the free membership level. The payment cleared on the processor side, but phpFox never recorded it because the Instant Payment Notification (IPN) or webhook callback failed to reach your listener. phpFox exposes these endpoints through its router, typically at a path such as https://yourdomain.com/payment/paypal/callback or the Stripe variant under the same /payment/ segment. The processor POSTs transaction data to that URL; phpFox validates it and then upgrades the account.
The first thing to verify is that the callback URL is publicly reachable with a clean 200 response and no redirect chain in the way. Open the URL directly in a browser. A 404 means the phpFox rewrite rules are not loading, which points at .htaccess. phpFox needs its front-controller rewrite intact in the document root .htaccess:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?_p=$1 [L,QSA]If you forced HTTPS or added a www canonical redirect, make sure those rules sit above the phpFox block and are limited to GET traffic patterns that will not strip the POST body from an incoming webhook. A redirect from http to https on the callback path will cause many gateways to drop the POST payload, so the processor records a delivery attempt while phpFox sees nothing. Register the HTTPS version of the callback URL inside the gateway dashboard so no redirect is ever needed.
A second common blocker is a WAF or hotlink rule that treats the external processor's POST as suspicious. In cPanel under Security → ModSecurity you can check whether rules are firing for your domain; if a specific rule ID is blocking PayPal's IPN verification postback, open a ticket asking for that single rule to be whitelisted for the callback path, since you cannot edit server ModSecurity config yourself. You can, however, relax your own .htaccess access controls. If you added an IP allow-list or a Require directive to protect a directory, confirm it does not cover /payment/.
Repairing outbound cURL and TLS handshake failures
The outbound direction breaks when phpFox cannot complete a TLS handshake with the gateway API. In phpFox this surfaces as a checkout that never redirects, a blank gateway page, or a logged error similar to cURL error 60: SSL certificate problem or cURL error 35. Modern processors require TLS 1.2 or 1.3 and current cipher suites, and they reject clients presenting an outdated CA bundle. Because you cannot touch the system OpenSSL or php.ini globally, the correct lever is the CloudLinux PHP Selector.
Open cPanel → Select PHP Version (or DirectAdmin → Select PHP Version) and confirm phpFox is running on a supported branch, PHP 8.1 or newer for current phpFox releases. In the Extensions tab, ensure curl and openssl are both checked. A missing openssl extension produces immediate handshake failures that look like network outages but are purely a PHP configuration gap. After enabling an extension, trigger a test checkout again; LiteSpeed will spawn a fresh PHP worker with the new module loaded.
If the handshake still fails with a certificate verification error, the CA bundle phpFox is referencing is stale. Rather than disabling verification, point PHP at a fresh bundle through a .user.ini file in your document root:
; placed in the phpFox document root
curl.cainfo = "/home/youruser/public_html/cacert.pem"
openssl.cafile = "/home/youruser/public_html/cacert.pem"Download the current cacert.pem from the curl project, upload it through File Manager to the path you referenced, and wait a few minutes for the .user.ini cache to refresh (the default refresh window is 300 seconds). Never resolve a TLS error by setting CURLOPT_SSL_VERIFYPEER to false in phpFox code; that disables the very validation the gateway requires and will fail PCI review. Confirm the fix by loading AdminCP → phpInfo and checking that the curl.cainfo value now reflects your bundle.
API credentials, environment mode, and transaction logging
With both traffic directions flowing, wrong or mismatched credentials are the remaining failure class. In AdminCP → Apps → Installed, open the payment gateway settings and verify the API keys. A frequent mistake is leaving the gateway in sandbox or test mode while using live keys, or the reverse. PayPal sandbox credentials will authenticate but never move real money, and Stripe test keys (prefixed pk_test_ and sk_test_) will reject live card tokens. Match the environment toggle to the key type, and for Stripe register your webhook endpoint in the Stripe dashboard with the signing secret copied back into phpFox so signature verification passes.
Store the live secret keys carefully. phpFox keeps gateway settings in the database, so you can audit them through phpMyAdmin by inspecting the settings table (commonly phpfox_setting) filtered on the payment module, but avoid editing values there directly unless the AdminCP form is inaccessible, because phpFox caches setting values and a raw edit can drift out of sync until you clear AdminCP → Maintenance → Cache.
When something still fails quietly, the local error_log is your evidence trail. phpFox writes framework errors into log files under PF.Base/file/log/ and PHP itself writes to an error_log in the directory where the fault occurred; use File Manager to open the most recent entries right after a failed checkout. Enable detailed logging temporarily through AdminCP → Settings → General by switching debug output on, reproduce one transaction, then switch it off so stack traces are never exposed to visitors. For a parallel example of diagnosing enrolment callbacks and gateway TLS on the same platform, the Moodle payments and webhooks guide covers the same cURL and credential patterns from a different CMS angle.
Build a short verification loop for every change: place one test subscription purchase, watch the gateway dashboard to confirm the callback was delivered with a 200, then confirm in AdminCP → Members that the account upgraded and that a row appears in the phpFox invoice or transaction listing. If the callback shows delivered but the membership did not change, the problem has moved from delivery to validation, usually a mismatched webhook secret or an IPN verification postback that your WAF is blocking. Isolating which of the three stages, outbound call, inbound callback, or record write, actually broke keeps the fix inside tools you fully control on a shared account.