Chrome extensions power productivity across organizations, but distributing them securely within an enterprise requires more than the public Chrome Web Store. A self-hosted extension store gives IT administrators complete control over which extensions are available, when they’re updated, and who can access them.
This guide walks through setting up a private Chrome extension repository for enterprise environments. You’ll learn the technical requirements, configuration steps, and practical considerations for managing internal extensions at scale.
Why Self-Hosted Extension Stores Matter
Enterprise environments often operate under strict security policies. Many organizations restrict internet access, require air-gapped networks, or need compliance with specific data handling regulations. The public Chrome Web Store becomes inaccessible in these scenarios.
A self-hosted extension store solves this by hosting extension CRX files on infrastructure you control. Your IT team approves extensions, hosts the packages internally, and configures Chrome to pull from your private repository instead of Google’s servers.
Beyond network restrictions, self-hosted stores provide:
- Version control: Deploy specific extension versions across your organization
- Security vetting: Review extensions before making them available company-wide
- Audit trails: Track which users have installed which extensions
- Offline support: Serve extensions without internet connectivity
Setting Up Your Extension Repository
A self-hosted Chrome extension store is fundamentally a web server serving CRX files with proper headers. You don’t need specialized software—a basic web server handles the job.
Directory Structure
Organize your extension repository with a clear structure:
/var/www/extensions/
├── manifest.json
├── internal-tool-1.2.0.crx
├── internal-tool-1.2.1.crx
├── company-password-manager.crx
└── custom-integration-0.5.0.crx
The manifest.json file lists available extensions in a format Chrome understands.
manifest.json Structure
Create a manifest that describes your extension catalog:
{
"name": "Company Extension Repository",
"version": "1.0",
"extensions": [
{
"name": "Internal Tool",
"version": "1.2.1",
"description": "Company internal utilities",
"id": "gjflkafdjjglhfjpgbognhfcnakkgbhe",
"package": "internal-tool-1.2.1.crx",
"icons": {
"128": "icons/icon-128.png"
}
},
{
"name": "Custom Integration",
"version": "0.5.0",
"description": "CRM integration module",
"id": "abcdefghijklmnopqrstuvwxyz123456",
"package": "custom-integration-0.5.0.crx"
}
]
}
The extension ID is critical. Chrome uses the ID to track installations and updates. Generate IDs using the official extension packaging process in Chrome.
Required Server Configuration
Your web server must serve CRX files with specific CORS headers. Without these headers, Chrome blocks the installation.
For Nginx, add these headers to your server block:
location ~* \.crx$ {
add_header Access-Control-Allow-Origin *;
add_header X-Content-Type-Options nosniff;
add_header Content-Type application/x-chrome-extension;
}
For Apache, use mod_headers in your .htaccess or server configuration:
<FilesMatch "\.crx$">
Header set Access-Control-Allow-Origin "*"
Header set X-Content-Type-Options "nosniff"
Header set Content-Type "application/x-chrome-extension"
</FilesMatch>
Configuring Chrome to Use Your Store
Chrome Enterprise policies control which extension sources Chrome uses. Configure these through Group Policy on Windows, configuration profile on macOS, or JSON policies on Linux.
Windows Group Policy
Deploy this policy through Group Policy Management:
- Policy path: Computer Configuration → Administrative Templates → Google Chrome → Extensions
- Setting: “Extension install sources”
- Value: Add your internal repository URL
The policy accepts patterns like https://extensions.company.internal/* or https://cdn.company.com/*.
JSON Configuration (Linux/Chromium OS)
Create a JSON policy file at /etc/opt/chrome/policies/managed/extensions.json:
{
"ExtensionInstallSources": [
"https://extensions.company.internal/*",
"https://cdn.company.com/*"
],
"ExtensionInstallForcelist": [
"gjflkafdjjglhfjpgbognhfcnakkgbhe;https://extensions.company.internal/internal-tool-1.2.1.crx",
"abcdefghijklmnopqrstuvwxyz123456;https://extensions.company.internal/custom-integration-0.5.0.crx"
]
}
The ExtensionInstallForcelist policy forces specific extensions onto managed devices without user interaction—useful for security tools that must be present on all machines.
Managing Updates
Self-hosted extensions require manual update management. Chrome checks for updates based on the update_url in the extension manifest. For internally hosted extensions, point this to your manifest.json.
In your extension’s manifest.json:
{
"update_url": "https://extensions.company.internal/manifest.json"
}
When you upload a new version to your repository, update the version number in your repository manifest. Chrome detects the new version on its next check cycle and prompts users to update.
Automate this process with a simple script that increments version numbers and regenerates your repository manifest:
#!/bin/bash
EXTENSION_DIR="/var/www/extensions"
NEW_VERSION="1.2.2"
cd "$EXTENSION_DIR"
zip -r "internal-tool-${NEW_VERSION}.crx" internal-tool/
mv "internal-tool-${NEW_VERSION}.crx" internal-tool-latest.crx
# Regenerate manifest with new version
python3 << EOF
import json
manifest = json.load(open('manifest.json'))
for ext in manifest['extensions']:
if ext['name'] == 'Internal Tool':
ext['version'] = '${NEW_VERSION}'
ext['package'] = 'internal-tool-${NEW_VERSION}.crx'
json.dump(manifest, open('manifest.json', 'w'), indent=2)
EOF
Security Considerations
Host your extension repository over HTTPS. Chrome blocks extensions loaded over insecure HTTP connections in modern versions.
Restrict access to your extension server using network ACLs or authentication. Only devices on your corporate network or VPN should reach the extension endpoints.
For highly sensitive environments, implement signed CRX files. Chrome validates signatures during installation, ensuring packages haven’t been tampered with during hosting.
Common Pitfalls
Extension IDs change when you repackage an extension. If you generate a new CRX file without preserving the original private key, Chrome treats it as a different extension. Keep your private keys secure and reuse them across versions.
Caching breaks update detection. Ensure your web server doesn’t cache manifest.json or CRX files with long TTLs. Configure appropriate cache headers:
location /extensions/ {
expires -1;
add_header Cache-Control "no-store, no-cache, must-revalidate";
}
Testing in incognito mode reveals permission issues. Extensions that work in regular mode sometimes fail in incognito due to additional restrictions. Test both modes before deploying organization-wide.
Wrap-Up
A self-hosted Chrome extension store provides the control enterprises need for secure extension distribution. The setup requires basic web hosting, proper CORS configuration, and Chrome Enterprise policies for deployment.
Start small—host a single internal tool and expand as your organization gains confidence with the infrastructure. The investment pays off in security, compliance, and operational control.
Related Reading
- Claude Code for Beginners: Complete Getting Started Guide
- Best Claude Skills for Developers in 2026
- Claude Skills Guides Hub
Built by theluckystrike — More at zovo.one