{"id":2138,"date":"2025-10-16T08:29:06","date_gmt":"2025-10-16T08:29:06","guid":{"rendered":"https:\/\/www.cmsgalaxy.com\/blog\/?p=2138"},"modified":"2025-10-16T08:29:07","modified_gmt":"2025-10-16T08:29:07","slug":"how-to-install-excalidraw-in-linux","status":"publish","type":"post","link":"https:\/\/www.cmsgalaxy.com\/blog\/how-to-install-excalidraw-in-linux\/","title":{"rendered":"How to install Excalidraw in Linux?"},"content":{"rendered":"\n<p>let\u2019s deploy a <strong>static Excalidraw embed<\/strong> under your cPanel hosting at:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Filesystem: \/home\/toolsdevopsschoo\/public_html\/excalidraw\nURL:       https:\/\/tools.devopsschool.com\/excalidraw\/\n<\/code><\/pre>\n\n\n\n<p>This method needs no Node.js server running on cPanel (just static files). You\u2019ll build locally on the server via SSH and copy the build output into <code>public_html\/excalidraw<\/code>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Step-by-Step (SSH)<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">0) Prereqs (one time)<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code># Log in over SSH, then check Node &amp; npm\nnode -v\nnpm -v\n<\/code><\/pre>\n\n\n\n<p>If Node is missing or &lt; 18, install with nvm:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Install nvm (if not present)\ncurl -o- https:\/\/raw.githubusercontent.com\/nvm-sh\/nvm\/v0.39.7\/install.sh | bash\nsource ~\/.bashrc  # or: source ~\/.zshrc\n\n# Install and use an LTS Node\nnvm install --lts\nnvm use --lts\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">1) Create a fresh React app (outside public_html)<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>cd ~\nnpm create vite@latest excali-static -- --template react\ncd excali-static\nnpm install\nnpm install @excalidraw\/excalidraw\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">2) Wire Excalidraw into the app<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">2.1 Replace <code>src\/App.jsx<\/code><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \/home\/toolsdevopsschoo\/excali-static\/src\/App.jsx\nimport { useEffect, useRef } from \"react\";\nimport { Excalidraw } from \"@excalidraw\/excalidraw\";\n\nexport default function App() {\n  const wrap = useRef(null);\n\n  useEffect(() =&gt; {\n    document.body.style.margin = \"0\";\n    if (wrap.current) wrap.current.style.height = \"100vh\";\n  }, &#91;]);\n\n  return (\n    &lt;div ref={wrap}&gt;\n      &lt;Excalidraw \/&gt;\n    &lt;\/div&gt;\n  );\n}\n<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>(Keep the default <code>src\/main.jsx<\/code> from Vite; no change needed.)<\/p>\n<\/blockquote>\n\n\n\n<h3 class=\"wp-block-heading\">2.2 Set Vite base path so assets load from <code>\/excalidraw\/<\/code><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \/home\/toolsdevopsschoo\/excali-static\/vite.config.js\nimport { defineConfig } from \"vite\";\nimport react from \"@vitejs\/plugin-react\";\n\nexport default defineConfig({\n  plugins: &#91;react()],\n  base: \"\/excalidraw\/\",   \/\/ IMPORTANT: site is served from \/excalidraw\/\n});\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">3) Build for production<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>cd ~\/excali-static\nnpm run build\n# Output appears in: ~\/excali-static\/dist\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">4) Deploy to your web root<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code># Make\/clean the target folder under public_html\nmkdir -p \/home\/toolsdevopsschoo\/public_html\/excalidraw\nrm -rf \/home\/toolsdevopsschoo\/public_html\/excalidraw\/*\n\n# Copy the built files\ncp -r ~\/excali-static\/dist\/* \/home\/toolsdevopsschoo\/public_html\/excalidraw\/\n<\/code><\/pre>\n\n\n\n<p>Open: <strong><a href=\"https:\/\/tools.devopsschool.com\/excalidraw\/\">https:\/\/tools.devopsschool.com\/excalidraw\/<\/a><\/strong> \ud83c\udf89<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">5) (If you see missing icons\/images) add <code>excalidraw-assets<\/code><\/h2>\n\n\n\n<p>Newer versions usually handle assets automatically. If your browser console shows 404s for <code>excalidraw-assets<\/code>, do this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mkdir -p \/home\/toolsdevopsschoo\/public_html\/excalidraw\/excalidraw-assets\ncp -r ~\/excali-static\/node_modules\/@excalidraw\/excalidraw\/dist\/excalidraw-assets\/* \\\n      \/home\/toolsdevopsschoo\/public_html\/excalidraw\/excalidraw-assets\/\n<\/code><\/pre>\n\n\n\n<p>Reload the page.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">6) Optional: add caching + security headers<\/h2>\n\n\n\n<p>Create <strong>\/home\/toolsdevopsschoo\/public_html\/excalidraw\/.htaccess<\/strong>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Caching (safe defaults)\n&lt;IfModule mod_expires.c&gt;\n  ExpiresActive On\n  ExpiresByType text\/javascript \"access plus 7 days\"\n  ExpiresByType text\/css \"access plus 7 days\"\n  ExpiresByType image\/png \"access plus 30 days\"\n  ExpiresByType image\/svg+xml \"access plus 30 days\"\n&lt;\/IfModule&gt;\n\n# Security headers\n&lt;IfModule mod_headers.c&gt;\n  Header set X-Content-Type-Options \"nosniff\"\n  Header set Referrer-Policy \"no-referrer-when-downgrade\"\n  Header set X-Frame-Options \"SAMEORIGIN\"\n&lt;\/IfModule&gt;\n<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>If your host uses aggressive caching, remember to re-upload after each new build.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">7) Update flow (next time you change something)<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>cd ~\/excali-static\nnpm run build\nrm -rf \/home\/toolsdevopsschoo\/public_html\/excalidraw\/*\ncp -r dist\/* \/home\/toolsdevopsschoo\/public_html\/excalidraw\/\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Notes &amp; Tips<\/h1>\n\n\n\n<ul class=\"wp-block-list\">\n<li>This approach is <strong>static<\/strong> (no collaboration server). It\u2019s perfect for shared cPanel hosting.<\/li>\n\n\n\n<li>If you <strong>must<\/strong> run the full Excalidraw app from the official repo (Next.js), your cPanel plan must support <strong>Node.js\/Passenger<\/strong> apps. If you have that, say the word and I\u2019ll give you those steps too.<\/li>\n\n\n\n<li>Always set <code>base: \"\/excalidraw\/\"<\/code> in <code>vite.config.js<\/code> since the site is served from a subpath.<\/li>\n<\/ul>\n\n\n\n<p>If you want, I can also add toolbar theming (light\/dark), export buttons, or a save-to-JSON flow in this static build\u2014just say the word and I\u2019ll extend <code>App.jsx<\/code>.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>let\u2019s deploy a static Excalidraw embed under your cPanel hosting at: This method needs no Node.js server running on cPanel<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-2138","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.cmsgalaxy.com\/blog\/wp-json\/wp\/v2\/posts\/2138","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cmsgalaxy.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cmsgalaxy.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cmsgalaxy.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cmsgalaxy.com\/blog\/wp-json\/wp\/v2\/comments?post=2138"}],"version-history":[{"count":1,"href":"https:\/\/www.cmsgalaxy.com\/blog\/wp-json\/wp\/v2\/posts\/2138\/revisions"}],"predecessor-version":[{"id":2139,"href":"https:\/\/www.cmsgalaxy.com\/blog\/wp-json\/wp\/v2\/posts\/2138\/revisions\/2139"}],"wp:attachment":[{"href":"https:\/\/www.cmsgalaxy.com\/blog\/wp-json\/wp\/v2\/media?parent=2138"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cmsgalaxy.com\/blog\/wp-json\/wp\/v2\/categories?post=2138"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cmsgalaxy.com\/blog\/wp-json\/wp\/v2\/tags?post=2138"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}