Skip to content
 
 

Latest commit

 

History

2,170 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FreeITSM

Free, open-source IT Service Management — self-hosted, AI-included, no per-seat fees. Ever.

MIT License PHP 7.4–8.4 MySQL 8.0+ Docker Ready GitHub stars

🌍 freeitsm.co.uk  ·  📖 Documentation Wiki  ·  💬 Discussions  ·  🐛 Issues


FreeITSM is a complete web-based ITSM platform: 24 integrated modules covering tickets, assets, knowledge, changes, problems, tasks, a CMDB, workflows, an LMS and more — plus a self-service portal for your end users. It runs on a plain PHP + MySQL stack (WAMP, XAMPP, LAMP, or Docker), so your data stays on your server.

Why teams pick it:

  • 🆓 Genuinely free — MIT licence, no per-seat/per-agent fees, no "Enterprise tier". Everything ships to everyone.
  • 🏠 Self-hosted — your tickets, your customers' conversations and your knowledge base live in your database, under your backups and your privacy policy.
  • 🤖 AI included, not upsold — reply cleanup, knowledge Q&A, form generation, course authoring, RCA drafting and more, all bring-your-own-key (Anthropic, OpenAI, or OpenRouter).
  • 📥 Every channel becomes a ticket — email (Microsoft 365, Gmail, IMAP), WhatsApp, Telegram, Slack, an embeddable web chat widget, and a portal that even staff without a company email address can use.
  • 🔔 A notification bell you can actually leave on — replies, assignments, notes and SLA warnings on your tickets, on every screen. It never tells you about your own actions, groups repeat changes to one ticket into a single entry, and stays silent for bulk updates, so it does not become the thing everyone ignores. It can also chime — each person picks their own sound, or none at all, under Preferences, and it only ever sounds for something that arrived while you were sitting there. Entries can be cleared as well as marked read: an individual one from the row it sits on, or the lot in one go — and Clear all spares anything you have not read yet unless you tick the box that says otherwise.

Screenshots

Watchtower
Watchtower
Tickets
Tickets
Assets
Assets
Knowledge
Knowledge
Changes
Changes
Calendar
Calendar

View all 57 screenshots →

🚀 Quick Start

The fastest route is Docker — no PHP, MySQL or web server setup required:

git clone https://github.com/edmozley/freeitsm.git
cd freeitsm
docker compose up -d

Then open http://localhost:8080/setup/ to verify the installation and create your admin account. The first sign-in uses admin / freeitsm and FreeITSM will make you choose a new password before it lets you do anything else.

  • Manual install (WAMP / XAMPP / LAMP): follow the Installation guide — prerequisites, database setup, encryption key, and configuration files.
  • Upgraded, or moved servers? System → Debug Tools → D017 checks your config.php against what this version expects and gives you the exact line to add for anything missing. It shows setting names only, never values.
  • Running in Docker? FreeITSM checks whether the folders holding your uploaded files are on Docker volumes, and warns you on the System screen if an update would discard them. System → Debug Tools → D013 shows the detail and what to do about it. Native installs are unaffected and see nothing.
  • HTTPS in Docker: System → Docker makes a certificate for the name your people type (such as freeitsm.internal) and walks you through the rest: the DNS record, installing its authority certificate on your PCs, and restarting the container. HTTPS is then served on port 8443. The authority can only vouch for that one name, so trusting it on your PCs does not let it impersonate any other site.
  • First login: admin / freeitsm — change it immediately via the account menu.
  • Demo data: System → Demo Data populates every module with realistic sample data, so you can evaluate with the system feeling alive. Every row it creates is marked as demo data, so re-importing a module replaces only its own sample records and leaves anything you have created alone.

Modules

Module What it does
Watchtower Unified attention dashboard — one glance shows what needs you across every module. Counts every status you have, under the name and colour you gave it, so renaming or adding one keeps working. Settings turn off cards you don't watch and narrow what each count includes
Tickets Outlook-style inbox with email, WhatsApp, Telegram, Slack and web chat channels, SLAs, CSAT, canned responses, multi-select bulk actions, snooze, collision detection, AI reply cleanup, and a staff rota you fill by copying — one shift into a block of cells, a whole day or one person's week onto another, or a whole week at a time — and clear the same way
Self-Service Portal End-user portal — request catalogue, knowledge, replies, screen recording; works even with no email address. People you create yourself set their own first password from Forgot your password?, so you never handle one. Can be set as the page people land on (System → Branding), with a per-analyst override
Tasks Kanban board, list, calendar and timeline views for internal work, with scheduled start and end times and a record of time spent that totals across subtasks. Tasks can repeat — daily, weekly, monthly or yearly, on chosen weekdays, on a day of the month including the last, or on a named weekday such as the third Monday — either when you complete the last one or on a fixed schedule, with a preview of every date the settings would produce before you commit to them. Optionally, tasks can carry checklists from the Checklists module, with Critical steps that must be done before the task completes
Assets Asset register with custody tracking, locations, warranties, QR labels and an in-app camera scanner for stocktakes, a per-person view of who holds what with a printable handover document, vCenter and Intune sync, plus saved table views — save the columns, sort and filters under a name, share them with a team or everyone, and set one as the view a table opens with (also on Tasks, Calendar and Change Management)
Checklists & SOPs Standard operating procedures as reusable templates - write onboarding, offboarding or a firewall change once, attach it to any ticket, and tick the steps off. Steps can be marked mandatory, ask the analyst for a value (an asset tag, a serial), and suggest which role does them; keyword matching offers the right procedure on a ticket before anybody goes looking. Closing a ticket with mandatory steps outstanding either warns and records an internal note or is refused outright - your choice, enforced on bulk actions, the REST API and workflow automation too. Contributed by Santhosh Srinivasan
Knowledge Rich-text articles organised in folders, with AI chat, vector search, review workflow, per-audience visibility and a distraction-free full-screen editor
Change Management ITIL changes with CAB voting, risk matrix and post-implementation review
Problem Management Root causes behind recurring incidents, known errors, AI-assisted RCA
Workflows Cross-module automation — visual canvas, 138+ triggers, outbound webhooks, AI co-author
CMDB Typed configuration items with relationships, impact analysis and AI summaries
Network Mapper Architecture diagrams where every node is bound to a real CMDB object
Calendar Team calendar with categories, and an iCal feed for your phone
Morning Checks Daily infrastructure health checks with optional groups routed to a team or analyst, raise a ticket or task from any check, trend charts and PDF export
Reporting System logs, audit trails, and an Intune device dashboard with drill-down
Software Software inventory from an agent script, plus licence management
Forms Dynamic form builder with AI assist, section headings, notes, warnings and images, tables a person adds rows to, conditional questions, versioning and submissions reporting. Half-finished forms can be saved as a draft and picked back up later, on the analyst side and in the portal. Fields can sit side by side on a line and stack to one column on a phone. Say what happens when a form is used — raise a ticket, send an email, call a webhook — separately for when it is submitted, approved or rejected. Keep a submission as a PDF carrying your own logo, the answers and who approved it — one at a time, or tick several and take them as separate files or a single bundle. Group several forms' submissions into a collection such as "Staff Survey 2026", and close it when the exercise is over — what closing does is yours to choose, and a submission remembers the collection it was filed under even if the form is later paired elsewhere
Contracts Supplier and contract lifecycle, plus an AI-powered RFP Builder, contracts with customers as well as suppliers (a company, a person, or both — seen only by analysts who can see that company, unless you choose otherwise), and equipment covered by a contract — link phones, SIMs, routers or hardware to the agreement that covers them, visible from both the contract and the equipment, with an equipment report you can print, download as CSV or email
Domains A register of every domain name you hold, per company: registration and expiry dates filled in from the registry (RDAP, with WHOIS for the rest), a security grade from A+ to F with plain-English advice covering locks, DNSSEC, SPF, DKIM, DMARC and certificates, change detection for hijacks, optional Certificate Transparency and look-alike domain watches, registrar accounts and encrypted auth codes, the customer each domain is looked after for (a person, or a supplier or one of its contacts) and its technical contact (one of your analysts, or a supplier contact), renewal alerts sent as one digest per person, or raised as a task or ticket, and connections to the CMDB items, tickets, runbooks and contract that go with each domain - with Service Status told (or raising the incident itself) when a domain or its certificate lapses, certificate renewals on the Calendar and Watchtower, and a right-click menu in the register
People One page per person and per company, from every module at once: the tickets someone raised, the equipment they hold, contracts and domains where they are the customer, their courses and the forms they submitted, plus their manager and the people who report to them. Suppliers and their contacts have pages too: a supplier's contacts, contracts, the equipment bought from it and every domain it is registrar, customer or technical contact for - shown here and still kept in Contracts, so a supplier's contact never becomes somebody who can sign in. Each section appears only to analysts who can open the module it comes from, and only for companies they can see. Find anyone from ⌘K
Service Status Service health dashboard driven by incident tracking, plus internal notes and external updates on an incident — publish a timeline to the self-service portal while keeping troubleshooting private
War Room Chat on your own server for when Teams, Slack or the internet are down — channels, direct messages, search, attachments, and an AI situation report that drafts the update to the business
LMS Author courses in-app (with AI) or upload SCORM; assign to learning groups, take them, and track progress by course, group, analyst or status; competency tests for job candidates
Process Mapper Flowchart builder with swimlanes, custom step types and Mermaid export
System Administration — analysts, teams, roles, encryption, database verify, demo data, and your finance department's cost centres

A System Wiki module also auto-documents the codebase from within the app, and a browser extension puts the Watchtower badge count in your Chrome/Edge toolbar.

Highlights

  • REST API — 200+ key-authenticated endpoints with granular per-key permissions, a live OpenAPI spec, and interactive in-app docs with code samples in seven languages.
  • Single Sign-On & LDAP / Active Directory — OIDC providers side by side (Keycloak, Entra, Okta, …), or bind straight to your on-prem directory with group-gated just-in-time provisioning. Local login always remains as break-glass.
  • CardDAV contact sync — bring your customers in from the address book you already keep them in (Baikal, Nextcloud, ownCloud, or anything else built on sabre/dav), scoped to whichever groups or tags you tick rather than the whole book. Imports are read-only unless you say otherwise; switch write changes back on and a correction an analyst makes during the call — job title, department, office, phone, mobile — updates the contact card too, so nobody has to remember to fix it twice. Write-back edits only the detail that changed and leaves the rest of the card untouched, and refuses rather than overwrites if somebody has changed the same detail in the address book since. Someone who is not in the address book yet can be added to it from their record with one button (a separate switch, also off by default), which checks for an existing card with their email first and makes sure the next import will pick them up. Customers can correct their own details the same way from the self-service portal if you allow it (off by default, under System → Portal profile); their change is saved only once the address book has accepted it.
  • Security — AES-256-GCM encryption at rest for secrets, TOTP MFA whose attempt limit is held on the account rather than in the browser session (so it cannot be reset by signing in again), brute-force protection, role-based permissions down to individual settings tabs, and audit trails throughout. Independently audited in August 2026; both rounds and the findings still open are documented in full. Attachments arriving by email, portal or chat are checked against an allow-list and stored under a name FreeITSM chooses, so an uploaded file can never be executed; System → Security sets which file types you accept — leave it empty for everything FreeITSM considers safe, or name just the types you want, noting that you can only narrow the list and never widen it to something executable — and whether a type you don't accept is kept as a download-only copy or not kept at all. Either way the ticket records what happened.
  • Attach documents to anything — contracts, assets, knowledge articles, problems, changes and individual notes on a ticket can all carry documents. Drag a file in, or paste a link to one held in SharePoint, Google Drive or whatever document system you already use — a link is a first-class document, so there is no pressure to move anything. The same document can be attached to several records, so one warranty covering eleven laptops is stored once rather than eleven times, and an ⓘ shows everywhere it lives. Who can see a document is decided entirely by what it is attached to: if you can see the contract you can read its documents, and if you cannot, it does not appear in the list, in search, in ⌘K, or at its own web address — including as it changes, because the question is asked when you ask it rather than written down at upload. The text inside PDFs and Office files is read in the background so ⌘K finds the contract that mentions a clause, not just the one named after it (Apache Tika needed for PDFs and scans).
  • Import assets from a spreadsheet — point it at a CSV and it suggests where each column goes, shows the first few values beside each one, and fills both the built-in details and your own custom fields. Nothing is written until you have previewed it: the Import button stays off until a preview has run, and the preview does every check while writing nothing. You declare which columns identify a row, so importing the same file again updates what is there instead of creating everything twice — and a row matching more than one existing asset is set aside rather than guessed at. Rows that cannot be imported are kept, showing what your file actually said and what was wrong with it, so you can fix the spreadsheet rather than work out what went missing.
  • Know whether an asset is still reporting — every asset now shows First seen and Last seen, in your own timezone and with how long ago that was, and a machine that has gone quiet for more than a week is flagged in amber. Last seen is a sortable column in the asset table, so one click brings the machines that stopped reporting to the top, and the Watchtower dashboard's "not seen in 7+ days" count is a link straight to that list — it used to tell you how many and leave you to find them. Equipment that no agent will ever report says Never reported rather than showing a blank, so "stopped" and "never started" never look the same.
  • Give a laptop to an analyst, not just to a user — equipment held by the desk itself, a spare machine, the loan phone, a test handset, had nowhere to live: an asset could only ever be assigned to one of the people you support. That is not a small gap, because analysts are not users — on most installs the people running the service desk have no user record at all, so most of your own team could not be recorded as holding anything. The assign dialog now has a User / Analyst switch that changes which directory it searches, and the holder shown on the asset carries a small Analyst tag so you can always tell which kind of person has it. Everything else is unchanged: the same expected return date, the same handover history, the same audit trail.
  • Leases, not just warranties — an asset now carries a Lease ends date beside its warranty date, and a date that has passed or is within 30 days is flagged on the asset itself, beside the date rather than as a banner, so you can see which one is the problem. Assets → Settings → Warranty gains a matching block for leases, with its own warning window and its own choice of where they appear: a figure on the Watchtower dashboard, entries in the Calendar under their own Lease category, both, or nowhere at all. The default window is 60 days rather than the 30 used for warranties, because returning or renewing leased equipment takes arranging. Turning either kind off removes only its own calendar entries and never touches the other, or anything you put in the calendar yourself.
  • Serial numbers for the drives inside a machine — the inventory agent has always collected the model, serial number, capacity, media type and interface of every physical disk, and FreeITSM now records and shows them under Storage, beneath the volumes. That is the number a warranty claim needs when a drive fails, and the one an auditor asks for when a machine is disposed of. Nothing to install: existing agent deployments start reporting drives after the next database verification. Windows also reports mounted virtual disks as though they were hardware, so any drive can be hidden — and the dialog offers to hide the rest like it across the whole estate in one go, which turns six hundred pointless rows into one decision.
  • Assets that know which company they belong to — on a multi-company install, an asset's Key info now shows its Company, and changing it moves the asset. Anything that exists only in the old company is cleared and the message says what: its location, and a type or status the new company does not have. The move is refused, with the reason, when the new company already has an asset with the same name or asset tag, or when the asset is held by someone from a different company. Adding an asset asks which company it is for whenever you can reach more than one, and in the All companies view it has no default, so a new asset can no longer land in whichever company you happened to pick last. The type, status and location lists follow the company you choose. Locations can be shared across companies: tick Shared with every company on a location such as a data centre that several clients' kit sits in, and every company can pick it alongside its own. Only someone with access to every company can share, change or delete a shared location, and it cannot be unshared while other companies' assets are still there.
  • Custom asset fields — assets arrive on their own from the inventory script, Intune and vCenter, and anything that cannot report for itself is added by hand from the asset list. The built-in asset details describe a computer, because that is what the inventory agent reports. Custom fields are how you record everything else: printers, monitors, headsets, televisions, anything. Define a field once — text, a number with a unit, a date, yes/no, a list to pick from, or a link to a person or another asset — then choose which asset types record it. A field is defined once and reused, so "serial number" on a headset is the same field as on a television and one search finds both. Fields can also be added to individual assets: if three of your ten meeting-room televisions are being trialled as smart TVs, those three carry an IP address and the other seven do not — not blank, absent. Adding a field takes effect immediately with no database change and nothing already recorded is touched, and a field is retired rather than deleted, so everything ever recorded against it survives and comes straight back if you reinstate it. On a multi-company install a company can add fields of its own alongside the shared ones.
  • Multi-tenancy — host multiple client companies in one install (built for MSPs), each walled off from the others. Invisible until you add a second company.
  • Cost centres, kept in step with your finance system — System → Cost Centres holds the codes your finance department charges things to, for each company, with a parent for each to build your hierarchy. Codes are text, so 0010 stays 0010 and N1414 works too, and capitals are ignored when matching. Bring the whole list in from an Excel workbook or CSV (semicolon-separated and German headings included): Preview shows exactly what will change, and one bad row means nothing is imported. Export as .xlsx, whose codes Excel cannot strip the zeros from. Or let your accounting system call POST /api/v1/cost-centres/sync every night: matched on code, only the fields sent are changed, and anything dropped from the list can be made inactive. Inactive means not offered for anything new, never deleted. (#160)
  • Photo Album, just for fun — System → Photo Album turns your webcam picture into ASCII art, live as you move: Braille (eight dots per character, for a startlingly good likeness), Classic characters or Blocks, on a green, amber, paper or full-colour screen, with detail, contrast and sharpen sliders. No AI — plain arithmetic in your browser — and the photo never leaves it: only the art is kept, in an album that is yours alone. Copy it as text or download it as .txt or .png.
  • Webhooks — push any event to Slack, Teams, Discord or any endpoint, with HMAC signing, retries and a delivery dashboard.
  • Service status with history — every tracked service carries a day-by-day availability strip, an uptime percentage over 7/30/90/365 days, and the incidents behind it. Worked out from your existing incidents, so it covers outages that already happened. Which impact levels count as downtime is set per level; planned maintenance is excluded by default.
  • Import people from Active Directory — bring your whole directory in, so people exist before they ever sign in. That matters because the staff who hold equipment are largely the staff who never log in. Name, job title, department, office, phone, employee number and the reporting line all come across. Preview runs the same job and changes nothing, nobody is ever deleted, and a safety brake stops an import that suddenly finds far fewer people than last time — because a mistyped starting point looks exactly like everybody leaving at once. Browse the directory and tick what you want rather than typing a distinguished name — the tree shows a head count per branch, so you can see that ticking Staff brings in 32 people before running anything, and ticking a branch takes anything added to it later too, with individual parts untickable to leave contractors or service accounts out. A Field mapping tab pairs each FreeITSM field with its directory attribute and will read one real person to show you the value each row would actually import, alongside every attribute that person carries — so a mistyped attribute name is caught before an import, rather than as an empty column somebody notices weeks later.
  • People, not just logins — a person record carries job title, department, office, phone, employee number and who they report to, and you can see and edit all of it from either Assets → Users or Tickets → Users, so which details you get does not depend on which module you came in through. Both are a directory you can add to, edit and mark leavers in. Where somebody was imported from a directory those details are read-only, and the screen says why rather than accepting a change the next sync would undo. Somebody who leaves is never deleted: they stay on every ticket, asset and handover document, and if they are still holding equipment the screen tells you. People can keep their own job title, office, phone and mobile up to date under My Account in the self-service portal, and System → Portal profile decides which of those four they may change; department, employee number and manager are never theirs to set. Groundwork for importing people from a directory, and useful on its own without one.
  • Training reminders, off until you switch them on — email the people whose training is nearly due, or already late, with the days set under LMS → Settings → Reminders: a week before and again the day before, say, plus a chase every week once the deadline has passed. Somebody who has finished the course is never chased, and nobody is ever reminded twice about the same deadline — though moving a deadline legitimately reminds again. It is off by default and says why: the first cron run after an upgrade is exactly when a helpful default would email several hundred people about training assigned months ago. Before you turn it on, the screen tells you how many reminders would go out right now, and how many people have no email address to reach — worked out by the same code that does the sending, so the number you are shown is the number that will go. Reminders can run from a daily scheduled task, or, if you have not set one up, whenever somebody opens the LMS — which makes the feature work out of the box, and the screen is honest that a fallback is not a schedule.
  • Competency tests for the people you are hiring — under LMS → Tests, describe the role you are recruiting for, add the skills it needs one at a time with a difficulty (beginner, intermediate, advanced), a number of questions and a format: multiple choice (one right answer of four) or graded in the style of the old ITIL intermediate exams, where four defensible answers are worth 5, 3, 1 and 0 marks. The AI drafts the questions into a question bank; nothing reaches a candidate until a person has approved it, and a new test takes approved questions from the bank before it asks the AI for more. Search the bank to build a test by hand, edit a question, or hide one for good. Each candidate gets a private, single-use link — no account — with a server-kept timer, answers that save as they go and answer order shuffled per person; their paper is frozen when it is sent, so every candidate sits an identical test and later edits never change a result. Results show a score per skill, every answer against the marks, and your notes. Candidates are personal data, so the whole feature has its own permission and finished results are deleted after 180 days unless you choose otherwise.
  • Push training to the people who use your service desk, not just the people who run it — the LMS could only ever assign a course to a group of analysts. A course can now go to a group of people (analysts and portal users together), or to everyone on the self-service portal in one go — mandatory security awareness for the whole company, from the same screen you already assign staff training from. Portal users get a Training tab of their own, showing what they have been asked to do, how far through they are and when it is due, and they take the course in the portal itself — the same player, the same knowledge checks, the same marking. Their results appear beside everyone else's on the Progress tab, so "who still has not done the phishing course" is one question with one answer rather than two systems to reconcile. The Training tab only appears for somebody who actually has a course, so an install that never uses it never grows a tab that leads nowhere.
  • Make the self-service portal look like yours, not like the app — a new System → Self-service portal screen. Give the portal its own logo, for a desk that trades under another name or a main logo drawn for a dark app header that looks wrong on a light portal page. Set the header and accent colours independently of the analyst side. Add a subtle background pattern — dots, a grid, diagonals or topography — if a flat page feels too plain; they are deliberately faint, and doing nothing leaves the portal exactly as it was. A live preview sits beside the settings so you can see the result without saving first.
  • People can close their own ticket — for the commonest wasted ticket on any desk: it started working, I sorted it myself, I raised this twice. Without it the requester either replies asking somebody to close it, which costs an analyst a round trip to do nothing, or says nothing at all and the ticket sits open until it is chased. They can add a reason, which is recorded on the ticket so the desk knows what actually happened. The history says plainly that the requester closed it, rather than attributing it to whichever analyst happened to be assigned — the audit trail can now record that nobody on the desk did something.
  • People can see the equipment assigned to them — a My equipment page in the portal, so somebody can read a serial number off the screen instead of raising a ticket to ask what it is. Off by default and switched on from the same Self-service portal screen, because what equipment somebody holds is not a thing every organisation wants to publish.
  • The portal remembers how each person likes to read it — the knowledge base comes in Cards, List, Tree or Table, chosen from the toolbar and remembered for that person, with the same four names the analyst side uses so nobody has to learn two vocabularies for one idea. Training runs full width, and a completed course now says when it was completed rather than only that it was. And light or dark now sticks: choosing dark in the portal used to be forgotten by the next page for anybody who was also signed in as an analyst, because the analyst theme quietly won — which meant the people most likely to notice were the ones least likely to be believed about it.
  • Groups of people, with an end date — put analysts and portal users together in a named group under Tickets → Users → Groups, and give the group access to something rather than naming six people. Each membership can carry a last day: three engineers on site for a fortnight go in with an end date, and they drop out of the group by themselves when it passes — the access is taken away by the clock rather than by somebody remembering. An expired membership is still listed, marked as expired, so you can see who had access and until when; and the group counts current members and lapsed ones separately, because one number would hide the difference. Knowledge folders already grant access to a group, which until now was a kind of permission nothing in FreeITSM could create. Anyone with Tickets can see the groups; only an administrator can change one, since adding somebody to a group that opens a folder is itself a grant.
  • Email send log — every email FreeITSM tries to send is recorded, whether it worked or not, in an Outbound tab beside the existing inbound mailbox activity. All eight sending routes are covered — analyst replies, ticket templates, workflow actions, SLA alerts, portal and system mail, password resets, and shared knowledge articles and change records — with the recipient, which part of FreeITSM sent it, and the provider's own words when it failed. A failed automated email used to be visible only in a log file on the server, which meant the first sign of one was usually somebody saying they never got a reply.
  • Email templates that can link back to the ticket — automatic emails carry a [ticket_url] merge code that resolves to the requester's own view of their ticket, so a confirmation email can say track it here instead of leaving somebody to go and find it. The body is edited in a small formatting toolbar rather than by hand-writing HTML, with a Preview tab that fills in every merge code with sample values so you see the email as it will arrive. Because these emails are usually sent by the overnight mail collector — when there is no browser request to work an address out from — the templates screen carries the public web address the links are built on, and says so plainly if a template uses [ticket_url] while nothing is set.
  • Automatic replies can be limited to particular senders — scope any email template to an address or a whole domain, so external senders stop receiving an internal-sounding auto-reply. Which template applies is decided by how specific it is, never by the order they are listed in: a template naming someone@a.com beats one naming a.com, and both beat one that goes to everyone — so there is no ordering to get wrong, and dragging rows cannot change what gets sent. A new template applies to everyone until you narrow it, which means an installation always has a catch-all unless one is deliberately removed. Type an address into Check what a sender would get and FreeITSM names the template that would go back and why, using the same code that will choose it for real. And if every template for an event has been restricted, the screen says so — while any email that is not sent because nobody matched is recorded as Not sent, with the reason, in the mailbox's send log, so the question "why did this customer never hear back?" has an answer long after everybody has forgotten the setup screen.
  • Tell the analyst, not just the customer, when a ticket is assigned — the assignment email has always gone to the person who raised the ticket ("assigned to Sam, we will update you soon"), which is what they need to hear. There is now a second, separate event, Assigned to an analyst, that emails the analyst the work has just landed with — with its own wording and a link straight into the inbox rather than the customer's portal view. Neither affects the other: configure one, both or neither. It is deliberately not sent when you assign a ticket to yourself, because an email describing what you did three seconds ago is how a notification gets switched off. The templates screen now says who each template is sent to — requester or assigned analyst — beside which senders it covers, so the two questions the Sends to column answers are no longer one. ⚠️ Note that [analyst_name] is the ticket's owner where one is set, which on most desks is a different person from the assignee; templates addressed to an analyst want [assigned_analyst_name], and the editor now says so.
  • Scheduled tickets in your real Outlook calendar — connect FreeITSM to Microsoft 365 once, under System → Calendar sync, and each analyst can have their scheduled tickets written into their own mailbox as genuine appointments: they mark you as busy, reach your phone, and update the instant you change something rather than whenever a calendar app next refreshes. Reassign a ticket and it moves out of one person's calendar and into the other's; close, bin or unschedule it and it goes. Setup borrows the Azure app registration you already configured for mail, so there is no per-analyst sign-in, no consent screen and no tokens to maintain — and a Test button that answers "do the credentials work" and "can this mailbox be reached" separately, so a problem points at its own fix. Each analyst turns it on for themselves and nobody can turn it on for them; switching on back-fills what is already scheduled, and switching off takes back everything FreeITSM put there. A calendar problem can never stop you scheduling a ticket — if Microsoft is unreachable the save still succeeds and the failure is reported on your own settings.
  • The same, on your own calendar server — not on Microsoft 365? Choose A CalDAV server under System → Calendar sync and enter its address, and scheduled tickets and tasks go into calendars on Nextcloud, Baïkal, Radicale, SOGo, iCloud, Fastmail or any other CalDAV server, as real appointments that work both ways: move one in your calendar app and the ticket follows on the next scheduled check. A CalDAV server has no way for one account to write into everybody's calendar, so each analyst signs in with their own account under Preferences, presses Find, and picks the calendar their work should go into (an app password is the better choice where the server offers one). The list only offers calendars that account can already write to, on the server you entered, so nobody can point FreeITSM anywhere else. A reminder or note you add to one of these appointments stays put when the ticket changes, because FreeITSM only rewrites the time, the title, the description and the link. Microsoft 365 and CalDAV can run side by side, with as many connections of each as you need, and each analyst picks which one their work goes to; changing or deleting a connection takes back only that connection's appointments, and tells you how many before it does.
  • Your scheduled work, in the calendar you actually use — schedule a ticket with a start time and a duration (or mark it as an all-day job), see it on the tickets calendar in Mine or Everyone with a colour per analyst, and take it with you: Preferences → My work calendar gives you a private subscription link that works with Google Calendar, Apple Calendar, Outlook, Thunderbird or anything else that speaks iCalendar. No Microsoft account required and nothing to configure — scan the QR code with your phone and it is there. The link is a secret URL rather than a login, so it is yours alone, can be reset at any moment to revoke every copy, and can be limited to ticket numbers without subjects if you would rather your day's shape travelled but not its detail; an administrator can also switch subscription links off across the whole system. FreeITSM warns you plainly if the system is not using HTTPS, because the link is unprotected in transit until it is.
  • Analysts keep their own email signatures — written under Preferences, with formatting and merge codes for your own details, and more than one is allowed: a formal signature for customers, a short one for colleagues, one per language if you answer in several. Exactly one is the Default, which is what gets used automatically — so anyone who only wants a single signature never sees a choice, and picking a different one stays deliberate rather than a decision on every reply. Signatures are per analyst and nothing else: there is no shared or install-wide signature to administer, and nobody can see or change anybody else's. A My details section adds job title, department, phone and mobile to your account so a signature has something to merge, and a code you have no value for is removed rather than left showing at the bottom of your emails. Open a reply and your default signature is already in the editor with a blank line above it — placed there visibly rather than added when you press Send, so you can change or remove it for one email and what you see is what the customer gets. A Signature button beside Templates swaps it for another or takes it out.
  • Mailboxes say where their tickets came from, and tell you when something is off — each mailbox carries a Default ticket origin, so tickets it opens are recorded as having come from Email, or from Monitoring, or from whatever you call it. It is set per mailbox rather than once for all email, because a helpdesk address and an alerting address both arrive as email and are not the same source. Each mailbox also carries an ! next to its name that lists everything quietly wrong with it — no origin set, reading the wrong inbox, never checked for mail, no folder chosen for imported mail, an IMAP mailbox that cannot send replies — because a mailbox can be connected, green and collecting mail and still not be doing what you assume. Any warning can be dismissed where it is something you meant, which clears the mark but keeps the item listed with a Restore beside it; errors cannot be dismissed, since reading the wrong inbox is a fault rather than a preference.
  • Cloud platforms you can actually record — the inventory agent finds what is installed on your machines, which is no help at all for Xero, Canva, Figma or anything else that lives in a browser. Software → Add application lets you enter one by hand, with a publisher, the web address you administer it at, and notes. That is worth more than it sounds: a licence in FreeITSM has to belong to an application, so until now there was nowhere to record what a cloud subscription costs, how many seats it has or when it renews. Now there is. Manual entries are marked as added by hand and are the only ones you can edit — an agent-discovered application is a report of what is on somebody's machine, and editing it would only be overwritten at the next inventory run. If the agent later finds one of your manual entries genuinely installed somewhere, it attaches the machines without touching a word you wrote. Seats and installs are shown as separate columns, because a cloud platform is installed nowhere and a nought in that column should not be read as "nobody uses this".
  • Software renewals now show up where you are looking — a contract about to expire has always appeared on the Watchtower dashboard, and an asset warranty has always been able to write itself into the calendar. Software licences did neither, so a large renewal was visible only to somebody who happened to open the Licences page that week. There is now a Software card on Watchtower counting renewals due in 30 and 90 days and notice periods running out — the same three windows the Contracts card uses, so you can read them against each other — and Software → Settings → Renewals decides whether renewals appear on that dashboard, in the calendar, in both, or nowhere. The calendar entries come in pairs: the renewal date itself, and the notice deadline worked out from the notice period, which is the one that actually costs you if you miss it.
  • One board across every company — if you support several schools, charities or clients from one service desk, the company switcher in the header now has an All companies option. Every ticket you are allowed to see appears in one list, each row wearing the company it belongs to, and anything that arrived by email or the portal without being routed yet is marked Unrouted so it stands out rather than hiding under Default. It grants nothing new: "all" means every company you could already reach one at a time, so an analyst who supports two of your three entities sees exactly those two. Each entity stays separate where it matters. Open a ticket and its type, origin, category and resolution list are the ones belonging to that company, not the one you happened to be in — so a status or category one school has and another doesn't can never be applied to the wrong ticket. Replies still go out from the mailbox the ticket arrived at. And raising a ticket from the combined view asks which company it is for, because that decides its ticket number, its mailbox and the SLA it will be measured against. Emptying the trash is the one thing that deliberately does not follow the combined view — it always applies to a single company, because "delete everything in the bin" across three entities at once is not what anyone means by it.
  • Categories that make your reports add up — a ticket type says what kind of thing this is; a category says what it is about. Build the list under Tickets → Settings → Categories: "Hardware", "Access requests", "Printing issues", with sub-categories underneath where you want them, up to three levels and no level compulsory. A category can be tied to one ticket type, so "User onboarding" is only offered on a service request, or left free to appear on all of them. A ticket carries one category, deliberately — every count in FreeITSM is one ticket, one slice, so a pie chart of your categories still adds up to the number of tickets you actually had. There are two more fields alongside it, each switched on separately. Category at close asks the same question again when the ticket is finished, which is how you find out that twelve of your thirty-seven "printer problems" were really the network — the person raising the ticket is guessing, the analyst who fixed it knows. And a resolution code records how it ended rather than what it was about: "Fixed remotely", "Training given", "No fault found". Ten sensible ones are there from the start and you can change them all. All three start switched off, so nothing changes on your ticket screen until you have built your list and turned them on, and each can be set differently for each company on a multi-company install. Requesters can be offered a short, plain-English version of the list in the portal while analysts see the whole tree, and any of the three can be charted on your ticket dashboard, rolled up to the top level. Retire a category rather than deleting it and the tickets that already carry it keep their label for ever.
  • Fields that must be filled in before a ticket closes — a resolution code nobody picked makes your monthly report wrong without anyone noticing. Tickets → Settings → Mandatory fields lists the ticket's fields — priority, category, category at close, resolution code, owner, requester and the rest — each with a tick for must be filled in before closing. Then choose what happens when somebody closes a ticket with one empty: warn and let them close anyway, warn and email the people you name (a service delivery manager, say) with the ticket and the fields that were empty, or refuse the close until they are filled in. A separate switch writes an internal note on the ticket saying which fields were empty and who closed it. The rule applies on the ticket screen, in bulk actions, through the REST API and in workflows, and a value filled in by the same change that closes the ticket counts. A field that is switched off for a company is never required, and merging tickets never triggers it. Nothing is ticked until you choose.
  • Ticket numbers you choose the shape of — the reference on a ticket is the thing people read out on the phone and write on a form, so Tickets → Settings → Ticket numbering lets you decide what it looks like: keep the random CKQ-418-73926 FreeITSM has always used, or count up as INC-2026-00042, with the year, month, a short code for the ticket type or the company, and as many digits as you like. On a multi-company install each company carries its own ticket code (set in System → Companies, or worked out from the name), and the numbering screen refuses per-company counting until every company has one that is unmistakably its own. The digits are a minimum, never a limit — an install that outgrows six of them gets a seventh rather than an error. You can count in one sequence, or give each ticket type or each company its own, and start again every year or month. A live preview shows the next few numbers as you type, and a format that cannot work — counting per type without saying which type — is refused rather than saved. Existing tickets keep their numbers, and every reference FreeITSM has ever issued goes on working, because email replies are matched by looking the number up rather than by recognising its shape. If you have just moved from another system and want the old references tidied away, Renumber existing tickets rewrites them all, oldest first — the old numbers are remembered for ever, so a reply quoting one still lands on the right ticket, exactly as it does when tickets are merged, and a retired number is never given to anybody else. It previews before it writes, and the Renumber button stays off until you have looked at the preview.
  • Raise a ticket for someone in a few keystrokes — search the requester by name or email and pick them, with their company shown so similar names are easy to tell apart. Anyone genuinely new can still be added inline without leaving the form.
  • Folders that add up — the folder list breaks every group down by status, so you can see at a glance that there are 41 tickets in progress before you open anything. All Tickets expands the same way as departments and analysts do, giving a status count across the whole desk, and dragging a ticket onto a status sets it.
  • Just my tickets, or no closed ones — a filter button beside Search narrows the folders and the list together to Mine (tickets assigned to you) and can hide closed tickets, whichever way the folders are grouped, and every folder count follows it. While a filter is on, the button carries a dot and a label sits beside the list title, so nobody wonders where half their tickets went. Grouped by analyst, your own folder is pinned to the top as My tickets, so on a desk of twenty analysts you are not scrolling to find yourself. Search has its own Include closed tickets switch, on by default. All of it is saved per analyst. Asked for in #149.
  • Assign a ticket to a team, not just a person — the service desk rarely knows who in Infrastructure handles what, so a ticket can go to the team and whoever picks it up assigns themselves. Team and analyst are separate, independent facts and both are optional: setting one never touches the other, and clearing the analyst leaves the team, so a ticket falls back into its queue rather than into the void. Everyone in the receiving team gets a bell notification, the folder list can be grouped by team as well as by department or analyst, and a team can be set from the reading pane, from the right-click menu, in bulk across a selection, or by a workflow that raises a ticket straight into a queue. It is invisible unless your install has teams — no picker, no grouping, nothing to switch off. Asked for in discussion #125.
  • A reading pane that stays readable on a ten-year-old ticket — email threads grow by re-quoting themselves, so the thing you opened the ticket to read ends up buried under a metre of chain, disclaimers and banners. Three things keep it legible, and none of them removes anything: a message taller than a limit you set is clipped with a Show more control (the newest is always shown in full, and what you expand stays expanded on that device); beyond a set number of recent messages the rest fold behind one {n} older messages line; and a message that has arrived before — a resend, a bounce carrying the original back, a distribution list delivering twice — is folded away with a line saying which earlier message it matches and when, catching a resend that differs by a single appended line as well as an exact copy. Everything is in the page the entire time, one tap from view, because a wrong judgement about what is noise should cost a click and never a fact. Eight settings under Tickets → Settings → General turn each part on or off and set the thresholds, so a desk that wants none of it can have none of it. Requested in discussion #104.
  • Optional AI help with a long ticket — two things, both off until you switch them on, because unlike everything else here they use your own AI provider and cost money per use. A maintained summary sits at the top of a ticket saying where it stands, what was asked, what has been done and who owes the next move; it always shows when it was written, how much it read, and how many messages have arrived since, so it can never quietly describe a ticket as it was five messages ago. Every version is kept — a refresh writes a new one rather than overwriting the last, because a later reading really can be worse than an earlier one and that loss would otherwise be silent. And "Read it for me" briefs you on a ticket you have never seen — what happened, what is unresolved, what it would do next — required to separate what the ticket says from what it is inferring. It is kept once written, so opening it again is instant and free rather than a minute's wait and a second charge — with a Read again button, and every earlier briefing still there. Neither ever replaces the conversation: the ticket sits underneath, in full, exactly as before. Configured under Tickets → Settings → General, sharing the one AI provider the Tickets module already uses. System → AI thinking decides, per feature, whether a model may think at length before answering — measured here at 54.7 seconds against 6.9 for the same job, with the fast answer the better of the two, so it is off unless you ask for it.
  • Ticket list you can tune — show priority, status and the assigned agent on each row in the inbox, each independently, as a left-edge colour bar, a corner block, a pill with the word, a dot, or initials. It is a per-analyst preference with an install-wide default, set at Tickets → Settings → Row display with a live preview.
  • Command palette — press ⌘K / Ctrl-K anywhere to jump to any module, search across tickets, changes, problems, knowledge, contracts, assets and CMDB items by name or reference, or run a quick action, all from the keyboard. Results respect your module access and active company.
  • A task in the large window, as one page or as tabs — a task carries a lot now: its fields, the people involved, tags, a description, repeats, links, subtasks, time recorded, comments and any attached documents. A button in the panel header switches the large window between the two columns it has always used and a strip of tabs — Details, Subtasks, Time, Comments, Links, Documents — and remembers which you prefer, per analyst, exactly like the side-panel/large-window choice beside it. Columns stay the default, because one long page is better when you want the whole task at once. Tabs holding a list carry a count, so three subtasks behind a tab are never indistinguishable from none, and a tab with nothing in it is not drawn.
  • Desktop notifications and task emails — in Preferences → Notifications, each analyst can have new items from the bell appear as notifications on their computer (in Edge on Windows, Windows notifications) while FreeITSM is open in a tab, and can ask for an email whenever a task is assigned to them, written in their own language.
  • The ticket menu on a phone — a long press on a ticket opens everything the desktop right-click offers, as a full-screen panel; choices with a further level, such as Set priority, slide across to their options.
  • Subtasks you can see and arrange — on the board, a task's subtasks hang under its card like branches of a tree, each one a click away; a personal setting in Preferences tidies them away once they are all complete. Inside the task, subtasks are dragged into order by a handle and carry Start and Due dates as columns you edit in place. Checklists on a task or subtask, and the steps inside each, can be dragged into order the same way.
  • More than one person on a task — a task still has one owner, who is accountable for it, and anybody else working on it is listed as Involved. The task then appears in their My Tasks as well, marked so they can still tell at a glance what is theirs to answer for and what they are helping with; pointing the analyst filter at somebody else asks the same question about them. Their initials sit beside the owner's on the board card, and on the task itself they are chips you add from a picker that offers only people who can actually reach that task's company. Adding somebody needs no special permission — it is everyday work, like tagging a task. Optionally, under Tasks → Settings → Involved, each person can tick off their own part, so you can see who has finished and who has not; the ticks are progress and never a gate — the owner still closes the task, with a warning you can dismiss if people are outstanding, because otherwise one person leaving would make a task permanently uncloseable. Switching that setting off hides the ticks rather than deleting them. Deliberately top-level tasks only: a subtask already carries an assignee of its own, which is how you say these four are each doing a piece. Being on a task means hearing what happens to it: Preferences → Notifications carries a switch for each moment on its own — assigned to you, added, taken off, a comment, a status change, a due-date change, completed — and everything about the task itself reaches the owner and everyone involved, with each person's own switches deciding what they see. Nothing ever tells you about your own actions. Those three moments are new workflow triggers as well, so they can drive automations rather than only notifications. Everything the REST API promised before is unmoved — assigned_analyst is still one person, and a new collaborators list sits beside it with involved_analyst_id and collaborator_id filters. From discussion #89.
  • Move a task to another company — a task raised against the wrong client used to mean deleting it and typing it again, losing its comments, its time entries and its history along with the mistake. Right-click a task and Move to company, from the board, the table or the timeline. Subtasks go with it, in one move, because a parent and its children have always belonged to the same company and splitting them would leave a parent with a child nobody else can see — for the same reason a subtask cannot be moved on its own. A task linked to a ticket, change or contract will not move away from what it is linked to; it says which link is in the way so you can decide what to do about it. Invisible on a single-company install.
  • A trail of where you have been — the waffle menu you use to leave a module now has a Recent tab you come back through, and it is an outline rather than a list. Records are grouped under the module you were in when you opened them, the way headings and body text sit in a word processor: read three tickets and they are three lines under one Tickets heading; step out to Knowledge for an article and that gets a heading of its own; come back to tickets and a second Tickets heading opens rather than the first one quietly growing. That repetition is the point — it shows you the shape of an afternoon's work and, more usefully, why those three tickets were open together. It lists things, not screens: APPSVR01 and TICKET-000110, never "Assets". Headings collapse, the newest is the one left open, and a search box along the bottom filters your own trail — not the whole system, which is what ⌘K is for. It is per analyst rather than per browser, so it survives signing out and follows you to another machine, and it needs no looking after: nothing to open, close or tidy, capped and aged out on its own. Everything is re-checked against your permissions each time you open it, so a record you can no longer see is simply gone, and a deleted one takes its heading with it rather than leaving a dead row. Covers tickets, tasks, problems, changes, assets, CMDB items, knowledge articles and contracts. Grew out of discussion #124, which asked for browser-style tabs inside the app — this is the answer to what those were for, in a shape that also works on a phone.
  • Dates written the way you want them — nine ways of writing a date (25 Aug 2026, 25/08/2026, 25.08.2026, 25-08-2026, 2026-08-25 and more) and the 24-hour or 12-hour clock, chosen under System → Date and time formats for the whole install and overridable by any analyst in their own Preferences. Deliberately not tied to the interface language: a German speaker at a British company may well want German wording and British dates, and two people in the same office genuinely disagree about this. Month names still follow the language, so 25 Aug 2026 reads 25 Mär 2026 in German in March. It changes only how a date is written — not the timezone it is shown in, not what is stored, and not service level targets, reports or exports.
  • Branding — set your organisation's logo once and it appears across the app, and design the login screen itself: background, layout, logo, headline, banner and footer strips, from presets or your own colours.
  • Internationalisation — 24 languages with per-analyst locale, plus per-analyst timezones, theming and dark mode, and a mobile-friendly core flow — the ticket inbox, Assets, the Calendar, the Knowledge Base, Service Status, Watchtower, Problem Management, Change Management, Software, Tasks, Forms, Contracts, Domains, the LMS, the CMDB, the Process Mapper, the Network Mapper, Workflows, System administration, Reporting, the System Wiki, the self-service portal and the War Room are built to work properly on a phone, without changing anything on the desktop. On the Network Mapper you can press and hold to place a box from the CMDB, move one, or delete it; on the Process Mapper a phone reads a map rather than builds one, and connectors stay a desktop job on both.

Documentation

Everything lives in the Documentation Wiki:

Guide Covers
Installation Docker and manual setup, prerequisites, configuration files
Architecture Technology stack, directory layout, shared components, database conventions
Security Authentication, authorisation layers, encryption, going-live checklist
REST API How the public API works, plus per-module endpoint guides
API Reference The internal session-based endpoints behind the UI

There are also long-form deep-dive articles on the website covering individual features, and a detailed update history.

Versions and releases

FreeITSM uses semantic versioning, read in terms of what an upgrade asks of you: a patch needs nothing, a minor adds features and keeps working with your existing configuration and data, and a major is reserved for the cases that can break a working install. How that is decided, when releases are cut, and what can honestly be rolled back are all written down in RELEASING.md.

The version you are running is shown on the System screen and stamped on the first line of every Debug Tools report. Released versions, with notes for each, are on the releases page.

New code sometimes brings new tables or columns with it, applied from System → Verify database. If you upgrade by hand that is one click, but anything unattended — a container coming up on a new image tag, a scripted deploy, a machine updating itself overnight — cannot click it. For those, run it from the command line instead:

php scripts/db_verify_cli.php            # report what would change, change nothing
php scripts/db_verify_cli.php --apply    # apply it

Preview is deliberately the default: this applies the same changes the button does, which includes dropping columns whose data has already been migrated elsewhere, so take a backup first. The script refuses to run over HTTP.

Every release is also published as a Docker image, so you can run a known version rather than building from whatever source you happen to have. In docker-compose.yml, replace build: . with:

image: ghcr.io/edmozley/freeitsm:1.0.0

:1.0 follows the newest 1.0.x, :1 the newest 1.x, and :latest the newest release. Pin the full number in production - rolling back is then a matter of changing it and running docker compose up -d. Images are built for both x86-64 and ARM, so a Raspberry Pi or an Apple Silicon Mac works too.

Technology stack: PHP 7.4–8.4 · MySQL 8.0+ · vanilla JavaScript (no frameworks) · TinyMCE · Apache, or nginx using the config it ships with.

👋 From the maintainer

FreeITSM is a one-developer project — your engagement is what keeps it moving:

  • ⭐ If you use FreeITSM, please star the repo — it's the single biggest signal that the work is landing.
  • 📬 Feedback, ideas, bugs? Email me directly at ed@freeitsm.co.uk — I read every message — or use Discussions and Issues.
  • 🔒 Found a security problem? Please report it privately rather than in an issue — see SECURITY.md. Every FreeITSM install is self-hosted, so operators need a chance to upgrade before anything is public.
  • 🌍 Mentioning freeitsm.co.uk on Reddit, Hacker News, Spiceworks or LinkedIn genuinely helps and means a lot.

Contributions are welcome — the first external pull request was merged in 2026 and more are encouraged.

License

MIT — free for commercial and personal use.

About

A completely free ITSM tool

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages