Self-Hosted Helpdesk Platform

Standing up a real MSP-style ticketing workflow, end to end.

Live
osTicket Nginx PHP-FPM MariaDB ITSM Let's Encrypt

The Goal

Anyone can claim "technical support" and "ITSM" on a resume. I wanted a live, working example of the actual system a support team would use day to day — not just installed, but configured and run the way I ran ticketing workflows during my time managing IT for MSP clients: departments, help topics, SLA targets, and real tickets worked start to finish.


What I Built

Stack

osTicket running on PHP-FPM and MariaDB, served through Nginx on a dedicated subdomain (helpdesk.brianlimones.com) with a free SSL certificate via Let's Encrypt — the same hosting pattern I used for the rest of this site.

Support Workflow Configuration

Rather than run it on defaults, I set up the pieces a real helpdesk actually needs: multiple departments to route tickets by team, help topics so tickets get categorized on intake, and an SLA plan with a defined response-time target — the operational details that separate "I installed a ticketing tool" from "I understand how a support queue runs."

Public osTicket ticket submission form
The public-facing "Open a New Ticket" portal end users would actually submit through.

Working Real Tickets Through a Full Lifecycle

I submitted six realistic support scenarios through the public portal — the same way an end user would — then worked each one from the agent side: assigned it, diagnosed the issue, documented my reasoning in an internal note, replied to the "customer" with a plain-language resolution, and closed it out. A couple of examples:

  • VPN kept disconnecting — ran a packet capture during a drop, spotted fragmentation pointing to an MTU mismatch, lowered the tunnel MTU, and confirmed the fix held.
  • Account lockout after a password change — traced it to a second device retrying cached credentials and tripping the lockout threshold, not the password change itself.
osTicket agent queue showing tickets in different statuses
Agent-side queue — tickets moving through open, assigned, and resolved states.
A fully worked osTicket ticket showing internal diagnosis notes and customer-facing reply
A fully worked ticket — internal diagnosis note alongside the customer-facing resolution.

The Part That Wasn't in Any Tutorial

Getting osTicket installed was the easy part. Getting ticket deletion and other AJAX-driven actions to actually work under Nginx took real debugging: osTicket's routing depends on PATH_INFO, which Nginx and PHP-FPM don't always pass through reliably. What looked like a generic "blank popup" bug turned into a multi-step diagnosis — checking the browser's Network tab to confirm it was returning an HTTP 400, tracing that to a routing mismatch, and eventually finding the real cause: a duplicate try_files directive conflicting with Ubuntu's default fastcgi-php.conf snippet, which was silently overriding the PATH_INFO handling it already provided.

The actual fix ended up being simpler than the problem looked — stripping the config back down to let the default snippet do its job instead of fighting it. That's the kind of bug that doesn't show up in a checklist: reading error output carefully, narrowing down from "vague symptom" to "specific HTTP status" to "one conflicting config line," and knowing when to simplify rather than add more configuration on top.


Trade-offs I'm Aware Of

This runs web-based ticket intake only, not full email piping — a real deployment would typically let users email support@ and have that land as a ticket automatically. I scoped that out deliberately to focus the time on the workflow and troubleshooting depth rather than mail server setup, but it's the natural next step if I extend this project.