<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Maddy</title>
    <description>The latest articles on Forem by Maddy (@maddy_404_).</description>
    <link>https://forem.com/maddy_404_</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3918054%2Ff0ee5ef6-16c5-4650-8fb7-6257be09972e.png</url>
      <title>Forem: Maddy</title>
      <link>https://forem.com/maddy_404_</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/maddy_404_"/>
    <language>en</language>
    <item>
      <title>How Engineers Adapt Screen Workflows for Color Blindness: Tools, ICC Profiles, and Beyond</title>
      <dc:creator>Maddy</dc:creator>
      <pubDate>Sat, 09 May 2026 00:41:58 +0000</pubDate>
      <link>https://forem.com/maddy_404_/how-engineers-adapt-screen-workflows-for-color-blindness-tools-icc-profiles-and-beyond-3e6f</link>
      <guid>https://forem.com/maddy_404_/how-engineers-adapt-screen-workflows-for-color-blindness-tools-icc-profiles-and-beyond-3e6f</guid>
      <description>&lt;h2&gt;
  
  
  Why Standard Color Correction Falls Short for Developers
&lt;/h2&gt;

&lt;p&gt;Most operating systems ship with color blindness filters—macOS has &lt;strong&gt;Display Color Filters&lt;/strong&gt;, Windows offers the &lt;strong&gt;Color Filtering&lt;/strong&gt; feature, and many Linux desktops include similar options. These tools adjust hues globally, simulating protanopia, deuteranopia, tritanopia, or grayscale modes. However, they often oversimplify the problem: they don’t account for rare color blindness variations like achromatopsia or blue-yellow deficiency nuances. They also fail to isolate corrections to specific apps or workflows, which matters when you’re debugging a UI with critical color cues.&lt;/p&gt;

&lt;p&gt;If you’re a developer, designer, or sysadmin, generic filters won’t cut it. You need surgical precision—targeted corrections that preserve contrast, don’t distort text legibility, and adapt across multiple displays. This is where &lt;strong&gt;ICC profiles&lt;/strong&gt;, custom shaders, and developer-centric tools come in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a Custom ICC Profile for Accurate Color Mapping
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Diagnose Your Color Vision Deficiency
&lt;/h3&gt;

&lt;p&gt;Start by identifying your exact type and severity. Tools like &lt;strong&gt;ColorOracle&lt;/strong&gt; or &lt;strong&gt;Ishihara Test&lt;/strong&gt; online can help, but a professional assessment (via an optometrist) is ideal. Once you know your deficiency, you can target corrections more effectively. For example, if you have deuteranomaly (the most common), reds and greens appear desaturated, so you’ll want to boost saturation in the red-green axis without altering blues or cyans.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Generate a Baseline ICC Profile
&lt;/h3&gt;

&lt;p&gt;Use a colorimeter like &lt;strong&gt;SpyderX Pro&lt;/strong&gt; or &lt;strong&gt;X-Rite i1Display Pro&lt;/strong&gt; to create an accurate display profile. This step ensures your corrections sit on a calibrated foundation. Without calibration, any correction you apply will be skewed by your screen’s native deficiencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Apply Color Blindness Corrections via ICC Profile
&lt;/h3&gt;

&lt;p&gt;ICC profiles can embed color transformations to simulate or compensate for vision deficiencies. You can edit an existing profile or create a new one using software like &lt;strong&gt;ArgyllCMS&lt;/strong&gt;. Here’s how to do it manually using ArgyllCMS on Linux or macOS:&lt;/p&gt;

&lt;p&gt;$ # Install ArgyllCMS (Ubuntu/Debian)&lt;br&gt;
$ sudo apt install argyll&lt;/p&gt;

&lt;p&gt;$ # Generate a baseline profile from your display&lt;br&gt;
$ dispcal -v -q l -t 6500 -o display_profiling.icc&lt;/p&gt;

&lt;p&gt;$ # Simulate deuteranopia correction on top of the baseline&lt;br&gt;
$ colprof -v -q h -S "deutan.icc" -o corrected.icc -C "Custom Deutan Correction"&lt;/p&gt;

&lt;p&gt;In this example, &lt;strong&gt;deutan.icc&lt;/strong&gt; is a pre-made profile simulating or correcting deuteranopia. You can also handcraft transformations using the &lt;strong&gt;ArgyllCMS .cal&lt;/strong&gt; file format or tools like &lt;strong&gt;LittleCMS&lt;/strong&gt; to blend colors more intelligently. While this method is powerful, it requires comfort with the command line and a colorimeter.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Apply the Profile System-Wide or Per-App
&lt;/h3&gt;

&lt;p&gt;On Linux, install the profile via &lt;strong&gt;GNOME Color Manager&lt;/strong&gt; or &lt;strong&gt;KDE’s Color Settings&lt;/strong&gt;. On Windows, use &lt;strong&gt;DisplayCAL&lt;/strong&gt; to install the ICC profile as the default system profile. macOS handles this natively through &lt;strong&gt;System Preferences &amp;gt; Displays &amp;gt; Color &amp;gt; Customize&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For per-application control (e.g., in VS Code or a terminal), use environment variables like:&lt;/p&gt;

&lt;p&gt;$ export QT_QPA_PLATFORM_COLOR_SCHEME=128&lt;br&gt;
$ export GDK_COLOR_SCHEME=dark&lt;/p&gt;

&lt;p&gt;These tweaks ensure consistent contrast and color mapping across editors and IDEs.&lt;/p&gt;

&lt;h2&gt;
  
  
  When ICC Profiles Aren’t Enough: Developer-Specific Workarounds
&lt;/h2&gt;

&lt;p&gt;Even with a perfect ICC profile, some tasks demand additional layers of adaptation. Here are proven strategies used by color-blind engineers:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Override App-Specific Color Palettes
&lt;/h3&gt;

&lt;p&gt;Many apps use hardcoded color schemes. For instance, Jira uses green for “Done” and red for “Blocked.” You can override these with browser extensions like &lt;strong&gt;Stylus&lt;/strong&gt; or &lt;strong&gt;Dark Reader&lt;/strong&gt;. Add custom CSS to swap colors:&lt;/p&gt;

&lt;p&gt;/* Jira: Change red blocked status to orange */&lt;br&gt;
.jira-issue.status-blocked {&lt;br&gt;
  background-color: #FFA500 !important;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;This overrides the default red, which may blend into the background for protanopes.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Use Terminals and Editors with Theme Flexibility
&lt;/h3&gt;

&lt;p&gt;Switch to colorblind-friendly themes in tools like &lt;strong&gt;VS Code&lt;/strong&gt;, &lt;strong&gt;JetBrains IDEs&lt;/strong&gt;, or &lt;strong&gt;Fira Code&lt;/strong&gt; font settings. The &lt;strong&gt;“Color Blind Friendly”&lt;/strong&gt; theme in VS Code uses high-contrast, luminance-based colors instead of hue-dependent ones. In JetBrains, choose the &lt;strong&gt;Darcula&lt;/strong&gt; theme and enable &lt;strong&gt;Color Blind Mode&lt;/strong&gt; under Settings &amp;gt; Editor &amp;gt; Color Scheme &amp;gt; Accessibility.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Leverage Screen Readers and Annotation Tools
&lt;/h3&gt;

&lt;p&gt;When color alone isn’t enough, combine visual cues with audio or text. Use &lt;strong&gt;NVDA&lt;/strong&gt; or &lt;strong&gt;JAWS&lt;/strong&gt; for screen reading. Alternatively, annotate your desktop with &lt;strong&gt;Sticky Notes&lt;/strong&gt; or &lt;strong&gt;Notion&lt;/strong&gt; to label folders and files by shape and pattern, not just color. For example, mark important logs with a red border and error logs with a dashed red border—both on a grayscale background.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Build Your Own Lens: Shader-Based Correction in Games
&lt;/h3&gt;

&lt;p&gt;In game development or real-time rendering, you can apply custom shaders to simulate or compensate for vision deficiencies. Using &lt;strong&gt;Unity&lt;/strong&gt; or &lt;strong&gt;Unreal Engine&lt;/strong&gt;, load a fragment shader that transforms color output:&lt;/p&gt;

&lt;p&gt;precision highp float;&lt;br&gt;
varying vec2 v_texCoord;&lt;br&gt;
uniform sampler2D u_texture;&lt;/p&gt;

&lt;p&gt;// Corrected color for deuteranomaly&lt;br&gt;
vec3 correctColor(vec3 c) {&lt;br&gt;
  return vec3(&lt;br&gt;
    (c.r * 0.7 + c.g * 0.3),&lt;br&gt;
    (c.r * 0.3 + c.g * 0.7),&lt;br&gt;
    c.b&lt;br&gt;
  ).rgb;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;void main() {&lt;br&gt;
  vec4 color = texture2D(u_texture, v_texCoord);&lt;br&gt;
  gl_FragColor = vec4(correctColor(color.rgb), color.a);&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;This shader blends red and green channels to reduce confusion without losing overall vibrancy. You can port this logic to Python with &lt;strong&gt;OpenCV&lt;/strong&gt; or &lt;strong&gt;Pillow&lt;/strong&gt; for static image correction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing and Iterating: Ensure Your Fixes Work
&lt;/h2&gt;

&lt;p&gt;Before deploying any solution, validate it with tools like &lt;strong&gt;Sim Daltonism&lt;/strong&gt; (macOS) or &lt;strong&gt;Color Oracle&lt;/strong&gt; (cross-platform). These simulators show how your screen appears to users with various deficiencies. Use them to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Check contrast on graphs and data visualizations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Test UI buttons and status indicators&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Simulate lighting conditions and display calibration drift&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, seek feedback from colleagues or friends with color blindness. What looks distinct to you might still blend for others due to residual hue shifts or brightness mismatches.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quick Integration Checklist
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;🎯 Identify your exact color vision deficiency type&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;🔧 Calibrate your display with a colorimeter&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;📦 Install corrected ICC profile system-wide&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;⚙️ Adjust app-specific themes and CSS overrides&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;🧪 Simulate and validate using Color Oracle&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;📝 Annotate critical UI elements with patterns or labels&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When All Else Fails: Go Grayscale or Monochrome
&lt;/h2&gt;

&lt;p&gt;For rare cases like achromatopsia or severe blue-yellow deficiency, consider running your entire workflow in grayscale. On macOS: &lt;strong&gt;System Preferences &amp;gt; Accessibility &amp;gt; Display &amp;gt; Use Grayscale&lt;/strong&gt;. On Windows: &lt;strong&gt;Ease of Access &amp;gt; Color Filters &amp;gt; Grayscale&lt;/strong&gt;. While this removes color entirely, it guarantees maximum contrast and eliminates hue-based confusion. Pair it with &lt;strong&gt;High Contrast&lt;/strong&gt; themes in your IDE to restore legibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts: Treat Color Blindness Like Any Debugging Problem
&lt;/h2&gt;

&lt;p&gt;Color blindness isn’t a limitation—it’s a variable to optimize for. Just as you’d configure a keyboard layout or IDE theme to suit your workflow, treat color correction as a tuning exercise. Start small: calibrate, simulate, override, and iterate. Use ICC profiles for systemic fixes, shaders for real-time apps, and CSS for web interfaces. Then validate with real users.&lt;/p&gt;

&lt;p&gt;Remember: The goal isn’t to “see like a non-color-blind person,” but to see clearly, act efficiently, and build inclusive tools. Your adaptations can also benefit people with situational impairments—bright sunlight, low-light glare, or aging eyes—making your workflow more robust for everyone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Can I really fix color blindness with an ICC profile, or is it just simulation?
&lt;/h3&gt;

&lt;p&gt;ICC profiles can’t &lt;em&gt;cure&lt;/em&gt; color blindness—they simulate or compensate by shifting colors. But they can make distinctions clearer by adjusting hue saturation and luminance. Think of it like turning up the contrast in a photo: you’re not changing reality, but you’re making details pop. It’s most effective when combined with calibrated displays and app-level overrides.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which tools are best for simulating color blindness across different operating systems?
&lt;/h3&gt;

&lt;p&gt;On macOS, &lt;strong&gt;Sim Daltonism&lt;/strong&gt; is free and powerful. On Windows and Linux, &lt;strong&gt;Color Oracle&lt;/strong&gt; offers real-time simulation across all apps. For developers, &lt;strong&gt;Coblis&lt;/strong&gt; (online) and &lt;strong&gt;Adobe Photoshop’s Proof Setup&lt;/strong&gt; are great for static previews. Use these tools to audit dashboards, logs, and UIs before shipping.&lt;/p&gt;

&lt;h3&gt;
  
  
  I’m a frontend developer. How can I make my web app more accessible to color-blind users?
&lt;/h3&gt;

&lt;p&gt;Always test with &lt;strong&gt;WCAG contrast ratios&lt;/strong&gt; (minimum 4.5:1 for text). Avoid relying on color alone: use icons, patterns, or labels. For example, don’t use red/green for success/error—use green checkmarks and red Xs. Use tools like &lt;strong&gt;WebAIM Contrast Checker&lt;/strong&gt; and &lt;strong&gt;axe DevTools&lt;/strong&gt; to catch violations early. Consider offering a “colorblind-friendly” theme switcher.&lt;/p&gt;

</description>
      <category>colorblindness</category>
      <category>accessibilitytools</category>
      <category>iccprofiles</category>
      <category>developertools</category>
    </item>
    <item>
      <title>Fixing WebSocket Failures in Production on SiteGround: A Practical Guide</title>
      <dc:creator>Maddy</dc:creator>
      <pubDate>Thu, 07 May 2026 14:24:39 +0000</pubDate>
      <link>https://forem.com/maddy_404_/fixing-websocket-failures-in-production-on-siteground-a-practical-guide-4ik</link>
      <guid>https://forem.com/maddy_404_/fixing-websocket-failures-in-production-on-siteground-a-practical-guide-4ik</guid>
      <description>&lt;h2&gt;
  
  
  Why WebSocket Fails in Production on SiteGround
&lt;/h2&gt;

&lt;p&gt;If your WebSocket connection fails in production on SiteGround, you’re not alone. The error you’re seeing—&lt;code&gt;WebSocket is closed before the connection is established&lt;/code&gt;—typically means the WebSocket handshake is failing, often due to SSL, port, or server configuration issues. SiteGround’s shared hosting environment is not optimized for raw WebSocket traffic by default, but that doesn’t mean it’s impossible. Let’s walk through the root causes and how to fix them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Root Cause #1: Missing SSL Certificates in the Expected Path
&lt;/h3&gt;

&lt;p&gt;Your code assumes that &lt;code&gt;/etc/ssl/privkey.pem&lt;/code&gt; and &lt;code&gt;/etc/ssl/fullchain.pem&lt;/code&gt; exist on SiteGround. In reality, SiteGround Shared and Cloud hosting customers don’t have direct access to &lt;code&gt;/etc/ssl&lt;/code&gt;. Those paths are internal to server management and not exposed to your application. This is why &lt;code&gt;fs.readFileSync()&lt;/code&gt; fails—it can’t find the files.&lt;/p&gt;

&lt;p&gt;Instead, SiteGround uses Let’s Encrypt for SSL certificates, but they’re stored in a managed location that you cannot read directly from your Node.js app. Even if you use SSH to browse the filesystem, you won’t see them in a standard user-accessible path.&lt;/p&gt;

&lt;h3&gt;
  
  
  Root Cause #2: WebSocket Ports Are Blocked by Default
&lt;/h3&gt;

&lt;p&gt;SiteGround blocks most high ports (like 6001, 7001, 8080, etc.) in shared hosting environments to prevent abuse. WebSocket traffic typically runs on non-standard ports, and these are often closed unless explicitly opened via support tickets or custom server configurations.&lt;/p&gt;

&lt;p&gt;When you try to connect to &lt;code&gt;mydomain.com:6001&lt;/code&gt;, the connection is rejected by the firewall before it even reaches your app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Root Cause #3: WebSocket Transport Not Properly Negotiated
&lt;/h3&gt;

&lt;p&gt;Even if the port is open and SSL is configured, the WebSocket upgrade request may fail if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The server is not sending the correct &lt;code&gt;Upgrade: websocket&lt;/code&gt; header.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The client is forcing WebSocket transport, but the server is falling back to polling.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CORS policies block the WebSocket connection.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your client-side code specifies &lt;code&gt;transports: ["websocket"]&lt;/code&gt;, which forces WebSocket. If the server can’t upgrade the connection, the fallback to polling may also fail if CORS isn’t correctly configured.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution: Host WebSocket on Port 443 with HTTPS Forwarding
&lt;/h2&gt;

&lt;p&gt;Since SiteGround blocks non-standard ports and manages SSL certificates centrally, the best workaround is to use port 443 (HTTPS default) for WebSocket traffic. This avoids firewall issues and leverages SiteGround’s managed SSL certificates automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Use HTTPS with Port 443 for WebSocket
&lt;/h3&gt;

&lt;p&gt;Modify your server code to listen on port 443 and route WebSocket traffic through it. Socket.IO supports running over standard HTTPS/443 ports.&lt;/p&gt;

&lt;p&gt;Update your server code:&lt;/p&gt;

&lt;p&gt;import { createServer } from "https";&lt;br&gt;
import { Server } from "socket.io";&lt;br&gt;
import { readFileSync } from "fs";&lt;/p&gt;

&lt;p&gt;// No need to manually load SSL files—SiteGround handles it&lt;br&gt;
const server = createServer({&lt;br&gt;
  // Let SiteGround's internal SSL handler take care of the certificate&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;// Note: We don't pass key/cert directly anymore&lt;br&gt;
// SiteGround uses SNI-based SSL termination at the proxy level&lt;/p&gt;

&lt;p&gt;const io = new Server(server, {&lt;br&gt;
  cors: {&lt;br&gt;
    origin: ["&lt;a href="https://mydomain.com" rel="noopener noreferrer"&gt;https://mydomain.com&lt;/a&gt;", "&lt;a href="https://www.mydomain.com%22" rel="noopener noreferrer"&gt;https://www.mydomain.com"&lt;/a&gt;],&lt;br&gt;
    credentials: true,&lt;br&gt;
  },&lt;br&gt;
  transports: ["websocket"], // Keep forcing websocket for efficiency&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;io.on("connection", (socket) =&amp;gt; {&lt;br&gt;
  console.log("✅ Client connected:", socket.id);&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;// Listen on port 443 (requires root privileges; use port 8443 if on Shared hosting)&lt;br&gt;
const PORT = process.env.NODE_ENV === "production" ? 8443 : 443;&lt;br&gt;
server.listen(PORT, () =&amp;gt; {&lt;br&gt;
  console.log(&lt;code&gt;⚡ Socket.IO server running on port ${PORT}&lt;/code&gt;);&lt;br&gt;
});&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="nx"&gt;Important&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="nx"&gt;On&lt;/span&gt; &lt;span class="nx"&gt;SiteGround&lt;/span&gt; &lt;span class="nx"&gt;Shared&lt;/span&gt; &lt;span class="nx"&gt;hosting&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;you&lt;/span&gt; &lt;span class="nx"&gt;cannot&lt;/span&gt; &lt;span class="nx"&gt;bind&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt; &lt;span class="nx"&gt;directly&lt;/span&gt; &lt;span class="nx"&gt;unless&lt;/span&gt; &lt;span class="nx"&gt;you&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="nx"&gt;re&lt;/span&gt; &lt;span class="nx"&gt;on&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;Cloud&lt;/span&gt; &lt;span class="nx"&gt;or&lt;/span&gt; &lt;span class="nx"&gt;dedicated&lt;/span&gt; &lt;span class="nx"&gt;plan&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="nx"&gt;access&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;For&lt;/span&gt; &lt;span class="nx"&gt;shared&lt;/span&gt; &lt;span class="nx"&gt;hosting&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;use&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="mi"&gt;8443&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="err"&gt;—&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;common&lt;/span&gt; &lt;span class="nx"&gt;alternative&lt;/span&gt; &lt;span class="nx"&gt;that&lt;/span&gt; &lt;span class="nx"&gt;SiteGround&lt;/span&gt; &lt;span class="nx"&gt;allows&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;SSL&lt;/span&gt; &lt;span class="nx"&gt;traffic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nx"&gt;Update&lt;/span&gt; &lt;span class="nx"&gt;your&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt; &lt;span class="nx"&gt;accordingly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;io&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://mydomain.com:8443&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;withCredentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;transports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;websocket&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Update CORS to Use HTTPS Origins
&lt;/h3&gt;

&lt;p&gt;Make sure your CORS configuration includes the correct HTTPS origin. SiteGround enforces HTTPS on all sites via Let’s Encrypt, so the origin must be &lt;code&gt;https://mydomain.com&lt;/code&gt;, not &lt;code&gt;http://&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Change:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;origin: isLocal ? ["http://localhost:5173"] : ["mydomain.com"]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;origin: isLocal ? ["http://localhost:5173"] : ["https://mydomain.com", "https://www.mydomain.com"]&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Ensure Your DNS Points to SiteGround Correctly
&lt;/h3&gt;

&lt;p&gt;Confirm that your domain’s A records point to SiteGround’s server IP (found in SiteGround’s Customer Area &amp;gt; Site &amp;gt; Site Information). Misconfigured DNS can cause SSL handshake failures even with correct WebSocket setup.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Handle Reverse Proxy Properly
&lt;/h3&gt;

&lt;p&gt;SiteGround runs behind a reverse proxy (Nginx or Apache). To allow WebSocket traffic through, you may need to configure a custom Nginx rule. Since you don’t control the web server directly on shared hosting, file a support ticket with SiteGround:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Request:&lt;/strong&gt; "Enable WebSocket support for port 8443 with upgrade headers."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Include:&lt;/strong&gt; Your domain and application purpose.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; SiteGround support can add a custom Nginx snippet like:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;location /socket.io/ {&lt;br&gt;
  proxy_pass http://localhost:8443;&lt;br&gt;
  proxy_http_version 1.1;&lt;br&gt;
  proxy_set_header Upgrade $http_upgrade;&lt;br&gt;
  proxy_set_header Connection "upgrade";&lt;br&gt;
  proxy_set_header Host $host;&lt;br&gt;
  proxy_set_header X-Real-IP $remote_addr;&lt;br&gt;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&lt;br&gt;
  proxy_set_header X-Forwarded-Proto $scheme;&lt;br&gt;
}&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This ensures WebSocket upgrade headers are passed correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing and Debugging Tips
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Test Locally First
&lt;/h3&gt;

&lt;p&gt;Run your server locally with &lt;code&gt;NODE_ENV=production&lt;/code&gt; to catch syntax errors or missing dependencies:&lt;/p&gt;

&lt;h1&gt;
  
  
  Local HTTPS test
&lt;/h1&gt;

&lt;p&gt;openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes&lt;br&gt;
node server.js&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


Then connect from your client (e.g., `https://localhost:443`) to verify the WebSocket path works.

### Use Browser DevTools

Open Developer Tools &amp;gt; Network tab and check the `Socket.IO` connection. Look for:

- Status code: Should be `101 Switching Protocols` after upgrade.

- Headers: Ensure `Upgrade: websocket` and `Connection: Upgrade` are present.

- WebSocket URL: Should be `wss://mydomain.com:8443/socket.io/?EIO=4&amp;amp;transport=websocket`

### Check Firewall Logs (via Support)

Ask SiteGround support to check if port 8443 is open and if any outgoing WebSocket traffic is being blocked. On shared hosting, you rely entirely on their configuration.

## Alternative: Use a Reverse Proxy with Standard Ports

If port 8443 is still problematic, consider using SiteGround’s Apache server to proxy WebSocket traffic internally. Use a standard path like `/ws` that maps to your Node.js app on another port (e.g., 3000).

Example Apache config (SiteGround can add this):

`&amp;amp;lt;Location /ws&amp;amp;gt;
  ProxyPass http://localhost:3000/socket.io/
  ProxyPassReverse http://localhost:3000/socket.io/
  RewriteEngine on
  RewriteCond %{HTTP:Upgrade} websocket [NC]
  RewriteCond %{HTTP:Connection} upgrade [NC]
  RewriteRule ^/?(.*) "ws://localhost:3000/socket.io/$1" [P,L]
&amp;amp;lt;/Location&amp;amp;gt;
`

Then connect your client to:

`const socket = io("https://mydomain.com/ws", {
  transports: ["websocket"],
});
`

This leverages standard HTTPS and avoids port restrictions entirely.

## Final Checklist

-  WebSocket server runs on port 8443 (or via reverse proxy).

-  CORS origin uses `https://`, not `http://`.

-  DNS is correct and SSL is active (check via `https://sslshopper.com`).

-  SiteGround support confirmed WebSocket support and Nginx proxy rules.

-  Client connects to `wss://mydomain.com:8443` (not `ws://`).

## FAQ

  ### Can I use WebSocket on SiteGround Shared Hosting?



      Yes, but with limitations. You cannot bind directly to port 443 without root access, and non-standard ports like 6001 are blocked by default. The recommended approach is to use port 8443 with SSL and request WebSocket support via SiteGround support. Alternatively, proxy WebSocket traffic through Apache/Nginx on standard paths like `/ws`.




  ### Why does my WebSocket connection fail with `Error during WebSocket handshake`?



      This usually means the server did not return a `101 Switching Protocols` response. On SiteGround, this happens when:



        - The port is blocked by firewall.

        - The reverse proxy (Nginx/Apache) lacks `Upgrade` header handling.

        - SSL is misconfigured or missing.



      Fix by using port 8443 with support-approved Nginx rules and HTTPS origins.




  ### Do I need to manually manage SSL certificates on SiteGround?



      No. SiteGround automatically provisions and renews Let’s Encrypt certificates for your domain. You should never manually read `privkey.pem` or `fullchain.pem` in your app. Instead, configure your HTTPS server to use the managed certificate via SiteGround’s internal proxy, and bind to port 8443.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>websocket</category>
      <category>siteground</category>
      <category>production</category>
      <category>node</category>
    </item>
  </channel>
</rss>
