- Docs
- Troy Server
- Server Troubleshooting
Troubleshooting
This page covers common problems and their fixes. For setup instructions and requirements, see Installation.
Package Installation
Plugin Installation Failed
- Check that the bundled plugin exists and has a Tag or Beta version available.
- Verify that the plugin status is Public or Unlisted.
- Ensure that the server is accessible from the user's WordPress site.
Troy Client Installation Failed
- Check connectivity to
repo.deploytroy.org. - Verify that the user's hosting allows outbound HTTPS connections.
- Check available disk space on the user's server.
Package Not Downloading
- Check that the package is published (not still in draft).
- Ensure that the package slug is correct in the URL.
Plugin Distribution Issues
Users Can't Download
- Plugin set to "Public"? Check the status in the Troy Server admin.
- Test the URL: Visit
https://repo.example.org/plugin/get/zip/your-pluginin your browser.
Downloads Fail with Invalid URL Error
If you see Download failed. A valid URL was not provided. while installing plugins through a package (with notice severity set to verbose), the URL is usually correct. This message is misleading — WordPress blocks HTTP requests to localhost and loopback addresses as protection against Server-Side Request Forgery (SSRF).
Fix: If you're developing locally, add this filter to allow loopback requests:
add_filter( 'http_request_host_is_external', '__return_true' );
Local Development Only:
Never use this filter on a production server. It disables WordPress's SSRF protection, exposing your site to request-forgery attacks.
Updates Not Showing for Users
- Troy Client installed? Updates require it.
Troyheader present? Check for aTroyheader pointing to your server URL in the plugin's main file.- Version higher? The server version must exceed the installed version.
- URL matches exactly? The
Troyheader value must match your server's domain — including or excludingwww.
GitHub Integration
Repository Not Found
- Use the
username/repositoryformat, not the full URL. - Private repos need a token with
reposcope. - Check for typos in the repository name.
Releases Not Fetching
- Use semantic version tags like
v1.0.0, notrelease-2024. - Create a Release on GitHub, not just a tag.
- If using webhooks, verify that the URL and secret match.
Rate Limiting
Add a Personal Access Token — even for public repos. This increases the GitHub API limit from 60 to 5,000 requests per hour.
API Issues
REST API Returns 403
- Security plugins may block REST endpoints.
- Check
.htaccessfor rules that block JSON responses. - Verify that WordPress isn't in maintenance mode.
Composer Endpoints Blocked by ModSecurity
If your server runs Apache or LiteSpeed with ModSecurity and the OWASP Core Rule Set, Composer requests to your Troy Server will fail with a 403 error. OWASP CRS rule 930130 blocks requests to /packages.json and similar paths.
This affects all Composer endpoints under /composer/get/.
There are two problems to fix:
- Rule 930130 blocks Composer metadata requests. ModSecurity intercepts the request before WordPress can handle it.
- 403 response body leak. When ModSecurity sends a 403, Apache's RewriteEngine still renders the full response body — leaking output that should be suppressed.
Both fixes require SecRule directives at the server or vhost level. These directives are not allowed in .htaccess — they cause a 500 Internal Server Error even inside an <IfModule> check.
Add ModSecurity Rules
Add these rules through your control panel:
- WHM (cPanel): Go to Security Center → ModSecurity Tools → Rules List → Edit Rules and add them to the Rules section.
- DirectAdmin: Add them to
/usr/local/directadmin/data/admin/modsecurity_rules, then runda build rewrite_confs. - Plesk: Go to Tools & Settings → Web Application Firewall (ModSecurity) → Settings and add them to the Custom Directives section.
# Allow 403 responses through so .htaccess rewrite rules can suppress the body.
SecRule RESPONSE_STATUS "@streq 403" "phase:response,id:1002,t:none,nolog,pass"
# Disable OWASP CRS rule 930130 for Composer endpoints.
SecRule REQUEST_URI "@beginsWith /composer/get/" "id:1003,phase:1,pass,nolog,ctl:ruleRemoveById=930130"
Suppress Leaked Response Bodies
In your .htaccess, add this rule above the WordPress rewrite block:
RewriteEngine On
# Suppress leaked 403/404 response bodies from ModSecurity.
# Requires the SecRule passthrough directive above.
RewriteCond %{ENV:REDIRECT_STATUS} ^40[34]$
RewriteRule ^ - [END]
Not Troy-Specific:
The 403 response body leak affects any WordPress site running ModSecurity with OWASP CRS — not just Troy Server. Until the ModSecurity passthrough rule is in place, any 403 response from your server may leak sensitive data.
Slow Downloads
- Don't use caching plugins — they cause more problems than they solve on a Troy Server.
- Use a CDN for static assets, but exclude REST API endpoints.
- Check server resources and upgrade if needed.
Background Tasks Not Running
Troy Server uses WordPress cron for stats aggregation, GitHub webhook processing, and transient cleanup. If background tasks aren't running, verify that you've set up a real cron job — see Set Up Real Cron on the installation page.
File Recovery (Graveyard)
Accidentally deleted a plugin or package? Troy Server doesn't destroy files immediately — it moves them to a "graveyard" directory for manual recovery.
Where Files Go
When you delete a plugin or package from the WordPress admin:
| Content Type | Graveyard Location |
|---|---|
| Plugins | wp-content/uploads/troy-plugins-graveyard/plugin-{id}/ |
| Packages | wp-content/uploads/troy-packages-graveyard/package-{id}/ |
The {id} is the plugin or package's database ID, visible in the admin URL when editing the item.
Recovery Steps
- Find the graveyard folder for the deleted item.
- Copy the contents back to the active storage directory:
- Plugins:
wp-content/uploads/troy-plugins/plugin-{id}/ - Packages:
wp-content/uploads/troy-packages/package-{id}/
- Plugins:
- Restore the database entry from a database backup.
Database Recovery Requires a Backup:
Re-adding the plugin or package through the WordPress admin creates a new database entry with a different ID — it won't match the graveyard folder. To fully restore a deleted item, you need a database backup from before the deletion.
No Automatic Cleanup:
Graveyard directories are not automatically purged. Check these folders periodically if disk space is a concern.
Disable Instead of Deleting:
Set a plugin or package to Disabled instead of deleting it. This keeps files intact while blocking public access — no graveyard recovery needed.
Getting Help
- GitHub Issues — bug reports.
- GitHub Discussions — questions.
- WordPress error log — check
wp-content/debug.logfirst.
When reporting issues, include your WordPress version, PHP version, Troy Server version, and any relevant error messages.
