Setting Up an NPM Private Registry: Docker Deployment, Data Migration, and OSS Disaster Recovery
This article provides a step‑by‑step guide to building an NPM private registry using Cnpmjs.org, covering containerized deployment with Docker, migrating packages from Verdaccio, implementing OSS disaster‑recovery backups, configuring email notifications, and tips for further customization.
The article begins with a brief overview of popular open‑source NPM private‑registry frameworks such as Verdaccio, Cnpmjs.org, and Nexus, highlighting their main features and typical use cases.
It then focuses on containerized deployment of Cnpmjs.org. The team uses an internal Ipaas platform and provides a Dockerfile and a docker-compose.yml to run the registry as two services (web and register). The Dockerfile defines the base Node image, environment variables, working directory, copy steps, exposed ports (7001 for the registry, 7002 for the web UI), volume for data persistence, and the final CMD ["npm", "run", "prod"] command.
FROM node:12
MAINTAINER zian [email protected]
# Working enviroment
ENV \
CNPM_DIR="/var/app/cnpmjs.org" \
CNPM_DATA_DIR="/var/data/cnpm_data"
# Shell format
RUN mkdir -p ${CNPM_DIR}
WORKDIR ${CNPM_DIR}
COPY package.json ${CNPM_DIR}
RUN npm set registry https://registry.npm.taobao.org
RUN npm install --production
COPY . ${CNPM_DIR}
COPY docs/dockerize/config.js ${CNPM_DIR}/config/
# Declare ports
EXPOSE 7001/tcp 7002/tcp
# Anonymous volume
VOLUME ["/var/data/cnpm_data"]
RUN chmod +x ${CNPM_DIR}/docker-entrypoint_prod.sh
CMD ["npm", "run", "prod"]After building the image, the article advises running docker-compose up -d , then accessing the web UI at http://127.0.0.1:7002 and configuring the npm client to use the private registry with npm config set registry http://127.0.0.1:7001 (or using nrm for easy switching).
The next section describes migrating existing packages from a Verdaccio instance to Cnpmjs.org. Because Verdaccio does not store package metadata in a database, the migration script reads the package JSON from Verdaccio’s API, extracts the tarball, decodes it from Base64, and saves the module information into Cnpmjs.org’s database. Core migration code snippets show how to obtain the package metadata, upload the tarball via fs‑cnpm or oss‑cnpm , and persist the module record.
var pkg = this.request.body; // package.json after libnpmpublish processing
var username = this.user.name;
var name = this.params.name || this.params[0];
var filename = Object.keys(pkg._attachments || {})[0];
var version = Object.keys(pkg.versions || {})[0];
// Upload attachment
var tarballBuffer = Buffer.from(attachment.data, 'base64');
var uploadResult = yield nfs.uploadBuffer(tarballBuffer, options);
var dist = { shasum: shasum, size: attachment.length };
if (uploadResult.url) { dist.tarball = uploadResult.url; }
else if (uploadResult.key) { dist.key = uploadResult.key; dist.tarball = uploadResult.key; }
var mod = { name: name, version: version, author: username, package: pkg.versions[version] };
mod.package.dist = dist;
var addResult = yield packageService.saveModule(mod);To automate the migration, a new controller save_zcy.js is added to the registry routes, and a periodic task runs npm install [name] for each package, triggering the custom save logic.
For disaster‑recovery, the article proposes uploading every published tarball both to local storage and to an OSS bucket. The fs‑cnpm and oss‑cnpm plugins handle the dual write. During installation, the system first checks whether the package is scoped; if it is a private package, it looks for the file locally, otherwise it falls back to the OSS bucket, downloads it to the NFS directory, and streams it to the client.
const ensureFileExists = function(filepath) {
return function(callback) {
fs.access(filepath, fs.constants.F_OK, callback);
};
};
const ensureDirExists = function(filepath) {
return function(callback) {
mkdirp(path.dirname(filepath), callback);
};
};Email notifications are configured so that maintainers receive alerts when a new version is published. The configuration uses Nodemailer with an Aliyun SMTP service, and the maintainers list is stored in the package’s maintainers field.
mail: {
enable: true,
appname: 'cnpmjs.org',
from: process.env.EMAIL_HOST,
host: 'smtp.mxhichina.com',
service: 'qiye.aliyun',
port: 465,
secureConnection: true,
auth: {
user: process.env.EMAIL_HOST,
pass: process.env.EMAIL_PSD
}
}Finally, the article mentions future customizations such as integrating internal permission systems, redesigning the web UI, and linking business component documentation, encouraging readers to adopt the solution for their own private NPM registries.
政采云技术
ZCY Technology Team (Zero), based in Hangzhou, is a growth-oriented team passionate about technology and craftsmanship. With around 500 members, we are building comprehensive engineering, project management, and talent development systems. We are committed to innovation and creating a cloud service ecosystem for government and enterprise procurement. We look forward to your joining us.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.