Skip to main content

Scheduled Tasks in Joomla

15 June 2026

Every website has chores that nobody wants to do by hand. Old log files pile up. Expired sessions clog the database. Articles stay locked because an editor closed the browser tab without saving. Someone really should check whether a new Joomla version is out. These jobs are boring, repetitive, and easy to forget, which is exactly why they should run on their own.

Joomla handles them with a quiet core component called Scheduled Tasks (com_scheduler). It is Joomla's built-in task scheduler: you define a job once, give it a timing rule, and Joomla runs it again and again without you lifting a finger. No third-party extension and no shell access required.

Set it once, and let Joomla do the chores you keep forgetting.

This article explains how the Scheduler really works. It covers the basics for owners and editors, the daily setup and timing rules for administrators, and the task plugins, database schema, locking model, and PHP API for developers. The goal is to help you trust the Scheduler enough to hand it your routine maintenance with confidence.

1. The Basics

1.1 What Are Scheduled Tasks?

The Scheduled Tasks component (com_scheduler) lets you run a piece of work automatically on a timing rule. Joomla introduced it in version 4.1 (early 2022), and it has shipped in core ever since. It replaces the old pattern of writing your own cron scripts for routine Joomla maintenance.

A few ideas make it special:

  • Each task is one row in a single table: #__scheduler_tasks.
  • A task does not contain code. It points to a task routine that a plugin provides. The plugin does the actual work.
  • Timing is data, not code. You pick a rule ("every 6 hours", "every night at 03:00", or a full cron expression) and Joomla calculates the next run.
  • Tasks can run from web traffic, from a real server cron, from the command line, or from a secure webcron URL. You choose.

In short: the component is the manager, the plugins are the workers, and the table is the to-do list.

1.2 Where Do I Find It?

In the Joomla 6 backend, these places are relevant:

System → Manage → Scheduled Tasks            (the task list)
System → Manage → Scheduled Tasks → New      (create a task)
System → Manage → Scheduled Tasks → Options  (settings + ACL)
System → Manage → Plugins (filter "Task")     (the task routines)

The component lives at administrator/components/com_scheduler/. The task routines live as plugins under plugins/task/. There is one more piece: a system plugin, System - Schedule Runner (plg_system_schedulerunner), which lets web visitors trigger due tasks in the background.

1.3 The Three Pieces

Scheduled Tasks is built from three parts that work together:

PartRole
com_scheduler The component. Lists tasks, edits timing rules, shows the last result, and runs the dispatch engine.
plg_task_* The task plugins. Each one advertises one or more routines and does the real work when its routine is called.
plg_system_schedulerunner The system plugin that triggers due tasks from web traffic, the webcron URL, or the backend "Test Run" button.

Disable the task plugin and its routine disappears from the "New Task" list. Disable the Schedule Runner and the web-based triggering stops, although a real server cron still works.

1.4 A Task vs a Routine

This distinction trips up a lot of people, so fix it early:

  • A routine is a capability that a plugin offers, identified by a string such as session.gc or delete.actionlogs. It is the same for every site.
  • A task is your configured instance of a routine: a title, a timing rule, some parameters, and a state. You can create several tasks from the same routine, for example two "Make a GET request" tasks pointing at two different URLs.
A routine is the recipe. A task is the meal you actually scheduled.
Back to top

2. Creating Your First Task

2.1 The Steps

Open System → Manage → Scheduled Tasks and click New. Joomla shows you the list of available routines from every enabled task plugin. Pick one, for example Session GC, and you land on the task edit screen.

You fill in three things that matter:

  1. Title: a name you will recognise later, such as "Clean expired sessions".
  2. Schedule: the timing rule (covered in section 4).
  3. Parameters: routine-specific options, shown only if the routine needs them.

Save the task. Joomla immediately calculates the next_execution time and the task appears in the list, enabled and waiting.

2.2 Reading the Task List

The list view is your dashboard. For each task it shows:

ColumnMeaning
Status Enabled, disabled, or trashed.
Task Your title plus the routine type.
Last Run / Next Run When it last ran and when it is due again.
Last Exit Code The numeric result of the last run (0 means success).
Times Run Total successful executions and failures.

Each row has a Test Run icon. Click it and Joomla runs that one task right now, in the background, and refreshes the exit code. This is the fastest way to confirm a task works before you trust it to a schedule.

2.3 The Last Exit Code Is Your Friend

After a run, the last_exit_code column tells you what happened. A green 0 means the routine finished cleanly. Any other number points to a problem, and section 6 lists what each code means. Get into the habit of glancing at this column. A task that quietly fails every night is worse than no task at all, because you assume the chore is done.

Back to top

3. The Core Task Types

Joomla 6 ships nine task plugins out of the box. Together they cover the most common maintenance chores. Here is what each one does and the routine id it provides.

PluginRoutine idWhat it does
Check Files (Image Size) checkfiles.imagesize Scans a folder for images larger than a set limit and resizes them.
Delete Action Logs delete.actionlogs Purges User Action Log rows older than a chosen age.
Global Check-in plg_task_globalcheckin_task_get Releases items left "checked out" (locked) by users.
Privacy Consent privacy.consent Invalidates expired privacy consents and reminds users to renew.
Requests (GET request) plg_task_requests_task_get Sends an HTTP GET to a URL you choose. Great for pinging webhooks.
Rotate Logs rotation.logs Archives and trims Joomla log files so they do not grow forever.
Session GC session.gc Garbage-collects expired user sessions from the session store.
Site Status plg_task_toggle_offline Puts the site online or offline on a schedule (toggle, set online, set offline).
Update Notification update.notification Emails super users when a new Joomla core version is available.

Two of these deserve a special mention. Update Notification turns Joomla into something that watches its own version for you, which is one of the simplest security wins on any site. And Requests is the bridge to the outside world: schedule a GET to a webhook and you can trigger anything an external service exposes, from a Slack message to a cache warm-up on a CDN.

Back to top

4. Scheduling Rules

4.1 The Rule Types

Every task stores its timing in the execution_rules field as JSON. On the edit screen you pick a rule type, and the form shows the matching inputs:

Rule typeYou setExample
interval-minutes A number of minutes Every 15 minutes
interval-hours A number of hours Every 6 hours
interval-days A number of days plus a time Every 1 day at 03:00
interval-months A number of months, day, and time Every 1 month on day 1 at 04:00
cron-expression A full cron pattern 0 3 * * 1 (Mondays at 03:00)
manual Nothing; no automatic run Run only via Test Run or CLI

The interval rules are easy and good enough for most chores. The cron expression gives you the full power of standard cron timing when you need precise control.

4.2 The Cron Expression

Behind the scenes Joomla uses a real cron parser, so the five-field syntax you may know from Linux works exactly as expected:

┌───── minute        (0 - 59)
│ ┌──── hour          (0 - 23)
│ │ ┌─── day of month  (1 - 31)
│ │ │ ┌─ month         (1 - 12)
│ │ │ │ ┌ day of week   (0 - 6, Sunday = 0)
│ │ │ │ │
*  *  *  *  *

So */30 * * * * runs every 30 minutes, 0 2 * * * runs daily at 02:00, and 0 4 1 * * runs at 04:00 on the first of every month. When you save, Joomla converts your rule into the cron_rules field and works out the next run time from it.

4.3 Next Execution Is Calculated, Not Stored Forever

The next_execution column is Joomla's plan for when the task is due. After each successful run Joomla recalculates it from the rule. A manual task has no next time, so its next_execution is left empty and it never fires on its own. If a task ever looks "stuck in the past", that simply means its trigger has not fired since the due time arrived, which leads us to the next section.

Back to top

5. How Tasks Actually Run

Defining a task does not make it run. Something has to wake the Scheduler up and ask "is anything due?". Joomla offers four ways to do that, and choosing the right one is the single most important decision you will make with this component.

5.1 The Lazy Scheduler (web traffic)

This is the default. When Lazy Scheduler is enabled in the Options, the Schedule Runner plugin injects a tiny background request into ordinary page loads. When a real visitor opens your site and a task is due, that visitor's page silently triggers the task through an AJAX call (onAjaxRunSchedulerLazy).

It is convenient and needs no server configuration, but it has a weakness: no traffic means no runs. A quiet site at 03:00 will not run its nightly task until the first visitor arrives in the morning. The lazy scheduler also has a minimum interval (default 300 seconds) so it does not fire on every single page view.

For reliable timing, let the operating system do the waking. Add one line to the server crontab that calls the Joomla CLI every few minutes:

*/5 * * * * /usr/bin/php /path/to/site/cli/joomla.php scheduler:run --all

Now the Scheduler is checked every five minutes regardless of visitors. This is the professional choice for any site where timing matters. See section 8 for the full command.

5.3 The Webcron URL

If you cannot add a system cron but your host (or an external service like a monitoring tool) can fetch a URL on a schedule, enable Web Cron in the Options. Joomla generates a secret key and builds a URL like this:

https://example.test/index.php?option=com_ajax&plugin=RunSchedulerWebcron
       &group=system&format=json&hash=YOUR_SECRET_KEY

Whatever fetches that URL triggers the due tasks (onAjaxRunSchedulerWebcron). Add &id=5 to run only task id 5. The hash is what keeps strangers from triggering your tasks, so treat it like a password and never share it in public.

5.4 The Test Run Button

The Test Run icon in the backend list fires a single task on demand (onAjaxRunSchedulerTest). It ignores the schedule and is meant for checking a task right after you create it. Use it freely while setting up; do not rely on it for production timing.

5.5 Which Should You Use?

MethodNeedsBest for
Lazy scheduler Nothing, just traffic Small sites, easy start
Server cron Crontab access Production, reliable timing
Webcron URL An external URL fetcher Shared hosting without cron
Test Run Backend access Setup and debugging only

On a site you care about, set up a server cron and switch the lazy scheduler off. That removes the small overhead from your visitors' page loads and gives you timing you can trust.

Back to top

6. Under the Hood

6.1 The Database Table

Almost everything lives in one table, #__scheduler_tasks. One row is one task. The columns that matter:

id                auto-increment primary key
asset_id          link to the ACL assets table
title             your task name
type              the routine id, e.g. session.gc
state             1 enabled, 0 disabled, -2 trashed
execution_rules   JSON: the rule type and its values
cron_rules        JSON: the parsed cron pattern
last_exit_code    result of the most recent run
last_execution    when it last ran
next_execution    when it is due next (empty for manual)
times_executed    successful run counter
times_failed      failure counter
locked            timestamp while the task is running (else empty)
priority          execution priority
params            JSON: routine-specific settings
note              free-text note
ordering          list order

Because the timing rules are JSON, the table stays simple and the same schema serves every kind of task.

6.2 The Locking Model

What stops the same task from running twice at once, for example when two visitors load a page at the same moment? A pseudo-lock. Before a task runs, Joomla writes the current time into its locked column. While locked holds a value, no other process will pick the task up. When the run finishes, Joomla clears the lock and writes the results.

If a task crashes mid-run and never clears its lock, the global timeout (default 300 seconds, set in the Options) saves you. Once the lock is older than the timeout, Joomla treats it as stale and lets the task run again. This is how a stuck task recovers on its own.

6.3 States and Exit Codes

A task's state is simple: 1 enabled, 0 disabled, -2 trashed. The result of a run is richer. Joomla defines a set of status constants in the Status class, and the most useful ones are:

CodeConstantMeaning
0 OK Ran successfully.
1 RUNNING Currently executing.
2 NO_LOCK Could not acquire the lock (already running).
3 NO_RUN The routine declined or failed to run.
4 NO_RELEASE Ran, but could not release the lock.
5 KNOCKOUT An unhandled error stopped the routine.
123 WILL_RESUME Paused; will continue on the next trigger.
124 TIMEOUT Exceeded the timeout.
125 NO_TASK No such task record.
127 NO_ROUTINE The routine (plugin) was not found.

The two you will see most are 0 (good) and 127 (you disabled or removed the plugin that provides the routine).

6.4 The Dispatch Flow

When a trigger fires, the flow is always the same:

Trigger (web / cron / webcron)
   ↓
Scheduler picks the next due, unlocked task
   ↓
Acquire lock (write "locked" timestamp)
   ↓
Dispatch onExecuteTask event with the routine id
   ↓
The matching task plugin runs its routine
   ↓
Record exit code, recalc next_execution, release lock

The component never contains the work itself. It is purely a dispatcher that hands control to a plugin through the onExecuteTask event.

6.5 The Logs Table and Logs View

The tasks table is only half the story. Joomla keeps a separate run history in a second table, #__scheduler_logs, and one row is written there every time a task runs. Its columns are practical:

id          auto-increment primary key
tasktype    the routine id that ran
taskname    the task title at run time
taskid      the id of the task in #__scheduler_tasks
jobid       a per-run job identifier
exitcode    the status code from section 6.3
duration    how long the run took, in seconds
lastdate    when this run happened
nextdate    the next run time after this one

You read this history in the backend through the Logs button in the Scheduled Tasks toolbar. The Logs view lists every run with its task name, exit code, and duration, and you can filter by exit code to see only the failures. A Clear Logs action empties the table when it grows too large; there is no automatic pruning, so on a busy site you clear it yourself or schedule a Database cleanup task to do it.

The duration column is the one developers watch. A task whose duration creeps up over time is usually processing more data than it used to, and it is the early warning that you should batch the work or raise the timeout before it starts hitting the TIMEOUT exit code.

6.6 Per-task Log File and Priority

Two smaller settings round out the picture. Each task has a logging fieldset where you can point the routine's output at a dedicated log_file, which keeps a noisy task's messages out of the main Joomla log. And the priority column lets a task signal its importance, which matters when several tasks fall due at the same moment and Joomla decides the order to run them in.

Back to top

7. Writing Your Own Task Plugin

7.1 The Shape of a Task Plugin

A task plugin is an ordinary Joomla plugin in the task group. It does three things: it advertises its routines, it runs them, and it optionally adds form fields for its parameters. Joomla gives you a trait, TaskPluginTrait, that handles most of the plumbing.

The heart of the plugin is a TASKS_MAP constant that maps each routine id to a method and a language prefix:

protected const TASKS_MAP = [
    'mycompany.cleanup' => [
        'langConstPrefix' => 'PLG_TASK_MYCLEANUP',
        'method'          => 'doCleanup',
        'form'            => 'cleanupForm',
    ],
];

7.2 Subscribing to the Events

The plugin subscribes to the Scheduler's events. onTaskOptionsList makes the routine appear in the "New Task" list; onExecuteTask runs it:

public static function getSubscribedEvents(): array
{
    return [
        'onTaskOptionsList'    => 'advertiseRoutines',
        'onExecuteTask'        => 'standardRoutineHandler',
        'onContentPrepareForm' => 'enhanceTaskItemForm',
    ];
}

The first two handlers come straight from TaskPluginTrait. You only write the routine method itself.

7.3 The Routine Method

Your method receives the execute event, does the work, and returns one of the status codes from section 6:

protected function doCleanup(ExecuteTaskEvent $event): int
{
    $params = $event->getArgument('params');

    // ... do the actual work here ...

    $this->logTask('Cleanup finished.');

    return Status::OK;   // 0 = success
}

Return Status::OK when all is well, or another constant to signal a problem. Joomla records the code, updates the counters, and recalculates the next run. That is the whole contract: subscribe, advertise, run, return a code.

7.4 The Key Classes

ClassRole
Scheduler Selects and runs due tasks; the dispatch engine.
Task Wraps one task record; acquires and releases the lock, logs, holds the snapshot.
ExecuteTaskEvent The event passed to your routine; carries the task id, routine id, and params.
Status The exit-code constants.
TaskPluginTrait The helper trait every core task plugin uses.

If you ever want a worked example, the nine core plugins under plugins/task/ are short, readable, and follow exactly this pattern. sessiongc is the simplest place to start.

7.5 Long-running Work: Batching with WILL_RESUME

What about a job too big for one run, such as resizing ten thousand images or emailing a newsletter to every subscriber? Run it in one go and it will hit a PHP memory limit or a time limit, especially under the lazy scheduler or a webcron, where the trigger lives inside a normal web request.

Joomla solves this with a dedicated exit code, Status::WILL_RESUME (123). The idea is simple: do one small batch per run, then tell Joomla you are not finished yet.

  • Process a manageable chunk (say 100 records), then return Status::WILL_RESUME.
  • Joomla logs the run as a success and leaves the task due, so the next trigger calls your routine again for the next batch.
  • When the final batch is done, return Status::OK and the task settles back onto its normal schedule.

The shape of a resumable routine looks like this:

protected function doImport(ExecuteTaskEvent $event): int
{
    $offset = (int) $this->getProgress();   // where the last batch stopped

    $batch = $this->fetchRecords($offset, 100);

    foreach ($batch as $record) {
        $this->processOne($record);
    }

    if (\count($batch) < 100) {
        $this->clearProgress();
        return Status::OK;            // last batch, we are done
    }

    $this->saveProgress($offset + 100);
    return Status::WILL_RESUME;       // more to do, run me again
}

One thing the framework does not do for you: it does not remember where you were. Each run is a fresh call, so your routine must persist its own progress (a cursor, an offset, or the ids already handled) between batches. Store it somewhere durable, such as the task parameters or your own table, and read it back at the start of the next run.

Keep each batch comfortably inside the global timeout from section 6.2, and keep the work idempotent so that a batch which runs twice (after a crash, for example) does no harm. None of the nine core task plugins need this pattern, but it is exactly how you would build a serious import, export, or bulk-mail task on top of the Scheduler.

Back to top

8. Command Line and Automation

8.1 The Console Commands

Joomla's CLI application exposes two scheduler commands. Run them from the site root:

# List every task with its state and next run
php cli/joomla.php scheduler:list

# Run all currently due tasks
php cli/joomla.php scheduler:run --all

# Run one specific task by id
php cli/joomla.php scheduler:run --id 5

The --id option (short form -i) takes priority: if you pass it, --all is ignored. scheduler:list prints a clean table of id, title, type, state, and next run, which is handy for a quick health check over SSH.

8.2 The Production Setup

The cleanest automation pairs a system cron with the CLI command. One crontab line drives the whole Scheduler:

*/5 * * * * /usr/bin/php /path/to/site/cli/joomla.php scheduler:run --all >/dev/null 2>&1

This runs every five minutes, checks what is due, and runs it. Each task still keeps its own schedule; the cron only controls how often Joomla looks. A five-minute cron with tasks scheduled hourly or daily is the sweet spot for most sites.

8.3 Why CLI Beats the Lazy Scheduler

Running tasks from the command line has real advantages over visitor-triggered runs:

  • Reliable timing: it fires even when nobody visits.
  • No visitor overhead: page loads stay fast because they no longer carry the trigger.
  • No PHP web timeout: long jobs are not cut off by the web server's request limit.
  • Clear logs: cron output and exit codes are easy to capture and monitor.

If you have shell access, this is the way. If you do not, the webcron URL from section 5 is the next best thing.

Back to top

9. Web Services and Headless

A common question: does the Scheduler have a REST API under /api, like articles or contacts do? In Joomla 6 the answer is no. The component does not register a Web Services route, so there is no v1/scheduler/tasks endpoint to create or list tasks over REST.

What it offers instead is the webcron endpoint, which is a triggering mechanism rather than a data API. It runs due tasks but does not let you read or edit task definitions:

curl "https://example.test/index.php?option=com_ajax&plugin=RunSchedulerWebcron&group=system&format=json&hash=<key>"

For everything else, treat the Scheduler as a server-side tool. If you need to manage tasks programmatically, use the PHP Scheduler and Task classes from section 7 inside your own code, or drive the CLI commands from a deployment script. For remote triggering on a timer, point an external monitoring service at the webcron URL.

Back to top

10. Performance and SEO Impact

The Scheduler has no frontend output, so it does not appear in search results and has no metadata of its own. Its effect on SEO is indirect but real: a well-tended site ranks and performs better than a neglected one.

  • Session GC and Rotate Logs keep the database and disk lean, which keeps response times low. Speed is a ranking signal.
  • Update Notification nudges you to patch promptly, and a hacked or defaced site is an SEO disaster.
  • Requests can warm a cache or ping a CDN after a deploy, so the first real visitor never meets a cold page.

One performance warning about the trigger model itself. The lazy scheduler adds a small background request to page loads. On a busy site this is measurable. Moving to a server cron removes that cost from every visitor at once, which is the most direct performance win this component offers.

Back to top

11. Common Mistakes and Pitfalls

11.1 "My nightly task never runs"

Symptom: a task scheduled for 03:00 only runs hours later, or not at all.

Fix: you are relying on the lazy scheduler on a low-traffic site. No visitor at 03:00 means no trigger. Set up a real server cron (section 8) so timing no longer depends on traffic.

11.2 "Last exit code is 127"

Symptom: the task fails immediately with exit code 127.

Fix: NO_ROUTINE means Joomla cannot find the plugin that provides the routine. The task plugin is probably disabled or uninstalled. Re-enable it under System → Plugins, filtered by the Task group.

11.3 "The same task ran twice"

Symptom: a job appears to execute twice close together.

Fix: usually two triggers fired before the lock was written, or a server cron and the lazy scheduler are both active. Pick one trigger method and disable the lazy scheduler when you use a server cron.

11.4 "A task is stuck and will not run again"

Symptom: a task shows as running forever and never fires again.

Fix: the run crashed and left the locked column set. Wait for the timeout (default 300 seconds) to expire and Joomla clears the stale lock by itself. If it never recovers, lower the timeout or unlock the task from the list toolbar.

11.5 "I shared my webcron URL and tasks fire randomly"

Symptom: tasks run at odd times after the webcron URL leaked.

Fix: the hash in the URL is a secret. Regenerate the key in the Options to invalidate the old URL, then keep the new one private.

11.6 "The site went offline on its own"

Symptom: the site is unexpectedly in offline mode.

Fix: check for a Site Status task. Its whole job is to toggle the site online or offline, and a misconfigured schedule will do exactly that. Disable or retime the task.

Back to top

12. Best Practices

If you remember only a few things from this article, remember these:

  • On any site that matters, run the Scheduler from a real server cron and turn the lazy scheduler off.
  • Always click Test Run after creating a task, and confirm the exit code is 0.
  • Keep the Update Notification task enabled. It is free early warning for security updates.
  • Treat the webcron hash like a password. Regenerate it if it ever leaks.
  • Watch the Last Exit Code column. A task that fails silently is worse than no task.
  • Give long jobs room: keep the global timeout sensible and prefer the CLI, which is not bound by web request limits.
Back to top

13. Quick Reference

COMPONENT      System → Manage → Scheduled Tasks
NEW TASK       Scheduled Tasks → New (pick a routine)
OPTIONS        Scheduled Tasks → Options (timeout, lazy, webcron)
TASK PLUGINS   System → Plugins (filter "Task")
RUNNER PLUGIN  System - Schedule Runner (plg_system_schedulerunner)
MAIN TABLE     #__scheduler_tasks
LOGS TABLE     #__scheduler_logs (run history; Clear Logs to empty)
LOGS VIEW      Scheduled Tasks → Logs (filter by exit code)
RULE TYPES     interval-minutes/-hours/-days/-months, cron-expression, manual
TRIGGERS       lazy scheduler, server cron, webcron URL, Test Run
CLI RUN        php cli/joomla.php scheduler:run --all
CLI ONE        php cli/joomla.php scheduler:run --id N
CLI LIST       php cli/joomla.php scheduler:list
WEBCRON URL    index.php?option=com_ajax&plugin=RunSchedulerWebcron
               &group=system&format=json&hash=KEY
EXIT 0         OK (success)
EXIT 124       TIMEOUT          EXIT 127  NO_ROUTINE (plugin missing)
STATE          1 enabled, 0 disabled, -2 trashed
LOCK           "locked" timestamp; cleared after timeout (default 300s)
SINCE          Joomla 4.1 (2022)
Back to top

14. Summary

The Scheduled Tasks component is Joomla's built-in answer to "who is going to remember to do this every day?". You define a task once, pick a timing rule, choose how it gets triggered, and Joomla takes the chore off your hands.

For a few minutes of setup you get:

  • Nine ready-made task routines covering logs, sessions, check-ins, image sizes, updates, and more.
  • Flexible scheduling, from simple intervals to full cron expressions.
  • Four trigger methods, so the Scheduler works with or without shell access.
  • A safe locking model that prevents double runs and recovers stuck tasks on its own.
  • A clean developer API for adding your own task routines in a single small plugin.

It is not magic. The lazy scheduler depends on traffic, a leaked webcron hash is a real risk, and a task that fails silently can lull you into a false sense of safety. But run from a proper server cron, with the exit codes watched and the Update Notification task switched on, the Scheduler quietly does the maintenance that keeps a Joomla site fast, tidy, and secure. If you are unsure whether your scheduled tasks are firing when they should, or you want a maintenance routine you can stop thinking about, it pays to have someone check the setup before a forgotten chore becomes a problem.

Back to top
Scheduled Tasks in Joomla
Peter Martin
Peter Martin

Joomla specialist and Linux admin for fast, secure and scalable websites.