{"id":3950,"date":"2026-01-01T23:19:00","date_gmt":"2026-01-01T20:19:00","guid":{"rendered":"https:\/\/www.dchost.com\/blog\/error-tracking-for-php-and-javascript-apps-on-a-vps-with-sentry-and-open-source-tools\/"},"modified":"2026-01-01T23:19:00","modified_gmt":"2026-01-01T20:19:00","slug":"error-tracking-for-php-and-javascript-apps-on-a-vps-with-sentry-and-open-source-tools","status":"publish","type":"post","link":"https:\/\/www.dchost.com\/blog\/en\/error-tracking-for-php-and-javascript-apps-on-a-vps-with-sentry-and-open-source-tools\/","title":{"rendered":"Error Tracking for PHP and JavaScript Apps on a VPS with Sentry and Open\u2011Source Tools"},"content":{"rendered":"<div class=\"dchost-blog-content-wrapper\"><p>If you run a serious PHP or JavaScript application, relying only on server logs or a few <code>try\/catch<\/code> blocks is not enough. You need a way to see exactly which errors users hit, with stack traces, browser info, request context and deployment versions \u2013 ideally in one place and in near real time. That is where dedicated error tracking tools like Sentry and their open\u2011source alternatives shine. In this article, we will walk through how to wire error tracking into both PHP backends and browser\/SPA frontends, and how to host these tools efficiently on your own <a href=\"https:\/\/www.dchost.com\/vps\">VPS<\/a>.<\/p>\n<p>We will look at Sentry (hosted and self\u2011hosted), explore open\u2011source options you can run on a VPS, and show how to connect everything into a broader observability stack: logs, metrics and alerts. Along the way, we will discuss performance impact, security, GDPR\/KVKK considerations and practical rollout tips based on what we see every day while hosting PHP, Laravel, WordPress and JavaScript apps at dchost.com.<\/p>\n<div id=\"toc_container\" class=\"toc_transparent no_bullets\"><p class=\"toc_title\">\u0130&ccedil;indekiler<\/p><ul class=\"toc_list\"><li><a href=\"#What_Error_Tracking_Really_Solves_Beyond_Classic_Logs\"><span class=\"toc_number toc_depth_1\">1<\/span> What Error Tracking Really Solves (Beyond Classic Logs)<\/a><ul><li><a href=\"#Logs_vs_eventbased_error_tracking\"><span class=\"toc_number toc_depth_2\">1.1<\/span> Logs vs. event\u2011based error tracking<\/a><\/li><li><a href=\"#Why_PHP_and_JavaScript_need_slightly_different_handling\"><span class=\"toc_number toc_depth_2\">1.2<\/span> Why PHP and JavaScript need slightly different handling<\/a><\/li><\/ul><\/li><li><a href=\"#Planning_Your_VPS_for_Error_Tracking\"><span class=\"toc_number toc_depth_1\">2<\/span> Planning Your VPS for Error Tracking<\/a><ul><li><a href=\"#Resource_sizing\"><span class=\"toc_number toc_depth_2\">2.1<\/span> Resource sizing<\/a><\/li><li><a href=\"#Security_and_basic_hardening\"><span class=\"toc_number toc_depth_2\">2.2<\/span> Security and basic hardening<\/a><\/li><\/ul><\/li><li><a href=\"#Setting_Up_Sentry_for_PHP_on_a_VPSHosted_App\"><span class=\"toc_number toc_depth_1\">3<\/span> Setting Up Sentry for PHP on a VPS\u2011Hosted App<\/a><ul><li><a href=\"#Installing_the_Sentry_PHP_SDK\"><span class=\"toc_number toc_depth_2\">3.1<\/span> Installing the Sentry PHP SDK<\/a><\/li><li><a href=\"#Configuring_Sentry_cloud_or_selfhosted_as_the_backend\"><span class=\"toc_number toc_depth_2\">3.2<\/span> Configuring Sentry (cloud or self\u2011hosted) as the backend<\/a><\/li><li><a href=\"#Selfhosting_Sentry_on_a_VPS_with_Docker\"><span class=\"toc_number toc_depth_2\">3.3<\/span> Self\u2011hosting Sentry on a VPS with Docker<\/a><\/li><\/ul><\/li><li><a href=\"#Setting_Up_Sentry_for_Browser_JavaScript_and_SPAs\"><span class=\"toc_number toc_depth_1\">4<\/span> Setting Up Sentry for Browser JavaScript and SPAs<\/a><ul><li><a href=\"#Adding_the_Sentry_browser_SDK\"><span class=\"toc_number toc_depth_2\">4.1<\/span> Adding the Sentry browser SDK<\/a><\/li><li><a href=\"#Uploading_source_maps\"><span class=\"toc_number toc_depth_2\">4.2<\/span> Uploading source maps<\/a><\/li><li><a href=\"#Capturing_extra_context_and_user_data_safely\"><span class=\"toc_number toc_depth_2\">4.3<\/span> Capturing extra context and user data safely<\/a><\/li><\/ul><\/li><li><a href=\"#OpenSource_Error_Tracking_Alternatives_You_Can_SelfHost\"><span class=\"toc_number toc_depth_1\">5<\/span> Open\u2011Source Error Tracking Alternatives You Can Self\u2011Host<\/a><ul><li><a href=\"#GlitchTip\"><span class=\"toc_number toc_depth_2\">5.1<\/span> GlitchTip<\/a><\/li><li><a href=\"#Exceptionless\"><span class=\"toc_number toc_depth_2\">5.2<\/span> Exceptionless<\/a><\/li><li><a href=\"#Errbit\"><span class=\"toc_number toc_depth_2\">5.3<\/span> Errbit<\/a><\/li><li><a href=\"#Where_centralised_logging_fits_in\"><span class=\"toc_number toc_depth_2\">5.4<\/span> Where centralised logging fits in<\/a><\/li><\/ul><\/li><li><a href=\"#Integrating_Error_Tracking_with_Metrics_and_Alerts\"><span class=\"toc_number toc_depth_1\">6<\/span> Integrating Error Tracking with Metrics and Alerts<\/a><ul><li><a href=\"#Creating_meaningful_alert_rules\"><span class=\"toc_number toc_depth_2\">6.1<\/span> Creating meaningful alert rules<\/a><\/li><li><a href=\"#Correlating_errors_with_logs_and_server_metrics\"><span class=\"toc_number toc_depth_2\">6.2<\/span> Correlating errors with logs and server metrics<\/a><\/li><\/ul><\/li><li><a href=\"#Security_Privacy_and_Compliance_for_Error_Tracking_on_a_VPS\"><span class=\"toc_number toc_depth_1\">7<\/span> Security, Privacy and Compliance for Error Tracking on a VPS<\/a><ul><li><a href=\"#Minimising_sensitive_data\"><span class=\"toc_number toc_depth_2\">7.1<\/span> Minimising sensitive data<\/a><\/li><li><a href=\"#Access_control_and_retention\"><span class=\"toc_number toc_depth_2\">7.2<\/span> Access control and retention<\/a><\/li><\/ul><\/li><li><a href=\"#A_Practical_Rollout_Plan_for_Small_Teams\"><span class=\"toc_number toc_depth_1\">8<\/span> A Practical Rollout Plan for Small Teams<\/a><ul><li><a href=\"#Step_1_Start_with_PHP_in_production\"><span class=\"toc_number toc_depth_2\">8.1<\/span> Step 1 \u2013 Start with PHP in production<\/a><\/li><li><a href=\"#Step_2_Add_browser_JavaScript_tracking\"><span class=\"toc_number toc_depth_2\">8.2<\/span> Step 2 \u2013 Add browser JavaScript tracking<\/a><\/li><li><a href=\"#Step_3_Introduce_alerts_and_triage_workflow\"><span class=\"toc_number toc_depth_2\">8.3<\/span> Step 3 \u2013 Introduce alerts and triage workflow<\/a><\/li><li><a href=\"#Step_4_Integrate_with_logs_and_monitoring\"><span class=\"toc_number toc_depth_2\">8.4<\/span> Step 4 \u2013 Integrate with logs and monitoring<\/a><\/li><li><a href=\"#Step_5_Harden_security_and_privacy\"><span class=\"toc_number toc_depth_2\">8.5<\/span> Step 5 \u2013 Harden security and privacy<\/a><\/li><\/ul><\/li><li><a href=\"#Conclusion_A_Calm_Observable_Stack_for_PHP_and_JavaScript_on_a_VPS\"><span class=\"toc_number toc_depth_1\">9<\/span> Conclusion: A Calm, Observable Stack for PHP and JavaScript on a VPS<\/a><\/li><\/ul><\/div>\n<h2><span id=\"What_Error_Tracking_Really_Solves_Beyond_Classic_Logs\">What Error Tracking Really Solves (Beyond Classic Logs)<\/span><\/h2>\n<p>Before jumping into configuration, it is useful to clarify what dedicated error tracking adds on top of plain log files or basic <code>error_log<\/code> calls.<\/p>\n<h3><span id=\"Logs_vs_eventbased_error_tracking\">Logs vs. event\u2011based error tracking<\/span><\/h3>\n<p>Traditional logs (Apache\/Nginx logs, PHP <code>error_log<\/code>, application logs) are line\u2011based. You can absolutely run serious systems just with good logging \u2013 and if you have not yet tuned your PHP logging, you should definitely read our guide on <a href=\"https:\/\/www.dchost.com\/blog\/en\/php-hata-kayitlarini-dogru-yapilandirmak-display_errors-error_log-ve-log_level\/\">PHP error logging best practices on hosting servers<\/a>.<\/p>\n<p>However, for debugging real production issues, logs have limitations:<\/p>\n<ul>\n<li>You need to grep through huge files to connect lines that belong to the same request.<\/li>\n<li>Front\u2011end JavaScript errors often never reach server logs at all.<\/li>\n<li>It is hard to see frequency: is this error happening once a week or 1000 times per hour?<\/li>\n<li>Grouping similar stack traces and tracking regressions over releases is manual and painful.<\/li>\n<\/ul>\n<p>Error tracking platforms solve these problems by treating each error as a structured event. They capture:<\/p>\n<ul>\n<li>Exception type, message and full stack trace<\/li>\n<li>Environment (production, staging), release version, server host<\/li>\n<li>User agent, OS, browser, URL and sometimes user ID<\/li>\n<li>Tags and custom context you add from your code<\/li>\n<\/ul>\n<p>Then they group similar errors, show trends over time, and notify you when a new issue appears or an old one comes back after a deployment.<\/p>\n<h3><span id=\"Why_PHP_and_JavaScript_need_slightly_different_handling\">Why PHP and JavaScript need slightly different handling<\/span><\/h3>\n<p>On a PHP backend (Laravel, WordPress, Symfony, custom frameworks), a typical fatal error or uncaught exception will terminate the request. The stack trace is deterministic, attached to a single HTTP request, and you usually have access to the full environment and server logs.<\/p>\n<p>In the browser or in a JavaScript SPA (React, Vue, Angular, plain JS), errors behave very differently:<\/p>\n<ul>\n<li>They may be swallowed by the framework unless you hook global handlers.<\/li>\n<li>Users run different browsers, extensions and ad blockers \u2013 many will hide or modify requests.<\/li>\n<li>Source code is usually minified, so raw stack traces are not human\u2011friendly without source maps.<\/li>\n<\/ul>\n<p>A good error tracking setup therefore needs to:<\/p>\n<ul>\n<li>Capture back\u2011end PHP exceptions centrally.<\/li>\n<li>Capture front\u2011end JS errors, with proper source maps and environment tags.<\/li>\n<li>Correlate both sides via release versions, request IDs or user IDs when possible.<\/li>\n<\/ul>\n<h2><span id=\"Planning_Your_VPS_for_Error_Tracking\">Planning Your VPS for Error Tracking<\/span><\/h2>\n<p>You can absolutely use a hosted Sentry account, but many teams prefer to self\u2011host error tracking to control data location, privacy and costs. That is where a VPS comes in. At dchost.com, we see two main patterns:<\/p>\n<ul>\n<li><strong>App + error tracker on the same VPS:<\/strong> OK for small projects and internal tools.<\/li>\n<li><strong>Dedicated VPS for observability stack:<\/strong> Recommended once you have multiple apps or higher traffic.<\/li>\n<\/ul>\n<h3><span id=\"Resource_sizing\">Resource sizing<\/span><\/h3>\n<p>Error tracking workloads are typically I\/O and storage heavy (lots of small write operations, many documents kept for 30\u201390 days) plus some CPU for processing and grouping events.<\/p>\n<p>As a starting point:<\/p>\n<ul>\n<li><strong>Small app \/ single project:<\/strong> 2 vCPU, 4 GB RAM, fast SSD\/NVMe, 50\u2013100 GB disk.<\/li>\n<li><strong>Multiple apps \/ medium traffic:<\/strong> 4 vCPU, 8\u201316 GB RAM, 200+ GB NVMe, with room for growth.<\/li>\n<li><strong>Heavy usage or many teams:<\/strong> Consider a dedicated observability node and centralised logging, e.g. <a href=\"https:\/\/www.dchost.com\/blog\/en\/birden-fazla-sunucuda-log-yonetimi-elk-ve-loki-stack-ile-merkezi-hosting-loglama\/\">centralised logs with ELK or Loki<\/a>, alongside Sentry or its alternatives.<\/p>\n<\/ul>\n<p>If you are unsure how much CPU, RAM and storage you need, our guide on <a href=\"https:\/\/www.dchost.com\/blog\/en\/yeni-web-sitesi-icin-cpu-ram-ve-trafik-nasil-hesaplanir\/\">estimating traffic and resource needs for new websites<\/a> is a good baseline. For error tracking, lean a bit higher on disk and IOPS because of the sustained write pattern.<\/p>\n<h3><span id=\"Security_and_basic_hardening\">Security and basic hardening<\/span><\/h3>\n<p>Because your error tracker will store stack traces, headers, and possibly user identifiers, you must treat that VPS as sensitive. Review the <a href=\"https:\/\/www.dchost.com\/blog\/en\/vps-guvenlik-sertlestirme-kontrol-listesi-sshd_config-fail2ban-ve-root-erisimini-kapatmak\/\">VPS security hardening checklist<\/a> and at minimum:<\/p>\n<ul>\n<li>Disable direct root SSH and use key\u2011based authentication.<\/li>\n<li>Keep the system updated and enable automatic security updates.<\/li>\n<li>Restrict inbound ports (typically only 80\/443 for the web UI and API).<\/li>\n<li>Place the error tracker behind HTTPS with a valid <a href=\"https:\/\/www.dchost.com\/ssl\">SSL certificate<\/a>.<\/li>\n<\/ul>\n<h2><span id=\"Setting_Up_Sentry_for_PHP_on_a_VPSHosted_App\">Setting Up Sentry for PHP on a VPS\u2011Hosted App<\/span><\/h2>\n<p>Sentry is one of the most widely used error tracking tools. You can use the SaaS version, or host Sentry yourself on a VPS using Docker. The PHP SDK is the same in both cases; the difference is where the DSN (Data Source Name) points.<\/p>\n<h3><span id=\"Installing_the_Sentry_PHP_SDK\">Installing the Sentry PHP SDK<\/span><\/h3>\n<p>For a modern PHP project using Composer, add the Sentry SDK:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">composer require sentry\/sentry-php<\/code><\/pre>\n<p>In Laravel, you can also use <code>sentry\/sentry-laravel<\/code>, but we will stay framework\u2011agnostic here.<\/p>\n<p>Next, initialise Sentry in your app bootstrap (for example, in <code>public\/index.php<\/code> or a framework service provider):<\/p>\n<pre class=\"language-php line-numbers\"><code class=\"language-php\">&lt;?php\n\nSentryinit([\n    'dsn' =&gt; getenv('SENTRY_DSN'),\n    'environment' =&gt; getenv('APP_ENV') ?: 'production',\n    'release' =&gt; getenv('APP_RELEASE') ?: 'unknown',\n    'traces_sample_rate' =&gt; 0.0, \/\/ enable later if you want performance tracing\n]);\n\n\/\/ Attach user \/ custom context if available\nif (isset($currentUserId)) {\n    SentryconfigureScope(function (SentryStateScope $scope) use ($currentUserId) {\n        $scope-&gt;setUser(['id' =&gt; $currentUserId]);\n    });\n}\n\n\/\/ In a global exception handler\ntry {\n    \/\/ your app logic\n} catch (Throwable $e) {\n    SentrycaptureException($e);\n    throw $e; \/\/ or render a friendly error page\n}\n<\/code><\/pre>\n<p>Always keep your DSN and API keys out of your code. We recommend placing them in environment variables or configuration files outside the document root. If you are not yet comfortable with this, see our detailed article on <a href=\"https:\/\/www.dchost.com\/blog\/en\/vpste-env-ve-gizli-anahtar-yonetimi\/\">managing .env files and secrets on a VPS safely<\/a>.<\/p>\n<h3><span id=\"Configuring_Sentry_cloud_or_selfhosted_as_the_backend\">Configuring Sentry (cloud or self\u2011hosted) as the backend<\/span><\/h3>\n<p>Once you create a project in Sentry\u2019s interface (or in your own self\u2011hosted instance), you will get a DSN string, which looks like this:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">https:\/\/publicKey@your-sentry.example.com\/1<\/code><\/pre>\n<p>Set it in your environment:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\"># .env\nSENTRY_DSN=https:\/\/publicKey@your-sentry.example.com\/1\nAPP_ENV=production\nAPP_RELEASE=1.3.0<\/code><\/pre>\n<h3><span id=\"Selfhosting_Sentry_on_a_VPS_with_Docker\">Self\u2011hosting Sentry on a VPS with Docker<\/span><\/h3>\n<p>Sentry provides an official Docker\u2011based self\u2011hosted bundle. On a fresh VPS, after hardening and installing Docker + docker\u2011compose, you can roughly follow this pattern (simplified example):<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">git clone https:\/\/github.com\/getsentry\/self-hosted.git sentry-self-hosted\ncd sentry-self-hosted\n\ncp .env.example .env\n# Edit SMTP, SENTRY_SECRET_KEY, database passwords, etc.\n\n.\/install.sh  # one-time bootstrap\n\ndocker compose up -d<\/code><\/pre>\n<p>By default, this stack will run Sentry, PostgreSQL, Redis, Kafka and related services. Point your DNS (e.g. <code>sentry.yourdomain.com<\/code>) to the VPS, put Nginx or Caddy in front with HTTPS, and configure the Sentry web UI to use your external URL.<\/p>\n<p>For production, make sure:<\/p>\n<ul>\n<li>The VPS disk is fast (NVMe if possible) to handle write operations.<\/li>\n<li>You set backups for the PostgreSQL database and configuration volumes (see our general <a href=\"https:\/\/www.dchost.com\/blog\/en\/yedekleme-stratejisi-nasil-planlanir-blog-e-ticaret-ve-saas-siteleri-icin-rpo-rto-rehberi\/\">backup strategy guide with RPO\/RTO planning<\/a>).<\/li>\n<li>Access to the Sentry UI is restricted (VPN, IP allow\u2011lists or at least strong authentication).<\/li>\n<\/ul>\n<h2><span id=\"Setting_Up_Sentry_for_Browser_JavaScript_and_SPAs\">Setting Up Sentry for Browser JavaScript and SPAs<\/span><\/h2>\n<p>Server\u2011side PHP error tracking is only half of the picture; many bugs appear only in certain browsers or devices. Sentry\u2019s JavaScript SDK can capture those errors, link them to releases and use source maps for readable stack traces.<\/p>\n<h3><span id=\"Adding_the_Sentry_browser_SDK\">Adding the Sentry browser SDK<\/span><\/h3>\n<p>For a simple multi\u2011page PHP site with inline scripts, you can use the CDN snippet:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">&lt;script src=&quot;https:\/\/browser.sentry-cdn.com\/7.x.x\/bundle.tracing.min.js&quot; integrity=&quot;sha384-...&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;\/script&gt;\n&lt;script&gt;\n  Sentry.init({\n    dsn: 'https:\/\/publicKey@your-sentry.example.com\/1',\n    environment: 'production',\n    release: '1.3.0',\n    tracesSampleRate: 0.0 \/\/ enable later if you also want front-end performance tracing\n  });\n&lt;\/script&gt;<\/code><\/pre>\n<p>For bundler\u2011based apps (React\/Vue\/Angular using Webpack, Vite, etc.), install via npm:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">npm install --save @sentry\/browser @sentry\/tracing<\/code><\/pre>\n<p>Then configure in your entry file (for example, <code>src\/main.js<\/code>):<\/p>\n<pre class=\"language-python line-numbers\"><code class=\"language-python\">import * as Sentry from '@sentry\/browser';\nimport { Integrations } from '@sentry\/tracing';\n\nSentry.init({\n  dsn: process.env.VUE_APP_SENTRY_DSN,\n  environment: process.env.NODE_ENV,\n  release: process.env.APP_RELEASE,\n  integrations: [\n    new Integrations.BrowserTracing(),\n  ],\n  tracesSampleRate: 0.0,\n});<\/code><\/pre>\n<h3><span id=\"Uploading_source_maps\">Uploading source maps<\/span><\/h3>\n<p>To make minified stack traces readable, you should upload source maps to Sentry as part of your build pipeline. Sentry offers CLI tools and Webpack\/Vite plugins that upload source maps during deployment, tagging them with the same release you use in <code>Sentry.init()<\/code>.<\/p>\n<p>Typical flow:<\/p>\n<ol>\n<li>Set a release identifier (e.g. git commit hash) in your build environment.<\/li>\n<li>Build assets with source maps enabled.<\/li>\n<li>Upload source maps with Sentry\u2019s CLI using that release ID.<\/li>\n<li>Deploy assets and application.<\/li>\n<\/ol>\n<p>This way, when a user\u2019s browser throws an error, Sentry can map the minified line\/column back to the original source file and line in your repository.<\/p>\n<h3><span id=\"Capturing_extra_context_and_user_data_safely\">Capturing extra context and user data safely<\/span><\/h3>\n<p>Both in PHP and JS, you should enrich errors with useful context, but avoid storing sensitive personal data (passwords, card numbers, raw addresses). A common safe pattern is:<\/p>\n<ul>\n<li>Attach anonymised user identifiers (internal user ID or hashed email), not full PII.<\/li>\n<li>Capture feature flags, A\/B test variants, or tenant IDs.<\/li>\n<li>Use Sentry\u2019s built\u2011in data scrubbing to mask known fields (e.g. <code>password<\/code>, <code>authorization<\/code> headers).<\/li>\n<\/ul>\n<p>If you operate in KVKK\/GDPR jurisdictions, align your setup with our guide on <a href=\"https:\/\/www.dchost.com\/blog\/en\/kvkk-ve-gdpr-uyumlu-hosting-secimi-turkiye-avrupa-ve-abd-veri-merkezleri-arasinda-veri-yerellestirme-stratejisi\/\">choosing KVKK\/GDPR\u2011compliant hosting and data localisation<\/a>. Error tracking data is part of that story.<\/p>\n<h2><span id=\"OpenSource_Error_Tracking_Alternatives_You_Can_SelfHost\">Open\u2011Source Error Tracking Alternatives You Can Self\u2011Host<\/span><\/h2>\n<p>Sentry is powerful, but not the only choice. If you prefer simpler stacks or different licenses, several open\u2011source alternatives work well on a VPS. Here are a few options many teams successfully self\u2011host.<\/p>\n<h3><span id=\"GlitchTip\">GlitchTip<\/span><\/h3>\n<p>GlitchTip is an open\u2011source error tracking platform that implements the Sentry protocol. That means your existing Sentry SDKs (PHP and JS) can often talk to GlitchTip with minimal code changes \u2013 you just point the DSN to your GlitchTip host.<\/p>\n<p>Highlights:<\/p>\n<ul>\n<li>Fewer moving parts than full self\u2011hosted Sentry.<\/li>\n<li>PostgreSQL\u2011backed, Django\u2011based.<\/li>\n<li>Works with Sentry SDKs for many languages.<\/li>\n<\/ul>\n<p>A minimal Docker Compose snippet (simplified example, always check the official docs):<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">version: '3.7'\n\nservices:\n  glitchtip:\n    image: glitchtip\/glitchtip:latest\n    env_file: .env\n    depends_on:\n      - postgres\n    ports:\n      - &quot;8000:8000&quot;\n\n  postgres:\n    image: postgres:15\n    environment:\n      POSTGRES_DB: glitchtip\n      POSTGRES_USER: glitchtip\n      POSTGRES_PASSWORD: strongpassword\n    volumes:\n      - db-data:\/var\/lib\/postgresql\/data\n\nvolumes:\n  db-data:\n<\/code><\/pre>\n<p>Once running behind your web server and HTTPS, create a project, copy the DSN and plug it into your PHP and JS SDKs just like you would with Sentry.<\/p>\n<h3><span id=\"Exceptionless\">Exceptionless<\/span><\/h3>\n<p>Exceptionless is a .NET\u2011centric but language\u2011agnostic error tracking solution with a modern web UI and REST API. It supports clients for multiple platforms and can ingest events via HTTP, so PHP\/JS integration is straightforward.<\/p>\n<p>Basic Docker example:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">version: '3.7'\n\nservices:\n  exceptionless:\n    image: exceptionless\/exceptionless:latest\n    environment:\n      EX_AppMode: Production\n      EX_ConnectionStrings__Storage: provider=folder;path=\/app\/storage\n      EX_ConnectionStrings__Elasticsearch: http:\/\/elasticsearch:9200\n    ports:\n      - &quot;5000:80&quot;\n    depends_on:\n      - elasticsearch\n\n  elasticsearch:\n    image: docker.elastic.co\/elasticsearch\/elasticsearch:7.17.0\n    environment:\n      discovery.type: single-node\n    volumes:\n      - es-data:\/usr\/share\/elasticsearch\/data\n\nvolumes:\n  es-data:\n<\/code><\/pre>\n<p>Use the provided authentication keys and project tokens to send events from your PHP and client\u2011side JavaScript. Exceptionless supports grouping, dashboards and notifications similar to Sentry.<\/p>\n<h3><span id=\"Errbit\">Errbit<\/span><\/h3>\n<p>Errbit is an open\u2011source error catcher compatible with the Airbrake and Hoptoad API. Many languages, including PHP, have Airbrake\u2011style clients, and some JavaScript libraries can send errors in that format as well.<\/p>\n<p>Errbit is Ruby\u2011based and can be deployed with Passenger, Puma or via Docker. For many teams, it is attractive because it is relatively lightweight and easy to run on a modest VPS if traffic is not huge.<\/p>\n<h3><span id=\"Where_centralised_logging_fits_in\">Where centralised logging fits in<\/span><\/h3>\n<p>Error trackers are for structured exception events. They are not a full replacement for logs. In practice, most mature setups combine:<\/p>\n<ul>\n<li>An error tracker (Sentry, GlitchTip, Exceptionless, Errbit, \u2026) for exceptions and front\u2011end errors.<\/li>\n<li>A central log stack (ELK, Loki, etc.) to store web server logs, application logs, database logs and security logs.<\/li>\n<\/ul>\n<p>If you are already thinking about multiple services and VPS nodes, it is worth reading our article on <a href=\"https:\/\/www.dchost.com\/blog\/en\/birden-fazla-sunucuda-log-yonetimi-elk-ve-loki-stack-ile-merkezi-hosting-loglama\/\">centralising logs for multiple servers with ELK and Loki<\/a>. Error tracking fits naturally into that wider observability picture.<\/p>\n<h2><span id=\"Integrating_Error_Tracking_with_Metrics_and_Alerts\">Integrating Error Tracking with Metrics and Alerts<\/span><\/h2>\n<p>Once PHP and JavaScript errors are flowing into your tracker, the next step is making sure they actually trigger useful actions instead of just filling a dashboard.<\/p>\n<h3><span id=\"Creating_meaningful_alert_rules\">Creating meaningful alert rules<\/span><\/h3>\n<p>A few practical alert patterns:<\/p>\n<ul>\n<li><strong>New error type in production:<\/strong> Notify the team when a brand\u2011new exception appears.<\/li>\n<li><strong>Error spike:<\/strong> Alert when the rate of a specific error exceeds a threshold over X minutes.<\/li>\n<li><strong>Regression after release:<\/strong> Alert if an error that was previously resolved reappears in the latest release.<\/li>\n<\/ul>\n<p>Most platforms let you send alerts to email, chat or generic webhooks. You can also integrate with Prometheus\/Grafana alerting by converting error rates into metrics. If you are building a more complete monitoring stack, see our guide on <a href=\"https:\/\/www.dchost.com\/blog\/en\/vps-izleme-ve-uyari-nasil-kurulur-prometheus-grafana-ve-node-exporter-ile-sessiz-alarmlari-konusturmak\/\">VPS monitoring and alerts with Prometheus and Grafana<\/a>.<\/p>\n<h3><span id=\"Correlating_errors_with_logs_and_server_metrics\">Correlating errors with logs and server metrics<\/span><\/h3>\n<p>When debugging a complex incident, you often need to move between three views:<\/p>\n<ul>\n<li><strong>Error event:<\/strong> Stack trace, user, URL, environment.<\/li>\n<li><strong>Logs:<\/strong> Application log lines and web server logs around the same timestamp.<\/li>\n<li><strong>Metrics:<\/strong> CPU, RAM, disk I\/O, database latency at that time.<\/li>\n<\/ul>\n<p>By standardising on request IDs or correlation IDs and logging them consistently, you can:<\/p>\n<ul>\n<li>Include the request ID as a tag in your error events.<\/li>\n<li>Write the same ID into your PHP logs and Nginx\/Apache logs.<\/li>\n<li>Search across logs and error tracker with that ID when debugging.<\/li>\n<\/ul>\n<p>This style of observability is especially helpful for larger stores and apps where performance issues and errors interact. For example, our article on <a href=\"https:\/\/www.dchost.com\/blog\/en\/woocommerce-ve-buyuk-katalog-siteleri-icin-mysql-indeksleme-ve-sorgu-optimizasyonu-rehberi\/\">MySQL indexing and query optimisation for WooCommerce<\/a> shows how database bottlenecks and PHP errors often appear together.<\/p>\n<h2><span id=\"Security_Privacy_and_Compliance_for_Error_Tracking_on_a_VPS\">Security, Privacy and Compliance for Error Tracking on a VPS<\/span><\/h2>\n<p>Error tracking systems can easily collect more data than you actually need. That can be a risk in terms of privacy regulations and security.<\/p>\n<h3><span id=\"Minimising_sensitive_data\">Minimising sensitive data<\/span><\/h3>\n<p>Good practices include:<\/p>\n<ul>\n<li><strong>Masking:<\/strong> Use built\u2011in data scrubbing to strip or anonymise fields like cookies, session IDs, credit card numbers, emails, etc.<\/li>\n<li><strong>Selective context:<\/strong> Do not send full request bodies (especially for POST\/PUT) unless necessary; if you do, mask known sensitive keys.<\/li>\n<li><strong>User identifiers:<\/strong> Prefer internal user IDs or hashed identifiers over raw emails or phone numbers.<\/li>\n<\/ul>\n<p>Review your error payloads by inspecting events within your tracker and adjust scrubbing rules until you are comfortable with what is stored.<\/p>\n<h3><span id=\"Access_control_and_retention\">Access control and retention<\/span><\/h3>\n<p>Because your error tracker contains internal application details and sometimes personal data, you should:<\/p>\n<ul>\n<li>Enforce strong authentication (MFA where possible) for the web UI.<\/li>\n<li>Limit who can access which projects, especially in multi\u2011tenant agency setups.<\/li>\n<li>Set sane data retention (for example 30\u201390 days) rather than keeping everything forever.<\/li>\n<li>Include the error tracker in your overall backup, DR and off\u2011site backup strategy.<\/li>\n<\/ul>\n<p>All of this should fit into your broader compliance and retention plan; if you do not yet have one, our article on <a href=\"https:\/\/www.dchost.com\/blog\/en\/hosting-ve-e-posta-altyapisinda-log-saklama-sureleri\/\">log retention on hosting and email infrastructure for KVKK\/GDPR<\/a> gives a practical starting point that applies to error events as well.<\/p>\n<h2><span id=\"A_Practical_Rollout_Plan_for_Small_Teams\">A Practical Rollout Plan for Small Teams<\/span><\/h2>\n<p>It is tempting to try to instrument everything at once. In practice, it works better to roll out error tracking gradually and improve as you go.<\/p>\n<h3><span id=\"Step_1_Start_with_PHP_in_production\">Step 1 \u2013 Start with PHP in production<\/span><\/h3>\n<ul>\n<li>Pick a tool: Sentry (hosted or self\u2011hosted), GlitchTip, Exceptionless, etc.<\/li>\n<li>Install the PHP SDK in your main application.<\/li>\n<li>Wire your global exception handler to capture errors.<\/li>\n<li>Confirm that test exceptions appear in your dashboard.<\/li>\n<\/ul>\n<h3><span id=\"Step_2_Add_browser_JavaScript_tracking\">Step 2 \u2013 Add browser JavaScript tracking<\/span><\/h3>\n<ul>\n<li>Install the JS\/browser SDK and configure it with DSN, environment and release.<\/li>\n<li>Generate and upload source maps if you use a bundler.<\/li>\n<li>Trigger a deliberate error in the browser and verify the event groups correctly.<\/li>\n<\/ul>\n<h3><span id=\"Step_3_Introduce_alerts_and_triage_workflow\">Step 3 \u2013 Introduce alerts and triage workflow<\/span><\/h3>\n<ul>\n<li>Define what should send alerts (new errors, spikes, specific endpoints).<\/li>\n<li>Connect alerts to your team\u2019s communication channel or ticketing system.<\/li>\n<li>Establish a routine: who triages, when, and how you mark issues as resolved.<\/li>\n<\/ul>\n<h3><span id=\"Step_4_Integrate_with_logs_and_monitoring\">Step 4 \u2013 Integrate with logs and monitoring<\/span><\/h3>\n<ul>\n<li>Standardise on a request ID or correlation ID across PHP, Nginx\/Apache and your error tracker.<\/li>\n<li>Set up central logging (ELK, Loki) if you run multiple services.<\/li>\n<li>Connect error rates to your metrics stack (Prometheus\/Grafana) for SLOs and reliability dashboards.<\/li>\n<\/ul>\n<h3><span id=\"Step_5_Harden_security_and_privacy\">Step 5 \u2013 Harden security and privacy<\/span><\/h3>\n<ul>\n<li>Review the data being stored in events and tighten scrubbing rules.<\/li>\n<li>Lock down your VPS following our <a href=\"https:\/\/www.dchost.com\/blog\/en\/vps-guvenlik-sertlestirme-kontrol-listesi-sshd_config-fail2ban-ve-root-erisimini-kapatmak\/\">VPS security hardening checklist<\/a>.<\/li>\n<li>Integrate error tracking into your backup and disaster recovery tests.<\/li>\n<\/ul>\n<h2><span id=\"Conclusion_A_Calm_Observable_Stack_for_PHP_and_JavaScript_on_a_VPS\">Conclusion: A Calm, Observable Stack for PHP and JavaScript on a VPS<\/span><\/h2>\n<p>Modern PHP and JavaScript applications are too complex to debug purely from scattered log files and user screenshots. A dedicated error tracking layer \u2013 whether Sentry or an open\u2011source alternative on your VPS \u2013 gives you structured events, grouping, trends and alerts that turn vague \u201cit is broken\u201d complaints into actionable stack traces.<\/p>\n<p>Start simple: capture PHP exceptions in production, then add browser\/SPA error tracking. Once events are flowing, add meaningful alert rules, tie everything into centralised logs and metrics, and harden the security of your tracking stack. With a well\u2011sized VPS from dchost.com, fast storage and a sensible retention policy, you can run your own error tracking platform alongside your apps without drama.<\/p>\n<p>If you would like help choosing the right VPS resources or planning where error tracking fits into your wider architecture (staging\/production separation, backups, observability), our team at dchost.com works with these patterns every day. Reach out, and we can design a calm, reliable stack tailored to your PHP and JavaScript applications.<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>If you run a serious PHP or JavaScript application, relying only on server logs or a few try\/catch blocks is not enough. You need a way to see exactly which errors users hit, with stack traces, browser info, request context and deployment versions \u2013 ideally in one place and in near real time. That is [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3951,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26],"tags":[],"class_list":["post-3950","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-teknoloji"],"_links":{"self":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/posts\/3950","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/comments?post=3950"}],"version-history":[{"count":0,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/posts\/3950\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/media\/3951"}],"wp:attachment":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/media?parent=3950"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/categories?post=3950"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/tags?post=3950"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}