.npmrc × Azure Artifacts
คู่มือ npm / ภาษาไทย

สร้าง .npmrc เพื่อดึงแพ็กเกจจาก Azure Artifacts npm private feed

คู่มือทีละขั้น: แยกไฟล์ตั้งค่า (commit ได้) ออกจากไฟล์ credential (ห้าม commit) ตั้งค่าบนเครื่อง, CI แล้วตรวจว่าใช้ได้จริง พร้อมตารางแก้ error ที่เจอบ่อย

เฉพาะการ install (pull)ใช้ placeholder ทั้งหมดอ้างอิง Microsoft Learn
สารบัญ
  1. ภาพรวม
  2. สิ่งที่ต้องมี
  3. รูปแบบ URL ของ feed
  4. .npmrc ของโปรเจกต์
  5. Credentials
  6. CI
  7. ตรวจสอบ
  8. แก้ปัญหา
  9. Security checklist

กรอกค่าของคุณ (ไม่บังคับ)

ค่าที่กรอกจะแทนที่ <ORG> <PROJECT> <FEED> @myscope ในทุก code block ทำงานในเบราว์เซอร์เครื่องคุณเท่านั้น ไม่ส่งไปไหนและไม่บันทึก ห้ามกรอก PAT ที่นี่ — ช่องนี้ไม่ได้ออกแบบมารับ secret

1ภาพรวม: ไฟล์ไหนทำอะไร

Azure Artifacts ใช้ไฟล์ .npmrc เพื่อให้ npm client รู้ว่า "ไปดึงแพ็กเกจที่ไหน" และ "พิสูจน์ตัวตนอย่างไร" Microsoft แนะนำให้แยกเป็น สองไฟล์: ไฟล์ระดับโปรเจกต์เก็บ URL ของ feed (commit ลง git ได้) ส่วนไฟล์ระดับผู้ใช้ ~/.npmrc เก็บ credential (ห้าม commit)

เครื่องนักพัฒนา ./.npmrc registry= (URL ของ feed) commit ลง git ได้ ~/.npmrc username / _password / email ห้าม commit npm install (HTTPS + auth) Azure Artifacts npm feed (private) pkgs.dev.azure.com upstream (ถ้าเปิดไว้) npmjs.com แผนภาพการไหลของ npm install เครื่องนักพัฒนาอ่าน .npmrc ของโปรเจกต์และ ~/.npmrc แล้วเรียก Azure Artifacts feed ซึ่งดึงแพ็กเกจที่ไม่มีจาก upstream npmjs.com เครื่องนักพัฒนา ./.npmrc registry= (URL ของ feed) commit ลง git ได้ ~/.npmrc username / _password / email ห้าม commit npm install HTTPS + auth Azure Artifacts npm feed (private) pkgs.dev.azure.com เก็บสำเนาแพ็กเกจ upstream npmjs.com (ถ้าเปิด upstream ไว้)
ลูกศรประ = ใช้เมื่อ feed เปิด upstream sources ไว้ และแพ็กเกจนั้นยังไม่เคยถูกบันทึกลง feed

2สิ่งที่ต้องมีก่อนเริ่ม

  • Node.js + npm เวอร์ชัน LTS ที่ยังได้รับ support (Microsoft Learn ไม่ได้ระบุเวอร์ชันขั้นต่ำ) ตรวจด้วย node -v และ npm -v
  • Azure DevOps organization, project และ feed ที่สร้างไว้แล้ว (Artifacts > Create Feed)
  • สิทธิ์บน feed อย่างน้อย Feed Reader สำหรับอ่านแพ็กเกจที่อยู่ใน feed แล้ว หากต้องการติดตั้งแพ็กเกจจาก upstream (เช่น npmjs.com) เป็นครั้งแรก ต้องเป็น Feed and Upstream Reader (Collaborator) ขึ้นไป เพราะการติดตั้งครั้งแรกจะบันทึกสำเนาลง feed
  • Personal Access Token (PAT) ที่มี scope Packaging (Read) สำหรับดึงแพ็กเกจที่อยู่ใน feed แล้ว (ถ้าต้องดึงจาก upstream ครั้งแรก ใช้ Read & write ดูหมายเหตุด้านล่าง)
หมายเหตุเรื่อง scope Packaging (Read) พอเฉพาะแพ็กเกจที่ถูกบันทึกลง feed แล้ว ถ้า feed ใช้ upstream และต้องดึงแพ็กเกจที่ยังไม่เคยถูกบันทึก ให้ใช้ Packaging (Read & write) ตามที่ Microsoft แนะนำ (ร่วมกับบทบาท Collaborator)

ภาพจำลอง: หน้าต่างสร้าง PAT

ชื่อปุ่มและเมนูจริงอาจต่างจากภาพนี้ตามเวอร์ชันของ Azure DevOps PAT จะแสดงให้เห็น ครั้งเดียว หลังกด Create ให้คัดลอกเก็บในที่ปลอดภัยทันที

3รูปแบบ URL ของ feed

ตอนสร้าง feed คุณเลือก Scope ว่าเป็น project-scoped หรือ organization-scoped รูปแบบ URL ต่างกัน:

ชนิด feedRegistry URL
Organization-scopedhttps://pkgs.dev.azure.com/<ORG>/_packaging/<FEED>/npm/registry/
Project-scopedhttps://pkgs.dev.azure.com/<ORG>/<PROJECT>/_packaging/<FEED>/npm/registry/
วิธีดู URL ที่ถูกต้องAzure DevOps > Artifacts > เลือก feed > Connect to feed > npm หน้านี้แสดง snippet "Project setup" ที่ตรงกับ feed ของคุณ ให้ใช้ค่าจากที่นั่นเป็นหลัก

ลงท้าย / เสมอ และต้องลงท้าย /npm/registry/ สำหรับบรรทัด registry=

4.npmrc ของโปรเจกต์ (commit ลง git)

สร้างไฟล์ .npmrc ไว้ในโฟลเดอร์เดียวกับ package.json ไฟล์นี้มี URL เท่านั้น ไม่มี credential

A

แบบ registry= (ทุกแพ็กเกจผ่าน feed)

.npmrc (organization-scoped)
registry=https://pkgs.dev.azure.com/<ORG>/_packaging/<FEED>/npm/registry/
.npmrc (project-scoped)
registry=https://pkgs.dev.azure.com/<ORG>/<PROJECT>/_packaging/<FEED>/npm/registry/
B

แบบ scoped: @myscope:registry=

.npmrc (project-scoped)
@myscope:registry=https://pkgs.dev.azure.com/<ORG>/<PROJECT>/_packaging/<FEED>/npm/registry/

แพ็กเกจต้องมีชื่อแบบ @myscope/package-name (ตั้งใน package.json ของแพ็กเกจนั้น) npm จะส่งเฉพาะชื่อที่ขึ้นต้น @myscope/ ไปที่ feed ส่วนที่เหลือไป registry เดิม

ควรเลือกแบบไหน

registry= (ทั้งหมดผ่าน feed)

เหมาะเมื่อ: feed เปิด upstream npmjs.com ไว้ และต้องการให้ทุกแพ็กเกจผ่านจุดเดียว ได้ cache, ตรวจสอบ และ audit รวมศูนย์ ข้อควรระวัง: ทุก install ต้องมี credential และถ้า upstream ปิดอยู่ แพ็กเกจสาธารณะจะหาไม่เจอ (E404)

@myscope:registry= (เฉพาะ scope)

เหมาะเมื่อ: แพ็กเกจภายในองค์กรใช้ scope ชัดเจน และ feed ไม่ได้เปิด upstream หรือไม่อยากให้แพ็กเกจสาธารณะผ่าน feed Microsoft ระบุว่ามีประโยชน์ในระบบ on-premises ที่ไม่มีอินเทอร์เน็ต ข้อดี: ลดการสับสนชื่อซ้ำ (name collision)

5Credentials (ไฟล์ระดับผู้ใช้)

ไฟล์ 1: .npmrc ในโปรเจกต์ registry=https://pkgs.dev… + อยู่ใน git, ทั้งทีมใช้ร่วมกัน + ไม่มีความลับ npm ไฟล์ 2: ~/.npmrc ของแต่ละคน :_password=<BASE64_PAT> - อยู่นอก repo, chmod 600 - ห้าม commit / ห้ามแชร์ การแยกสองไฟล์ .npmrc ไฟล์โปรเจกต์ที่อยู่ใน git เก็บ URL ส่วนไฟล์ในโฮมของผู้ใช้เก็บ PAT และ npm รวมสองไฟล์ตอนรัน ไฟล์ 1: .npmrc ในโปรเจกต์ registry=https://pkgs.dev… + อยู่ใน git repo + ทั้งทีมใช้ร่วมกัน + ไม่มีความลับ ไฟล์ 2: ~/.npmrc ของแต่ละคน //pkgs…:_password=<BASE64_PAT> - อยู่นอก repo เสมอ - chmod 600 (macOS/Linux) - ห้าม commit / ห้ามแชร์ npm npm อ่านทั้งสองไฟล์แล้วรวมค่า (ค่าใน project ชนะ user เมื่อชื่อซ้ำ)

5a. Windows: vsts-npm-auth

บน Windows ใช้ tool vsts-npm-auth ที่สร้างและต่ออายุ token ลงไฟล์ user-level ให้อัตโนมัติ (ไม่รองรับ Azure DevOps Server และไม่รองรับ macOS/Linux)

1
PowerShell / cmd, ติดตั้งครั้งเดียว
npm install -g vsts-npm-auth --registry https://registry.npmjs.com
2

ในโฟลเดอร์โปรเจกต์ที่มี .npmrc (หัวข้อ 4) แล้ว รัน:

PowerShell / cmd
vsts-npm-auth -config .npmrc

เมื่อ token หมดอายุ npm จะตอบ 401 Unauthorized ให้รันคำสั่งเดิมซ้ำเพื่อต่ออายุ

legacyเอกสารรุ่นเก่าของ Microsoft แนะนำต่อท้าย --always-auth false ตอนติดตั้ง และตั้ง always-auth=true ใน .npmrc option always-auth npm 7+ ไม่ใช้ค่านี้แล้ว และ npm รุ่นใหม่ (เช่น 10/11) จะเตือน Unknown config ไม่ต้องใส่และถ้ามีอยู่ให้ลบทิ้งได้

5b. macOS / Linux: ~/.npmrc + PAT (base64)

1

สร้าง PAT (หัวข้อ 2) แล้วแปลงเป็น base64 โดย ไม่ให้ PAT ค้างใน shell history: พิมพ์แบบไม่แสดงตัวอักษร ไม่ใส่ในอาร์กิวเมนต์ของคำสั่ง

bash / zsh
printf 'PAT (ไม่แสดงตัวอักษร): ' && read -rs PAT && echo
printf '%s' "$PAT" | base64 | tr -d '\n'; echo
unset PAT

วางผลลัพธ์ (สายอักขระยาว) แทน <BASE64_PAT> ด้านล่าง ถ้าไม่มี shell ที่เหมาะ ใช้วิธีของ Microsoft ที่ถามผ่าน Node.js ก็ได้ (ตั้ง historySize:0 ไว้แล้ว):

Node.js, ทุก OS
node -e "require('readline').createInterface({input:process.stdin,output:process.stdout,historySize:0}).question('PAT> ',p=>{console.log(Buffer.from(p.trim()).toString('base64'));process.exit();})"
ห้ามทำecho -n "PAT จริง" | base64 (ตัวอย่างในเอกสารทางการ) จะทำให้ PAT ถูกบันทึกใน history ถ้าเผลอทำไปแล้วให้ revoke PAT นั้นและสร้างใหม่
2

เพิ่มบล็อกนี้ใน ~/.npmrc (ไฟล์ในโฮมของคุณ ไม่ใช่ในโปรเจกต์) สำหรับ feed ชนิด project-scoped:

~/.npmrc (project-scoped feed)
; begin auth token
//pkgs.dev.azure.com/<ORG>/<PROJECT>/_packaging/<FEED>/npm/registry/:username=anything
//pkgs.dev.azure.com/<ORG>/<PROJECT>/_packaging/<FEED>/npm/registry/:_password=<BASE64_PAT>
//pkgs.dev.azure.com/<ORG>/<PROJECT>/_packaging/<FEED>/npm/registry/:email=not-used@example.com
//pkgs.dev.azure.com/<ORG>/<PROJECT>/_packaging/<FEED>/npm/:username=anything
//pkgs.dev.azure.com/<ORG>/<PROJECT>/_packaging/<FEED>/npm/:_password=<BASE64_PAT>
//pkgs.dev.azure.com/<ORG>/<PROJECT>/_packaging/<FEED>/npm/:email=not-used@example.com
; end auth token

สำหรับ feed ชนิด organization-scoped ตัด /<PROJECT> ออกจากทุกบรรทัด:

~/.npmrc (organization-scoped feed)
; begin auth token
//pkgs.dev.azure.com/<ORG>/_packaging/<FEED>/npm/registry/:username=anything
//pkgs.dev.azure.com/<ORG>/_packaging/<FEED>/npm/registry/:_password=<BASE64_PAT>
//pkgs.dev.azure.com/<ORG>/_packaging/<FEED>/npm/registry/:email=not-used@example.com
//pkgs.dev.azure.com/<ORG>/_packaging/<FEED>/npm/:username=anything
//pkgs.dev.azure.com/<ORG>/_packaging/<FEED>/npm/:_password=<BASE64_PAT>
//pkgs.dev.azure.com/<ORG>/_packaging/<FEED>/npm/:email=not-used@example.com
; end auth token
  • username: ใส่ค่าอะไรก็ได้ที่ไม่ใช่สตริงว่าง
  • _password: base64 ของ PAT เพียงอย่างเดียว (ไม่ใช่ user:PAT)
  • email: npm บังคับให้มี แต่ไม่ใช้ค่านี้ ใช้ค่าสมมติได้
  • บรรทัดไม่ขึ้นต้นด้วย https: (เป็น //host/path/) เพื่อผูก credential กับ URL นั้น
3
macOS / Linux
chmod 600 ~/.npmrc

5c. กฎเหล็ก: อย่า commit PAT

  • PAT อยู่ใน ~/.npmrc เท่านั้น ไฟล์โปรเจกต์มีแค่ URL
  • ถ้าโปรเจกต์ต้องมีไฟล์ที่มี credential จริง (เช่น เครื่องชั่วคราว) ให้เพิ่มชื่อไฟล์นั้นใน .gitignore ก่อน
  • เผลอ commit PAT แล้ว: revoke PAT ทันที ลบจากไฟล์ไม่พอเพราะยังอยู่ใน history

6CI: ไม่ใช้ PAT ส่วนตัวของใคร

6a. Azure Pipelines: npmAuthenticate@0

task นี้ใส่ credential ของ build ลงใน .npmrc ที่ระบุ เฉพาะช่วงที่ build รัน (ห้ามใช้ร่วมกับ task Npm@1) วางก่อนคำสั่ง npm install

azure-pipelines.yml
steps:
- task: npmAuthenticate@0
  inputs:
    workingFile: .npmrc
- script: npm ci
  displayName: Install packages
สิทธิ์ของ buildบัญชี Build Service ของโปรเจกต์ได้รับบทบาท Feed and Upstream Reader (Collaborator) โดยค่าเริ่มต้นตอนสร้าง feed ถ้า feed อยู่ต่างโปรเจกต์หรือต่าง organization ต้องเพิ่มสิทธิ์ให้บัญชีนี้เอง (หรือใช้ customEndpoint กับ npm service connection)

6b. GitHub Actions / CI อื่น: env var ใน .npmrc

เก็บ base64 ของ PAT ไว้ใน secret ของ CI ส่วน .npmrc ที่ commit ต้องมี URL อย่างเดียว (แบบหัวข้อ 4) แล้วให้ CI เขียนบรรทัด auth ลง ~/.npmrc ก่อน npm ci โดย npm แทนค่า ${VAR} ด้วย environment variable ตอนรัน

.github/workflows/build.yml
name: build
on: [push]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 'lts/*'
      - name: Write npm credentials (CI only)
        run: |
          P=//pkgs.dev.azure.com/<ORG>/<PROJECT>/_packaging/<FEED>/npm
          for B in "$P/registry/" "$P/"; do
            printf '%s\n' "$B:username=ci" "$B:_password=\${NPM_TOKEN}" "$B:email=ci@example.com" >> ~/.npmrc
          done
      - run: npm ci
        env:
          NPM_TOKEN: ${{ secrets.AZURE_ARTIFACTS_PAT_B64 }}
  • secret AZURE_ARTIFACTS_PAT_B64 = ผลลัพธ์ base64 จากหัวข้อ 5b (ไม่ใช่ PAT ดิบ)
  • ใช้ PAT ของ service account แยกต่างหาก scope Packaging (Read) ถ้าดึงเฉพาะแพ็กเกจที่อยู่ใน feed แล้ว (ถ้าต้องดึงจาก upstream ครั้งแรก ใช้ Read & write ร่วมกับบทบาท Collaborator) อย่าใช้ PAT ส่วนตัว
  • ขั้นตอน npm ci ต้องตั้ง NPM_TOKEN ด้วย เพราะ npm อ่านค่า ${NPM_TOKEN} ใน ~/.npmrc ตอนรัน
ห้ามใส่บรรทัด auth ในไฟล์ที่ commitnpm รุ่นใหม่ไม่ error ถ้าตัวแปรไม่ถูกตั้ง แต่ใช้ข้อความ ${NPM_TOKEN} ตรง ๆ เป็นรหัสผ่าน → E401 และเพราะค่าใน project ชนะ ~/.npmrc จึงห้ามใส่บรรทัด auth ในไฟล์ที่ commit

7ตรวจสอบว่าใช้ได้จริง

1

registry ชี้ถูกที่

shell
npm config get registry

ต้องได้ URL ของ feed (ถ้าใช้แบบ scoped ให้ดู npm config get @myscope:registry)

2

ดูแพ็กเกจ

shell
npm view @myscope/<PACKAGE> version

ถ้าใช้ registry= กับ upstream ลอง npm view <ชื่อแพ็กเกจสาธารณะ> version ได้เช่นกัน

3

ติดตั้งจริง

shell
npm install

ตัวเลขและข้อความเป็นตัวอย่างประกอบ ผลจริงขึ้นกับโปรเจกต์ของคุณ

เคล็ดลับดู URL ที่ npm เรียกจริงด้วย npm install --loglevel verbose หรือ npm config list เพื่อดูว่า .npmrc ไฟล์ไหนถูกโหลด (ระวังอย่าแชร์ผลที่มี credential)

8แก้ปัญหาที่เจอบ่อย

อาการสาเหตุที่เป็นไปได้วิธีแก้
E401 UnauthorizedPAT หมดอายุ / base64 ผิด (มีขึ้นบรรทัดใหม่, เข้ารหัสผิดสตริง) / scope ไม่พอ / URL ใน credential ไม่ตรงกับ registryWindows: รัน vsts-npm-auth -config .npmrc ใหม่ อื่น ๆ: สร้าง PAT ใหม่ เข้ารหัสใหม่ด้วย tr -d '\n' เช็กว่าบรรทัด //pkgs… ตรงกับ URL ของ registry= ทุกตัวอักษร
E403 Forbiddenยืนยันตัวตนผ่านแต่ไม่มีสิทธิ์: ไม่ใช่ Feed Reader, หรือ PAT ไม่มี Packaging scope, หรือการติดตั้งจาก upstream ต้องการ Collaborator, หรือ PAT scope Read อย่างเดียวขณะดึงแพ็กเกจจาก upstream ครั้งแรกขอสิทธิ์ Feed Reader (หรือ Collaborator ถ้าต้องดึงจาก upstream ครั้งแรก) ตรวจ scope ของ PAT
E404 Not Foundชื่อแพ็กเกจ/scope ผิด, ไม่ได้ตั้ง @myscope:registry, หรือ feed ไม่ได้เปิด upstream แต่ใช้ registry= ดึงแพ็กเกจสาธารณะ, หรือ feed อยู่ใน project ต่างจาก URLตรวจชื่อแพ็กเกจใน Artifacts, เปิด upstream sources ใน Feed settings หรือเปลี่ยนไปใช้แบบ scoped, ตรวจ URL ตามหัวข้อ 3
always-auth warning / Unknown configค่าเก่าจากเอกสารรุ่นเก่า npm 7+ ไม่ใช้ค่านี้แล้ว และ npm รุ่นใหม่ (เช่น 10/11) จะเตือน Unknown configลบ always-auth ออกจากทุกไฟล์ .npmrc (มักไม่กระทบการทำงาน)
timeout / ECONNRESET / ผ่าน proxyองค์กรใช้ proxy หรือ TLS inspectionตั้ง npm config set proxy / https-proxy ตามข้อกำหนดองค์กร ใส่ CA ภายในด้วย cafile= (ห้ามปิด strict-ssl เป็นทางลัดถาวร)
แก้ทุกอย่างแล้วยังเหมือนเดิมcache เก่า หรือ metadata เก่าnpm cache clean --force แล้วลองใหม่ (ลบ node_modules และ lockfile เฉพาะเมื่อจำเป็น)
lockfilepackage-lock.json อาจจำ URL ของ registry เดิมไว้ในฟิลด์ resolved ถ้าย้ายมาใช้ feed ใหม่ ให้ตรวจ URL เหล่านั้นด้วย

9Security checklist และการหมุน PAT

  • PAT scope Packaging (Read) สำหรับแพ็กเกจที่อยู่ใน feed แล้ว (Read & write เฉพาะกรณีต้องดึงจาก upstream ครั้งแรก)
  • ตั้งวันหมดอายุสั้น (เช่น 30 วัน) และใส่ปฏิทินเตือนก่อนหมดอายุ
  • ~/.npmrc สิทธิ์ chmod 600
  • ไม่มี _password/_authToken จริงในไฟล์ที่อยู่ใน git (ตรวจด้วย git grep _password)
  • CI ใช้ npmAuthenticate@0 หรือ secret store ไม่ฝัง PAT ใน YAML
  • ใช้ service account แยกสำหรับ CI และ PAT รายคนสำหรับ dev
  • คนออกจากทีม หรือสงสัยว่ารั่ว: revoke PAT ทันที

ขั้นตอนหมุน PAT

  1. สร้าง PAT ใหม่ (scope เดิม) ก่อนอันเก่าหมดอายุ
  2. เข้ารหัส base64 ตามหัวข้อ 5b และแก้ _password ทั้งสองบรรทัด (หรืออัปเดต secret ใน CI)
  3. รัน npm view <แพ็กเกจใน feed> version และ npm install เพื่อตรวจ
  4. Revoke PAT เก่าใน User settings > Personal access tokens
คัดลอกแล้ว