Application Detection
Stop hunting for wp-config.php
Point the scanner at a server and it finds the sites, reads each one’s database credentials out of its own config file, and offers you a matched file and database job per install.
Scan server
Looks for WordPress, Laravel, Craft CMS, Ghost, and Nextcloud installs in common web-root locations. Database credentials are read automatically where the config format allows it.
Storage destination for created jobs
www/acme-blog
/var/www/acme-blog
File backupDatabase backup (acme_blog)
www/acme-app
/var/www/acme-app
File backupDatabase backup (acme_app)
sites/acme-docs
/home/deploy/sites/acme-docs
File backupDatabase backup (ghost_prod)
One find command, six places it looks
There is no daemon, no plugin to install, and no control-panel integration to authorise. The scan is a read-only SSH session that runs this and then reads what it matched.
$ find <roots> -maxdepth 3 \
\( -name wp-config.php \
-o -name config.production.json \
-o -name .env \) 2>/dev/nullThe roots are shell globs, expanded by your own shell — a pattern that matches nothing contributes nothing rather than erroring the scan. That is why a server with only /var/www on it never has to care that the Cloudways and Forge paths are in the list.
The six roots
- /var/www
- The default nearly everywhere, and where GridPane and SpinupWP put site roots
- /home/*/public_html
- Per-user document roots on cPanel-style and hand-rolled setups
- /home/*/htdocs
- The same convention under its other common name
- /home/master/applications/*/public_html
- Cloudways’ application layout
- /home/forge/*
- Laravel Forge’s per-site directories
- /srv/www
- The FHS-tidy alternative to /var/www
What can be read, platform by platform
Five platforms get their database credentials extracted automatically. Everything else that carries a .env is still detected and still gets a file job — it just arrives without a database job attached.
| Platform | Found by | Engine | Credentials read from | Default excludes |
|---|---|---|---|---|
| WordPress | wp-config.php | MySQL | DB_NAME, DB_USER, DB_PASSWORD, DB_HOST read from the define() calls | none by default |
| Laravel | .env beside an artisan file | MySQL, PostgreSQL or SQLite | DB_DATABASE, DB_USERNAME, DB_PASSWORD, DB_HOST; engine chosen from DB_CONNECTION. On SQLite, the default since Laravel 11, the database file goes in the file job instead, copied safely | vendor, node_modules, storage/logs/* |
| Craft CMS | .env beside a craft file | MySQL or PostgreSQL | CRAFT_DB_DATABASE, CRAFT_DB_USER, CRAFT_DB_PASSWORD, CRAFT_DB_SERVER, falling back to the unprefixed v3 names | vendor, node_modules, storage/runtime/logs/* |
| Ghost | config.production.json | MySQL only | database.connection read from the JSON, but only when database.client is mysql | node_modules, content/logs/* |
| Nextcloud | config/config.php, with occ beside it and Nextcloud named in version.php | MySQL, MariaDB or PostgreSQL; SQLite in the file job | dbname, dbuser, dbpassword and dbhost, with its port or socket, from config.php; the data directory from datadirectory, added to the file job when it lives elsewhere | none by default |
| Anything else with a .env | .env with no artisan or craft alongside it | — | Not read — the file job is still created, the database job is not | node_modules, vendor |
Craft names moved in v4
Craft 4 and 5 prefix their variables CRAFT_DB_*, Craft 3 leaves them unprefixed. Both are checked, prefixed first — but a site that has renamed them beyond either convention is detected as Craft without credentials.
SQLite goes in the file job
Ghost, Laravel and Nextcloud can each run on SQLite, and then there is no database server to dump. The file job carries the database instead, copied with SQLite’s own backup API rather than read while it is written. That needs python3 or sqlite3 on the server; without either, the run’s log says the file was copied as is.
WordPress ships with no excludes
A WordPress tree is small and almost entirely worth keeping, so nothing is excluded by default. If you run a page-cache plugin that writes gigabytes under wp-content, add that directory to the job’s exclude list after it is created.
What one click actually creates
Detection is a shortcut to two ordinary backup jobs. Nothing it makes is special, hidden, or harder to change afterwards.
Step 1
A file job pointed at the install directory
Named after the last two segments of the path — “www/acme-blog files” — archiving the directory the signature file was found in, with that platform’s default excludes already filled in.
Step 2
A database job, when there was something to read
Created only when the scan came away with both an engine and a database name. No half-configured job with a blank password is ever left behind for you to discover on the first failed run.
Step 3
Sensible defaults you can immediately override
Both jobs arrive enabled, running daily at 02:00, with seven-day retention, failure alerts on and success alerts off. Every one of those is a normal field on a normal job — reschedule, rename, or re-point them the moment they exist.
Step 4
One decision left to you: where it goes
You pick the storage destination before creating anything, so the jobs land in the bucket you meant. Scan a server twice and you can send staging and production to different buckets.
Where the scan comes up empty
Detection is a convenience layer over file and database jobs. When it misses, nothing is lost — you configure the same two jobs yourself.
Four filenames, three or four levels deep
The scan looks for wp-config.php, config.production.json and .env up to three levels down, and Nextcloud's config/config.php up to four. A release-directory deploy that buries the .env at /var/www/site/releases/20260902/.env is four levels down and won’t be seen.
Six roots, all conventional
If your sites live somewhere the list above doesn’t cover — /opt, /data, a mounted volume — the scan finds nothing there. That isn’t a dead end, it just means creating the file and database jobs by hand, which takes about a minute.
Platforms that use none of those files
Drupal, TYPO3, Rails, and plain static builds keep their configuration somewhere else entirely, so there is no signature to match and they aren’t detected at all. Nothing stops you backing them up — detection is a shortcut, not the gate.
Anything running inside a container
The scan reads the host filesystem over SSH. A WordPress living in a container is a Docker job, not an application job — back up the named volumes and the compose file instead.
Hosted and headless CMSs
Sanity, Contentful, and their neighbours keep no files and no database on your server, so there is nothing on disk to detect. Their own export tooling is the right way to back those up.
No inbound SSH at all?
Detection needs an SSH connection from us to the server. On private infrastructure, the Agent runs file and database jobs from inside your network instead — you just configure them rather than scanning for them.
Prefer to follow along step by step? Read the detection guide in the help centre.
FAQs
Can’t find the answer you’re looking for? Reach out to our support team.
Does the scan change anything on my server?
No. It opens an SSH connection, runs one find command, and reads the config files that matched. Nothing is written, installed, restarted, or left behind — and if a file can’t be read, that file is skipped rather than failing the whole scan.
Where do the database passwords end up?
They are read out of the application’s own config during the scan and stored against the database job encrypted with AES-256-GCM, the same as any credential you type in yourself. They are never displayed back to you and never written to the database in plaintext.
What happens when I rotate that password later?
The database job keeps the credential captured at scan time, so rotating the password will start failing the job until you update it. Either edit the job’s credentials directly or run the scan again — nothing re-reads wp-config.php or .env on its own.
Does this work on Cloudways, Forge, GridPane, or SpinupWP?
Yes, on any of them, because the scan matches web-root conventions rather than a control panel’s API. Cloudways’ /home/master/applications/*/public_html and Forge’s /home/forge/* are searched explicitly, and GridPane and SpinupWP both sit under /var/www. All that’s required is an SSH connection VPS Snaps can use.
What if one server hosts a dozen sites?
Each install is listed separately with its own path, detected type, and its own Create backup jobs button, so you can take the four that matter and leave the staging copies alone. There is no bulk-create-everything button on purpose.
What do I see if nothing is found?
A plain message saying no recognisable applications were found in the common web-root locations — not an error. It usually means the sites live outside the six search roots, or the platform doesn’t use one of the three signature files.
The job types underneath
Detection creates these two together. Both work perfectly well on their own, on any server you can reach.
File backups
The job type detection creates for you, configured by hand: any path, your own exclude patterns, one gzipped tar per run.
Read moreDatabase backups
The other half of the pair. pg_dump and mysqldump over SSH for PostgreSQL, MySQL, and MariaDB, on whatever schedule you set.
Read moreVPS snapshots
When you would rather have the whole machine back than its parts — provider-native snapshots across eight clouds.
Read moreEverything else it does
Storage, schedules, alerts, recovery and team access, in one place. Which plan each one starts on is on the pricing page.
- Bring your own storage
- Backups land in your own S3-compatible bucket — Backblaze B2, Wasabi, Cloudflare R2, or plain S3 — or in your own Google Drive, Box, Dropbox or OneDrive. You hold the keys and the data.
- Snapshots stay with your provider
- Provider snapshots are created through the provider's own API and never leave your account. We store the snapshot ID, not the image.
- Eight providers, one dashboard
- DigitalOcean, Hetzner, Vultr, Linode, AWS EC2, AWS Lightsail, Google Compute Engine and Microsoft Azure — scheduled and reviewed from the same place.
- A replacement server on demand
- Recover now builds a new server on your own DigitalOcean, Hetzner, Vultr, Linode, AWS EC2, AWS Lightsail, Azure or Google Compute Engine account, from its snapshot or from its backups, software included.
- Failover on any cloud
- When a server stops answering, its traffic moves to the recovery server: by reserved or floating IP where your cloud has one, or by your DNS on Cloudflare, which works on every cloud.
- Know it's down, with the way back
- Uptime monitors for sites, ports and scheduled jobs confirm an outage before alerting, name the server's newest backup, and publish a status page. On paid plans.
- Your DNS zones, backed up
- Every record in a Cloudflare zone, kept in your own storage as a BIND file too. A restore previews what differs and writes back only that.
- Schedules that fit your traffic
- Hourly, daily, weekly, monthly, or a fixed interval in minutes — anchored to your timezone, so a 02:00 job stays at 02:00 across a DST change.
- Retention that prunes itself
- Set how many days to keep. Older snapshots and archives are cleaned up after each successful run, so storage bills stay flat.
- Every run on record
- Status, duration, size and trigger, with each step it took in order and its warnings and errors kept in place — so a failure tells you which step broke.
- Checksummed on upload
- Every archive is hashed as it streams to your bucket and the checksum is stored with the run, so you can verify what landed.
- Run on demand
- Trigger any job by hand before a migration or a risky deploy, without touching its schedule or its retention window.
- Alerts on five channels
- Email plus Slack, Microsoft Teams, Google Chat, and Discord — on success, on failure, and on a job that missed its schedule entirely.
- Encrypted credentials
- SSH keys, database passwords, and storage secrets are sealed with AES-256-GCM before they touch the database.
- Team access with roles
- Invite your team into a shared workspace as owner, admin, or member, so backups outlive whoever set them up.

“I'm constantly spinning up WordPress and Laravel applications for clients, and backups are one of those things that are easy to put off until something goes wrong. VPS Snaps can detect the applications on a server and help create the file and database backup jobs, which makes getting proper backups in place much faster.”
Find out what is actually running on that server.
Connect it over SSH, run one scan, and turn every site it finds into a pair of backup jobs before you have finished your coffee.
No credit card required. Cancel anytime.