Self-Host a Chrome Extension: Complete Distribution Guide for Linux (2026)

AppBooster Team · · 4 min read
Server rack for self-hosted distribution

Self-Hosting Chrome Extensions

Linux is the only platform that allows installing Chrome extensions from outside the Chrome Web Store. This makes self-hosting relevant for enterprise deployments, internal tools, development testing, and Linux-focused distributions.


Packaging Your Extension as CRX

Method 1: Download from Chrome Web Store

If your extension is already published:

  1. Go to the Chrome Developer Dashboard
  2. Find your extension under Your Listings
  3. Click More info → Download the main.crx file

This is the most secure method — the CRX is signed by the Chrome Web Store.

Method 2: Pack via Chrome UI

  1. Navigate to chrome://extensions/
  2. Enable Developer Mode
  3. Click Pack extension
  4. Select your extension’s root folder
  5. Chrome generates extension.crx and extension.pem

Critical: Save the .pem private key securely. You need it for every future update to maintain signing consistency.

Method 3: Command Line

# First time (generates .pem)
chrome --pack-extension=/path/to/extension

# Subsequent updates (use existing .pem)
chrome --pack-extension=/path/to/extension --pack-extension-key=/path/to/extension.pem

Hosting the CRX File

Server Requirements

Your web server must serve .crx files with the correct Content-Type header:

Content-Type: application/x-chrome-extension

Nginx Configuration

location ~ \.crx$ {
    types { }
    default_type application/x-chrome-extension;
    add_header Cache-Control "no-cache";
}

location ~ \.xml$ {
    types { }
    default_type application/xml;
}

Apache Configuration

AddType application/x-chrome-extension .crx

Alternative: Without Content-Type

Chrome also recognizes .crx files when served with these content types (without X-Content-Type-Options: nosniff):

  • text/plain
  • application/octet-stream
  • application/unknown
  • Empty content type

Auto-Update Configuration

Step 1: Add update_url to Manifest

{
  "manifest_version": 3,
  "name": "Internal Tool",
  "version": "2.0.0",
  "update_url": "https://your-server.com/extensions/updates.xml"
}

Step 2: Create Update Manifest XML

<?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
  <app appid='your-32-character-extension-id-here'>
    <updatecheck
      codebase='https://your-server.com/extensions/my-extension-v2.crx'
      version='2.0.0' />
  </app>
</gupdate>

Multiple Extensions in One Update Manifest

<?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
  <app appid='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'>
    <updatecheck
      codebase='https://your-server.com/ext/tool-a-v3.crx'
      version='3.0.0' />
  </app>
  <app appid='bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'>
    <updatecheck
      codebase='https://your-server.com/ext/tool-b-v1.crx'
      version='1.2.0' />
  </app>
</gupdate>

Update Behavior

SettingDetail
Check frequencyEvery few hours (automatic)
Manual triggerExtensions page → Update extensions now
Cookie handlingNo cookies sent or accepted
Version comparisonOnly updates if server version > installed

Minimum Browser Version

Restrict updates to specific Chrome versions:

<updatecheck
  codebase='https://your-server.com/ext/my-ext-v3.crx'
  version='3.0.0'
  prodversionmin='120.0.0.0' />

Dynamic Update Server

Build a server that responds to Chrome’s update requests:

// Express.js example
app.get('/extensions/updates.xml', (req, res) => {
  // Chrome sends: ?x=id%3DEXTENSION_ID%26v%3DCURRENT_VERSION
  const params = new URLSearchParams(req.query.x);
  const extensionId = params.get('id');
  const currentVersion = params.get('v');

  const latestVersion = getLatestVersion(extensionId);

  res.type('application/xml');
  res.send(`<?xml version='1.0' encoding='UTF-8'?>
    <gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
      <app appid='${extensionId}'>
        <updatecheck
          codebase='https://your-server.com/ext/${extensionId}-v${latestVersion}.crx'
          version='${latestVersion}' />
      </app>
    </gupdate>`);
});

Version Management Workflow

  1. Increment version in manifest.json
  2. Re-pack with the same .pem key
  3. Upload new .crx to your server
  4. Update the XML manifest with the new version and codebase URL
  5. Chrome clients pick up the update within a few hours

Platform Restrictions

PlatformSelf-hosted Extensions
LinuxFull support
WindowsChrome Web Store only (since Chrome 33)
macOSChrome Web Store only (since Chrome 44)
ChromeOSChrome Web Store only

What’s Next

Self-hosting gives you full control over distribution and updates for Linux environments. Keep your .pem key secure, automate your update pipeline, and always increment versions before re-packaging.

For extensions distributed via the Chrome Web Store, ExtensionBooster provides tools to optimize your listing and grow your user base.

Share this article

Build better extensions with free tools

Icon generator, MV3 converter, review exporter, and more — no signup needed.

Related Articles