🏠 The Ridiculous Letter: Why Using `wget` in Cron to Call Your Own Website Is a Bad Idea

Imagine that you have a house.

Every evening at 8 PM, you have to tidy your bedroom.

Pretty simple, right?

You are already inside the house. Your bedroom is upstairs.

So you walk upstairs, open the door, and tidy your room.

But what if, instead, you decided to do this:

« I am going to send myself a letter asking myself to tidy my bedroom. »

Sounds ridiculous?

That’s exactly what happens when a cron job uses wget to call an URL on the same server.


📮 The ridiculous letter

Let’s imagine your server is your house.

Your application is inside the house.

Your PHP code is inside the house.

Your database is inside the house.

Your cron job is also inside the house.

Everything you need is already there.

But instead of directly executing the code, the cron job does something like:

wget https://www.example.com/cron/my-task          

In other words:

« Hey website, could you please call yourself and execute this task? »

Let’s see what happens.

❌ The wget approach

You need to tidy your bedroom at 8 PM.

Instead of going upstairs, you:

  1. 📝 Write a letter: « Dear me, please tidy my bedroom. »
  2. 📮 Put it in an envelope.
  3. 🚶 Leave your house.
  4. 🚶 Walk to the mailbox.
  5. 📬 Put the letter in the mailbox.
  6. 🚚 The postal service collects it.
  7. 🏢 The letter goes through the postal system.
  8. 🚚 The letter eventually comes back to your neighborhood.
  9. 📭 The letter is delivered to your own mailbox.
  10. 🚶 You go outside and get it.
  11. 📖 You open the letter.
  12. 🤔 You read: « Please tidy your bedroom. »
  13. 🏠 You finally go upstairs.
  14. 🧹 You tidy the room.

Congratulations.

You have successfully used the entire postal system to tell yourself something you already knew.


💻 What does this look like on a real server?

The same thing happens technically.

A cron job might contain:

*/5 * * * * wget -q -O /dev/null https://www.example.com/cron/process-orders

At first glance, this may look perfectly reasonable.

Every five minutes, the server calls an URL.

But look at what is actually happening.

The request has to go through the web stack:

CRON
  │
  ▼
wget
  │
  ▼
DNS / hostname resolution
  │
  ▼
Network
  │
  ▼
Firewall / load balancer / CDN / proxy
  │
  ▼
Web server
  │
  ▼
PHP / PHP-FPM
  │
  ▼
Magento / application
  │
  ▼
Task

And all of this happens to execute code that is already on the same machine.

It is the technical equivalent of walking around the block to enter your own front door.


🏠 The better solution: use the stairs!

If the code is already on the server, the simplest solution is usually to execute it directly.

Instead of:

wget https://www.example.com/cron/process-orders

you could have a CLI command:

php bin/my-command

And your cron becomes:

*/5 * * * * php /path/to/application/bin/my-command

Now the journey looks more like this:

CRON
  │
  ▼
PHP CLI
  │
  ▼
Application
  │
  ▼
Task

That’s it.

No letter.

No mailbox.

No postal service.

No trip around the city.

Just:

🏠 « I’m already home. I’ll just walk upstairs. »


🚀 1. It’s faster

An HTTP request introduces additional work.

Even on the same server, you may have:

  • DNS resolution
  • TCP connections
  • TLS negotiation if using HTTPS
  • HTTP processing
  • web server processing
  • PHP-FPM
  • HTTP headers
  • authentication
  • routing
  • application bootstrap
  • network timeouts

A CLI command can avoid most of this.

This becomes particularly important when the cron task runs frequently or performs heavy processing.

A task running every minute doesn’t need to spend part of every minute pretending to be an external visitor.


🧠 2. The application knows it’s a scheduled task

A CLI command can be designed specifically for background processing.

For example:

php bin/magento my:process-orders

The application knows:

« This isn’t a customer visiting a webpage. This is a scheduled background operation. »

That’s a much cleaner separation.

An HTTP controller, on the other hand, is designed to handle an HTTP request.

Using a web URL as a replacement for a CLI command mixes two different responsibilities:

HTTP
  → customer/browser/API requests

CLI
  → server-side commands/jobs/maintenance

🔐 3. It reduces your attack surface

This is perhaps the most important point.

Suppose you create:

https://www.example.com/cron/process-orders

You now have an HTTP endpoint that triggers an administrative operation.

Even if you try to hide it, the URL exists.

Someone can potentially discover it.

Someone can call it.

Someone can call it repeatedly.

Someone can try to manipulate parameters.

Someone can generate thousands of requests.

And suddenly your « private cron URL » isn’t really private anymore.

« But we can add a secret token! »

Yes.

For example:

https://www.example.com/cron/process-orders?token=ABC123

That’s better than nothing.

But now you’re building an authentication mechanism for an HTTP endpoint…

…because you wanted to execute a local task.

The CLI version can instead rely on the server’s existing permissions and execution environment.

php bin/my-command

No public URL required.

No HTTP endpoint required.

No secret token in a URL.


🐌 4. HTTP introduces failure points you don’t need

Remember our postal service?

The letter can get lost.

The same principle applies to HTTP.

Your request can fail because of:

  • DNS problems
  • connection failures
  • firewall rules
  • reverse proxy problems
  • CDN configuration
  • SSL certificate issues
  • HTTP timeouts
  • web server limits
  • PHP-FPM limits
  • rate limiting
  • WAF rules
  • authentication
  • maintenance mode
  • incorrect routing
  • a web server restart

And the application task itself may be perfectly healthy.

Imagine discovering this at 8:05 AM:

« The nightly order processing didn’t run. »

Why?

Because the web server had a temporary problem.

That’s frustrating when the job could simply have been executed locally.


⏱️ 5. Timeouts become especially annoying

HTTP requests are designed around the idea that a client sends a request and eventually receives a response.

But background jobs can take a long time.

For example:

Process 10 products       → 2 seconds
Process 1,000 products    → 3 minutes
Process 100,000 products  → 45 minutes

If you trigger the job through HTTP, you now have to think about:

HTTP timeout
Nginx timeout
PHP timeout
PHP-FPM timeout
proxy timeout
CDN timeout

The task might still be running…

…while the HTTP client has already given up.

That’s another unnecessary complication.

A CLI process is much more natural for long-running jobs.


📊 6. Monitoring is easier

A proper CLI command can return an exit code.

For example:

php bin/my-command

can return:

0 → success
1 → error

Cron and monitoring systems understand this very well.

You can also log meaningful information:

Starting order processing...
1,245 orders found
1,245 orders processed
17 errors
Process completed   

With an HTTP request, you often end up with something like:

wget ...

and then you have to inspect HTTP status codes, output, logs, response bodies, etc.

Again: more machinery for the same job.


🧱 7. It bypasses the normal web traffic

This is particularly important for an e-commerce website.

Your website is designed to serve customers.

Customers generate HTTP traffic:

Customer
   ↓
Website
   ↓
Magento        

Your background jobs are different:

Cron
   ↓
CLI
   ↓
Magento  

You don’t necessarily want an internal background task to compete with customer traffic through the same HTTP infrastructure.

Otherwise, your server can end up doing this:

Customers ┐
          ├──→ Web Server → PHP-FPM → Magento
Cron jobs ┘   

When the cron jobs could instead be handled separately:

Customers ──→ Web Server ──→ PHP-FPM

Cron ──────→ CLI ──────────→ Application

This doesn’t magically make the job cheaper—it still consumes CPU, memory, database connections, etc.—but it removes unnecessary web-layer overhead and makes the architecture clearer.


⚠️ But is wget always wrong?

No.

This is important.

Using wget to call an HTTP endpoint is not inherently bad.

HTTP is exactly what you should use when the task is genuinely an HTTP operation.

For example:

wget https://api.example.com/import          

might be perfectly legitimate if:

  • the API belongs to another server
  • the service is external
  • the endpoint is intentionally public/private API infrastructure
  • the application is deliberately designed around HTTP
  • the request must go through an HTTP gateway

The problem is specifically this pattern:

A cron job on your server calling an HTTP URL on the same application, just to execute local code.

That’s where the architecture starts looking like the person mailing a letter to themselves.


🧑‍💻 Magento makes this particularly obvious

In Magento, you already have a CLI framework.

For example:

bin/magento

Magento commands are designed for exactly this kind of operation.

Instead of creating:

https://www.example.com/custom/cron/run

you can create something like:

bin/magento vendor:module:process

And your cron can execute:

*/5 * * * * php /path/to/magento/bin/magento vendor:module:process

This gives you a clear distinction:

Web Controller
    ↓
HTTP request
    ↓
Customer / external system


CLI Command
    ↓
Scheduled job
    ↓
Cron / administrator / deployment

Much easier to understand.

Much easier to secure.

Much easier to monitor.


🏁 The simple rule

Here’s the rule I would use when reviewing an existing application:

🌍 Calling another server?

Use HTTP.

Server A ──HTTP──→ Server B

That’s normal.

🏠 Calling your own application from the same server?

Prefer CLI.

Cron ──→ CLI ──→ Application

Rather than:

Cron ──→ wget ──HTTP──→ Your own website

📨 The final version of our story

So, if someone asks:

« Why is using wget in cron to call our own website a bad practice? »

You can simply tell them:

Imagine you’re inside your house and you need to tell yourself to clean your bedroom.

You could walk upstairs and clean it.

Or you could write yourself a letter, put it in the mailbox, wait for the postal service to deliver it, collect the letter, read it, and then finally go upstairs.

Both methods work.

But one of them is obviously ridiculous.

That’s what calling your own website with wget from cron can be.

If the code is already on the server, execute it directly with CLI whenever possible.

Don’t leave the house just to send yourself a letter. 🏠📮

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *