Nodejs

 


 

소스 : https://github.com/braverokmc79/nestjs-netflix

1.   AWS  Elastic Beanstalk 배포

.gihub/workflows/aws-deploy.yml

name: Deploy to AWS Elastic Beanstalk

on:
  push:
    branches:
      - main

jobs:
  build-and-deploy:
    runs-on: nextjs-latest

    services:
      postgres:
        image: postgres:16
        env:
          POSTGRES_USER: postgres
          POSTGRES_PASSWORD: postgres
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 5432:5432

    steps:
      - name: Checkout Code
        uses: actions/checkout@v3

      - name: Set Up NodeJS
        uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: Create Env File
        env:
          ENV: ${{secrets.ENV}}
          DB_TYPE: ${{secrets.DB_TYPE}}
          DB_HOST: ${{secrets.DB_HOST}}
          DB_PORT: ${{secrets.DB_PORT}}
          DB_USERNAME: ${{secrets.DB_USERNAME}}
          DB_PASSWORD: ${{secrets.DB_PASSWORD}}
          DB_DATABASE: ${{secrets.DB_DATABASE}}
          HASH_ROUNDS: ${{secrets.HASH_ROUNDS}}
          ACCESS_TOKEN_SECRET: ${{secrets.ACCESS_TOKEN_SECRET}}
          REFRESH_TOKEN_SECRET: ${{secrets.REFRESH_TOKEN_SECRET}}
          AWS_ACCESS_KEY_ID: ${{secrets.AWS_ACCESS_KEY_ID}}
          AWS_SECRET_ACCESS_KEY: ${{secrets.AWS_SECRET_ACCESS_KEY}}
          AWS_REGION: ${{secrets.AWS_REGION}}
          BUCKET_NAME: ${{secrets.BUCKET_NAME}}
        run: |
          touch test.env
          echo ENV="test" >> test.env
          echo DB_TYPE="$DB_TYPE" >> test.env
          echo DB_HOST="localhost" >> test.env
          echo DB_PORT="$DB_PORT" >> test.env
          echo DB_USERNAME="$DB_USERNAME" >> test.env
          echo DB_PASSWORD="$DB_PASSWORD" >> test.env
          echo DB_DATABASE="$DB_DATABASE" >> test.env
          echo HASH_ROUNDS="$HASH_ROUNDS" >> test.env
          echo ACCESS_TOKEN_SECRET="$ACCESS_TOKEN_SECRET" >> test.env
          echo REFRESH_TOKEN_SECRET="$REFRESH_TOKEN_SECRET" >> test.env
          echo AWS_ACCESS_KEY_ID="$AWS_ACCESS_KEY_ID" >> test.env
          echo AWS_SECRET_ACCESS_KEY="$AWS_SECRET_ACCESS_KEY" >> test.env
          echo AWS_REGION="$AWS_REGION" >> test.env
          echo BUCKET_NAME="$BUCKET_NAME" >> test.env
          echo "test.env created"
          cat test.env

          touch env.env
          echo ENV="$ENV" >> .env
          echo DB_TYPE="$DB_TYPE" >> .env
          echo DB_HOST="$DB_HOST" >> .env
          echo DB_PORT="$DB_PORT" >> .env
          echo DB_USERNAME="$DB_USERNAME" >> .env
          echo DB_PASSWORD="$DB_PASSWORD" >> .env
          echo DB_DATABASE="$DB_DATABASE" >> .env
          echo HASH_ROUNDS="$HASH_ROUNDS" >> .env
          echo ACCESS_TOKEN_SECRET="$ACCESS_TOKEN_SECRET" >> .env
          echo REFRESH_TOKEN_SECRET="$REFRESH_TOKEN_SECRET" >> .env
          echo AWS_ACCESS_KEY_ID="$AWS_ACCESS_KEY_ID" >> .env
          echo AWS_SECRET_ACCESS_KEY="$AWS_SECRET_ACCESS_KEY" >> .env
          echo AWS_REGION="$AWS_REGION" >> .env
          echo BUCKET_NAME="$BUCKET_NAME" >> .env
          echo ".env created"
          cat .env

      - name: Create Folders
        run: |
          mkdir -p ./public/movie
          mkdir -p ./public/temp

      - name: Install Depencies
        run: npm i

      - name: Build Project
        run: npm run build

      - name: Run Test
        run: npm run test

      - name: Install Typeorm
        run: npm i -g typeorm

      - name: Run Migration
        run: typeorm migration:run -d ./dist/database/data-source.js

      - name: Zip Artfact For Deployment
        run: zip -r deploy.zip .

      - name: Upload To S3
        env:
          AWS_ACCESS_KEY_ID: ${{secrets.AWS_ACCESS_KEY_ID}}
          AWS_SECRET_ACCESS_KEY: ${{secrets.AWS_SECRET_ACCESS_KEY}}
          AWS_REGION: ${{secrets.AWS_REGION}}
        run: |
          aws configure set region $AWS_REGION
          aws s3 cp deploy.zip s3://nestjs-netflix-bucket/deploy.zip

      - name: Deploy To AWS Elastic Beanstalk
        env:
          AWS_ACCESS_KEY_ID: ${{secrets.AWS_ACCESS_KEY_ID}}
          AWS_SECRET_ACCESS_KEY: ${{secrets.AWS_SECRET_ACCESS_KEY}}
          AWS_REGION: ${{secrets.AWS_REGION}}
        run: |
          aws elasticbeanstalk create-application-version \
            --application-name "nestjs-netflix" \
            --version-label $GITHUB_SHA \
            --source-bundle S3Bucket="nestjs-netflix-bucket",S3Key="deploy.zip"

          aws elasticbeanstalk update-environment \
            --application-name "nestjs-netflix" \
            --environment-name "Nestjs-netflix-env" \
            --version-label $GITHUB_SHA

 

 

1)이름과 트리거 조건

name: Deploy to AWS Elastic Beanstalk
on:
  push:
    branches:
      - main
  • 이름: Deploy to AWS Elastic Beanstalk

  • 트리거 조건: main 브랜치에 push가 발생할 때 워크플로 실행

 

 

2)jobs: build-and-deploy

실행 환경

runs-on: nextjs-latest

nextjs 최신 버전에서 워크플로 실행

 

 

3)  PostgreSQL 서비스 (CI 테스트용)

services:
  postgres:
    image: postgres:16
    ...
  • PostgreSQL 16 버전을 도커로 실행

  • 포트: 5432 사용

  • pg_isready를 통해 DB 헬스 체크 수행

 

 

 

4)1. 코드 체크아웃

- name: Checkout Code
  uses: actions/checkout@v3

현재 커밋된 코드를 워크플로에 가져옴

 

 

 

5) 2. Node.js 환경 설정

- name: Set Up NodeJS
  uses: actions/setup-node@v3
  with:
    node-version: '18'
  • Node.js 18버전 설치

 

 

 

6) 3. .env 파일 생성

- name: Create Env File
  • CI/CD에 필요한 .env 파일과 test.env 파일을 생성

  • GitHub Secrets에서 민감한 정보들을 주입

  • localhost DB로 지정한 것은 CI 환경에서 테스트용 PostgreSQL을 사용하기 위함

 

 

7)폴더 생성

- name: Create Folders



./public/movie, ./public/temp 디렉토리 생성

 

 

8) 의존성 설치

- name: Install Dependencies
  run: npm i

 

 

 

9) 프로젝트 빌드

- name: Build Project
  run: npm run build

프로젝트 빌드 (예: NestJS 빌드)

 

 

10) 테스트 실행

- name: Run Test
  run: npm run test

테스트 코드 실행

 

 

11) TypeORM CLI 설치

- name: Install Typeorm
  run: npm i -g typeorm

전역으로 TypeORM CLI 설치 (마이그레이션 실행을 위해)

 

 

12) 마이그레이션 실행

- name: Run Migration
  run: typeorm migration:run -d ./dist/database/data-source.js

 

빌드된 data-source.js를 기반으로 DB 마이그레이션 실행

 

 

 

13)  배포용 압축파일 생성

- name: Zip Artifact For Deployment
  run: zip -r deploy.zip .

 

현재 프로젝트 전체를 deploy.zip으로 압축

 

 

14)  S3 업로드

- name: Upload To S3
  run: |
    aws configure set region $AWS_REGION
    aws s3 cp deploy.zip s3://nestjs-netflix-bucket/deploy.zip

deploy.zip을 S3 버킷에 업로드 (nestjs-netflix-bucket)

 

 

 

15)  Elastic Beanstalk 배포

- name: Deploy To AWS Elastic Beanstalk
  run: |
    aws elasticbeanstalk create-application-version ...
    aws elasticbeanstalk update-environment ...
  • 새 어플리케이션 버전 생성 (커밋 SHA를 버전 라벨로 사용)

  • 해당 버전으로 Elastic Beanstalk 환경 업데이트
    (환경명: Nestjs-netflix-env, 앱명: nestjs-netflix)

 

 

 

 

 

 

 

 

 

2.   우분트 22  SSH  배포

 

다음 참조

✅Spring Boot 3.4 애플리케이션을 우분투 22 서버에 GitHub Actions를 사용해 무중단 배포

 

 

1) SSH 키 기반 인증 준비

 SSH Key 생성 및 서버 등록

 

1. 로컬에서 SSH 키 생성 

여기서 github-actions@our-sample 는 임의 명이다.

github-deploy-key 또한 원하는 이름으로 변경하면된다.

중요한것은 깃허브에서  actions 에서 우분트 22 에 접속할수 있는  개인 키 등록과 우부트 22에 공개 키 설정이다.

 

PowerShell 사용 시 (경로를 명시적으로 써야 함)

ssh-keygen -t rsa -b 4096 -C "github-actions@our-sample" -f "$env:USERPROFILE\.ssh\github-deploy-key"

 

Git Bash 사용 시 (추천).

	
ssh-keygen -t rsa -b 4096 -C "github-actions@our-sample" -f ~/.ssh/github-deploy-key

 

 

2. GitHub에 개인 키 등록

github-deploy-key 내용을 복사

GitHub 저장소> 깃허브 해당 프로젝트에서 > Settings > Secrets and variables > Actions > New secret 이름은 예: DEPLOY_KEY  값을 복붙

 

 

 

 

nextjs 22 서버의 nextjs계정에 SSH 기반 GitHub Actions 배포 설정

우부트 계정이  nextjs라고 할때 

 

✅ 1단계: 로컬에서 SSH 키 생성 (GitHub Actions용)

ssh-keygen -t rsa -b 4096 -C "github-actions@nextjs" -f ~/.ssh/github-nextjs-key
  • 결과:

    • 개인 키: ~/.ssh/github-nextjs-key

    • 공개 키: ~/.ssh/github-nextjs-key.pub

 

윈도우에 파워셀 명령어로 키 생성 후  우분투 22 에서 공개키 저장 및 깃허브에 개인키 저장, 다음 명령어로 키를 생성한다

ssh-keygen -t rsa -b 4096 -C "github-actions@our-nextjs" -f "$env:USERPROFILE\.ssh\github-nextjs-key"

 

 

✅ 2단계: GitHub에 개인 키 등록 (Secrets)

  1. 개인 키 내용 복사:   nextjs 사용자라면/home/nextjs/.ssh/github-nextjs-key

cat ~/.ssh/github-nextjs-key
  1. GitHub 저장소 → Settings > Secrets and variables > Actions > New secret

    • 이름: DEPLOY_KEY

    • 값: 위에서 복사한 개인 키 전체 내용

개인 키는 절대 서버에 저장하지 않습니다.

✅ 3단계: 우분투 서버(nextjs 계정)에 공개 키 등록

  1. 서버 접속:

ssh nextjs@your.server.ip
  1. .ssh 디렉토리 및 권한 설정:

mkdir -p ~/.ssh
chmod 700 ~/.ssh
  1. 로컬에서 공개 키 내용 복사:

cat ~/.ssh/github-nextjs-key.pub
  1. 서버에 공개 키 붙여넣기:

 

echo "<복사한 공개 키 내용>" >> ~/.ssh/authorized_keys

cat ~/.ssh/github-nextjs-key.pub >> ~/.ssh/authorized_keys


chmod 600 ~/.ssh/authorized_keys

주의 

cp로 복사하면 안 되는 이유

1. 기존 authorized_keys 내용이 모두 덮어쓰기 됨

  • cp는 파일 전체를 덮어쓰기합니다.

  • 이미 authorized_keys에 다른 공개키들이 등록돼 있었다면, 모두 삭제되고 새 키만 남습니다.

2. 공개키 여러 개 사용하는 환경에 적합하지 않음

  • 나중에 다른 팀원 또는 자동화 툴의 키를 추가하려고 할 때 문제가 생깁니다.

 

 

 

 

✅ 4단계: GitHub Actions에서 SSH 설정

- name: Setup SSH
  run: |
    mkdir -p ~/.ssh
    echo "${{ secrets.DEPLOY_KEY }}" > ~/.ssh/id_rsa
    chmod 600 ~/.ssh/id_rsa
    ssh-keyscan your.server.ip >> ~/.ssh/known_hosts

 

✅ 5단계: 배포 예시 스크립트

- name: Deploy to Server
  run: |
    ssh nextjs@your.server.ip "cd ~/app && ./deploy.sh"

 

✅ 보안 설정 요약

항목설정

접속 계정nextjs 전용 계정 사용

루트 로그인PermitRootLogin no

비밀번호 인증PasswordAuthentication no

개인 키 위치GitHub Actions Secret (DEPLOY_KEY)

공개 키 위치/home/nextjs/.ssh/authorized_keys

 

 

 

 

 

 

 

 

설치

sudo apt install nodejs npm
npm install -g pm2

 

 

 

2) GitHub에  Secrets  등록

  1. GitHub > Settings > Secrets and variables > Actions > New repository secret

  2. 아래 항목 등록:

  3. 권한 설정 문제 :  

a) DEPLOY_KEY: 개인 키 (~/.ssh/github-deploy-key 내용)
b) HOST: sample.com
c) USER: nextjs
d) TARGET_DIR: /home/nextjs/app
e) SERVICE_NAME: nextjs.service
f) PORT:  1234
g) ENV :  .env 전체 내용을 그대로 붙여넣기

 

 

디렉토리 생성 : 샘플

mkdir -p /home/nextjs/app

 

.env  샘플

#dev = 개발  환경
#prod = 배포 환경
NESTJS_ENV="prod"

TARGET_DIR="/home/nextjs/app"

#DB
DB_TYPE = "postgres"
DB_HOST="192.168.0.19"
DB_PORT="5432"
DB_USERNAME="sample"
DB_PASSWORD="sample"
DB_DATABASE="sample"

# Hash
HASH_ROUNDS=10

# JWT  $ openssl rand -base64 64
ACCESS_TOKEN_SECRET="sample"
REFRESH_TOKEN_SECRET="sample"
JWT_SECRET="sample"

 

 

 

 

 

3) ssh-deploy.yml

GitHub에 등록한 self-hosted runner가 있다면, runs-on:에는 해당 runner를 구분할 수 있는 라벨(label) 을 지정해야 합니다

  runs-on: [self-hosted, nextjs-host]

 

라벨 지정 방법

1)

 

2)

 

서버 실행시 확인

3) sudo systemctl status github-runner

 

 

 

 

 

 

 

 

 

1. runs-on은 runner의 라벨 이름
GitHub Actions에서 runs-on:은 "어떤 runner에서 이 job을 실행할지"를 지정합니다.

GitHub에서 직접 제공하는 runner는 예: nextjs-latest, windows-latest, macos-latest

Self-hosted runner는 등록할 때 **라벨(label)**을 하나 이상 설정하게 되어 있음

예시:

 

만약에 등록한 값이 없다면, 깃허브에서 기본적으로 제공하는  nextjs-latest  를 적어 준다.

 

 

 

 

 

✅ NestJS Health Check 설정 방법 (캔버스 정리)

NestJS 앱을 배포하고 정상 작동 여부를 확인하려면 Health Check 엔드포인트를 설정하는 것이 중요합니다. 아래는 GitHub Actions와 함께 사용할 수 있도록 헬스 체크를 구성하는 단계별 가이드입니다.

1️⃣ Terminus 모듈 설치

npm install @nestjs/terminus

Terminus는 NestJS에서 헬스 체크를 표준화하기 위한 공식 모듈입니다.

2️⃣ CLI로 Health 리소스 생성

nest g resource health

CLI 질문 응답:

  • Transport Layer: REST

  • CRUD 생성 여부: No

생성되는 기본 구조:

src/health/

├── health.controller.ts
├── health.module.ts
└── health.service.ts

3️⃣ health.controller.ts 수정

import { Controller, Get } from '@nestjs/common';
import {
  HealthCheck,
  HealthCheckService,
  HealthCheckResult,
} from '@nestjs/terminus';
import { Public } from 'src/auth/decorator/public.decorator';

@Controller('health')
export class HealthController {
  constructor(private readonly health: HealthCheckService) {}

  @Public()
  @Get()
  @HealthCheck()
  check(): Promise<HealthCheckResult> {
    return this.health.check([]);
  }
}

이 코드는 단순히 서버가 살아 있는지 확인하는 기본 체크입니다.

4️⃣ health.module.ts 수정

import { Module } from '@nestjs/common';
import { TerminusModule } from '@nestjs/terminus';
import { HealthController } from './health.controller';
import { HealthService } from './health.service';

@Module({
  imports: [TerminusModule],
  controllers: [HealthController],
  providers: [HealthService],
})
export class HealthModule {}

5️⃣ app.module.ts에 등록

import { Module } from '@nestjs/common';
import { HealthModule } from './health/health.module';

@Module({
  imports: [HealthModule],
})
export class AppModule {}

6️⃣ 헬스 체크 확인

NestJS 서버 실행 후:

GET http://localhost:3000/health

응답 예:

{
  "status": "ok",
  "info": {},
  "error": {},
  "details": {}
}

✅ GitHub Actions 연동

HEALTHCHECK_URL 값을 .env 또는 GitHub Secret에 설정:

Name: HEALTHCHECK_URL
Value: http://your-domain.com/health

CI/CD 스크립트에서 해당 URL로 상태 확인 후 배포 성공 여부 결정.

 

 

 

 

 

 

ssh-deploy.yml

name: CI/CD for NestJS

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: [self-hosted, nextjs-host]

    steps:
      - name: ✅ Checkout repository
        uses: actions/checkout@v3

      - name: ✅ Set up Node.js 18
        uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: ✅ List directory contents
        run: |
          pwd
          ls -alR

      - name: ✅ Create .env file from secrets
        run: |
          mkdir -p backend
          echo "${{ secrets.ENV }}" > backend/.env
          echo ".env created in backend/"

      - name: ✅ Install backend dependencies
        working-directory: ./backend
        run: npm install

      - name: ✅ Build backend project
        working-directory: ./backend
        run: npm run build

      - name: ✅ Setup SSH private key and known_hosts
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.DEPLOY_KEY }}" > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa
          ssh-keyscan -p ${{ secrets.PORT }} -H ${{ secrets.HOST }} >> ~/.ssh/known_hosts

      - name: ✅ Compress and transfer build to remote server
        run: |
          tar -czf backend.tar.gz backend
          scp -F /dev/null -P ${{ secrets.PORT }} backend.tar.gz ${{ secrets.USER }}@${{ secrets.HOST }}:${{ secrets.TARGET_DIR }}/backend-latest.tar.gz

      - name: ✅ Restart service on remote server
        env:
          TARGET_DIR: ${{ secrets.TARGET_DIR }}
          HOST: ${{ secrets.HOST }}
          USER: ${{ secrets.USER }}
          PORT: ${{ secrets.PORT }}
        run: |
          ssh -F /dev/null -p "$PORT" "$USER@$HOST" << 'EOF'
            set -e
            echo "✅ Connected to remote server"

            echo "✅ Extracting build..."
            cd "$TARGET_DIR"
            rm -rf backend_new
            mkdir backend_new
            tar -xzf backend-latest.tar.gz -C backend_new --strip-components=1

            echo "✅ Fixing permissions (if needed)..."
            chown -R nextjs:nextjs "$TARGET_DIR/backend_new"

            echo "✅ Updating symlink..."
            ln -sfn "$TARGET_DIR/backend_new" "$TARGET_DIR/current"

            cd "$TARGET_DIR/current"

            echo "✅ Installing production dependencies..."
            npm install --omit=dev

            echo "✅ Restarting PM2 service..."
            pm2 restart app || pm2 start dist/main.js --name app

            echo "✅ 현재 실행 중인 모든 애플리케이션의 상태를 저장"
            pm2 save

            echo "✅ Deployment complete."
          EOF

 

 

※전송 시 scp로 권한 유지

cat ~/.ssh/github-deploy-key.pub >> ~/.ssh/authorized_keys

chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

 

authorized_keys 를 루트에서 설정했기 때문에 루트 권한을 가집니다.

 따라서 scp 자체는 파일을 원격에서 어떤 유저로 실행하는지가 중요합니다.

만약 scp 전송 명령이 root 권한으로 실행되고 있다면, GitHub Action의 self-hosted runner 권한을 nextjs로 제한하거나,

파일 전송 후 아래처럼 권한을 반드시 조정하세요:

 

chown nextjs:nextjs backend-latest.tar.gz

 

authorized_keys 를 루트에서 설정 했기 때문에 github action 에 등록 한 USER 가 일반 접속 유저일경우

 항상 

일반 유저 파일 권한 변경 추가 다음처럼 권한 변경을 추가해야 합니다.

# inside your SSH script
sudo chown -R nextjs:nextjs /home/nextjs/app/backend-latest.tar.gz

 

 

 

 

 

4) 서버에 PM2 설치

서버에 SSH 접속해서 아래 명령어 실행:

# Node.js가 설치되어 있어야 합니다
npm install -g pm2

 

설치 확인:

 

pm2 -v

 

 

Restart service via SSH 설정 설명

- name: Restart service via SSH
  run: |
    ssh -p ${{ secrets.PORT }} ${{ secrets.USER }}@${{ secrets.HOST }} << 'EOF'
      set -e
      cd ${TARGET_DIR}
      tar -xzf backend-latest.tar.gz
      ln -sf ${TARGET_DIR}/backend ${TARGET_DIR}/current
      cd ${TARGET_DIR}/current
      npm install --omit=dev
      npm run build
      pm2 restart nestjs-app || pm2 start dist/main.js --name nestjs-app --env production
    EOF

 

위 명령은:

  • 앱이 이미 실행 중이면 restart

  • 앱이 없으면 새로 start

 

GitHub Actions에서 서버에 코드 배포

 

이미 설정하신 이 부분은 그대로 유지하시면 됩니다:

  • backend를 tar로 압축해서 서버로 전송

  • 서버에서 압축 해제

  • ln -sf로 /home/nextjs/app/current 심볼릭 링크 생성

즉, current 디렉토리에 항상 최신 NestJS 앱이 배포되게 설정돼 있어야 합니다.

 

 PM2 프로세스 등록 (처음 1번만)

서버에서 다음 명령어로 PM2에 NestJS 앱을 등록합니다

 

cd /home/nextjs/app/current

# .env가 있는 상태여야 함
npm install --omit=dev
npm run build

# PM2에 등록 (앱 이름은 nestjs-app으로 설정)
pm2 start dist/main.js --name nestjs-app --env production

 

.env는 GitHub Actions에서 이미 자동 생성되어 있으니 괜찮습니다.

 

 

 

 

5). PM2 로그 보기 (서버에서)

pm2 logs nestjs-app

 

 

 

 

 

 

✅ GitHub Actions에서 self-hosted 러너를 설정

 

기본 개념

  • GitHub Actions는 GitHub에서 제공하는 CI/CD(지속적 통합/배포) 도구입니다.

  • 기본적으로 GitHub에서는 무료로 제공되는 호스팅 러너(nextjs-latest 등)를 사용하지만,

  • 필요에 따라 자체 서버(local, VM, 클라우드 등)를 러너로 등록하여 사용할 수 있습니다. 이것이 self-hosted runner입니다.

 

 

 

Self-Hosted 러너를 사용하는 이유

 

1)성능 제어    :     CPU , 메모리, 스토리지 등 자원을 내가 원하는 수준으로 구성 가능

2) 커스텀 환경  :  특정 라이브러리, 툴체인, DB 등을 미리 설치해 둘 수 있음

3) 보안  :  외부에 노출되지 않은 사내 네트워크나 내부 시스템 접근 가능

4)비용 절감  :   Actions 사용량이 많을 경우 GitHub의 무료 러너 한도를 초과함 → 자체 서버 사용 시 비용 절감

5) Windows/macOS 필요 시   :   GitHub이 기본적으로 Linux 러너만 제공하므로 Windows/macOS 환경이 필요할 경우 직접 구성해야 함

 

 

✅ 설정 요약

  1. GitHub 저장소 → Settings → Actions → Runners

  2. OS 선택 (Linux, Windows, macOS)

  3. 스크립트 복사

  4. 자신의 서버에서 실행 (ex. WSL2에서 실행 가능)

 

 

깃허브 액션 러너 설정

 

 

관리 권한으로 하면 안된다. 또한 접속자 권한으로 실행시에도 다음과 같은 오류가 난다.

 

 

actions-runner 디렉터리 내 파일의 소유권을 현재 사용자로 변경하세요

sudo chown -R $USER:$USER /actions-runner

 

다시 실행 전에 권한을 안전하게 설정해줍니다:

 

chmod -R u+rwX /actions-runner

 

 

위 권한 수정이 완료되면 다시 설정 명령어를 실행하세요:

 

작업은 sudo 없이 현재 사용자 계정으로 실행되어야 합니다. ./run.sh 역시 마찬가지입니다:

./run.sh

 

 

 

 

 

 

 

 

 WSL(Windows Subsystem for Linux)로 리눅스 사용하기

 

✅ WSL이란?

Windows에서 리눅스 커널을 직접 실행할 수 있게 해주는 기능입니다. 일반적으로 nextjs 배포판을 가장 많이 사용합니다.

 

✅ 설치 순서 (Windows 10/11 기준)

  1. PowerShell(관리자) 열기

wsl --install

자동으로 nextjs 설치됨 (Windows 11에서는 단순 명령어 하나로 끝)

  1. 설치 후 초기 설정

    • 사용자 이름 및 비밀번호 설정

  2. WSL2 설정 확인

wsl --set-default-version 2

 

실행

wsl

또는 시작 메뉴 → nextjs 검색

 

✅ GitHub Actions Self-Hosted Runner + WSL 사용 가능?

WSL2 환경에서도 self-hosted 러너를 등록할 수 있습니다.

 

# WSL2에서 러너 등록
mkdir actions-runner && cd actions-runner
curl -o actions-runner-linux-x64-2.316.0.tar.gz -L https://github.com/actions/runner/releases/download/v2.316.0/actions-runner-linux-x64-2.316.0.tar.gz
tar xzf actions-runner-linux-x64-2.316.0.tar.gz

# GitHub에서 발급받은 설정 명령어 붙여넣기 (token 포함)
./config.sh --url https://github.com/your-org/your-repo --token XXXXXX

# 실행
./run.sh

 

✅ 기본 설치 경로 (권장)

GitHub에서 공식적으로 제시하는 설치 경로 예시:

# 예: nextjs 사용자
cd ~
mkdir actions-runner && cd actions-runner

# 설치 및 구성
curl -o actions-runner-linux-x64-*.tar.gz -L https://github.com/actions/runner/releases/download/...
tar xzf ./actions-runner-linux-x64-*.tar.gz
./config.sh --url https://github.com/your_org/your_repo --token your_token

 

이렇게 하면 runner는 ~/actions-runner 디렉토리에 설치되고,
실행 파일은 ~/actions-runner/run.sh에 위치하게 됩니다.

 

 

왜 홈 디렉터리에 설치하나?

  • 보안: 시스템 전역 경로(/)나 /opt, /usr/local 등에 설치할 경우 root 권한이 필요하며, 잘못 관리될 경우 보안 문제가 생길 수 있습니다.

  • 유지보수: 여러 사용자 환경에서 독립적인 runner 관리가 쉬워짐.

  • 권장 관행: GitHub 문서가 사용자 단위 설치를 기본으로 안내함.

  • 컨테이너/CI 환경과의 호환성: 일반적으로 비-root 환경에서 실행되도록 구성됨

 

 

확인 방법

설치가 어디에 되어 있는지 확인하려면 아래 명령어를 사용하세요

sudo find / -name "run.sh" -path "*/actions-runner/*" 2>/dev/null

 

 

 

 

 

 

 

 

 

 

 

 

 

 

✅nextjs 시스템에서 부팅 시 /actions-runner/run.sh 자동 실행을 설정하는 방법 

 

1. run.sh 권한 확인

실행 가능 여부를 먼저 확인합니다:

chmod +x ~/actions-runner/run.sh

 

2. systemd 서비스 파일 생성

sudo nano /etc/systemd/system/github-runner.service

 

 

[Unit]
Description=GitHub Actions Runner
After=network.target

[Service]
ExecStart=/home/nextjs/actions-runner/run.sh
User=nextjs
WorkingDirectory=/home/nextjs/actions-runner
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

 

 

3. systemd 서비스 등록 및 활성화

# 권한 다시 로딩
sudo systemctl daemon-reexec
sudo systemctl daemon-reload

# 서비스 등록
sudo systemctl enable github-runner.service

# 즉시 실행
sudo systemctl start github-runner.service

# 상태 확인
sudo systemctl status github-runner.service

 

 

확인

  • 시스템 재부팅 후에도 run.sh가 자동으로 실행됩니다.

  • journalctl -u github-runner.service 로 로그 확인 가능

 

✅ 부팅 시 정상 동작 확인 팁

  1. 시스템 재부팅

sudo reboot

 

2.재부팅 후 로그인 없이도 GitHub Runner가 자동 실행되는지 확인:

sudo systemctl status github-runner
 

 

 

 

 

 

 

Self-hosted Runner를 위한 네트워크 및 보안 체크리스트

 

✅ 1. GitHub 서버와의 통신 허용

  • GitHub에서 runner와 통신하기 위해 아웃바운드 포트가 열려 있어야 합니다.

  • 기본적으로 허용해야 할 포트:

    • HTTPS (443) → GitHub와의 통신 (최우선)

    • HTTP (80) → 초기 리디렉션에 사용되기도 함

  • 필수 도메인:

    • github.com, api.github.com, actions.githubusercontent.com 등

대부분의 경우 아웃바운드만 허용되면 충분합니다. 방화벽이 너무 제한적인 환경이라면 도메인 화이트리스트 등록도 필요할 수 있습니다.

 

✅ 2. 방화벽 설정

  • Runner는 GitHub 서버에서 직접 접속하지 않습니다. 즉, GitHub → runner로 인바운드 요청이 발생하지 않음.

  • 따라서 인바운드 포트를 열 필요는 없음, 단:

    • CI 환경 내에서 테스트 대상 애플리케이션이 서버처럼 동작하고 내부적으로 포트를 사용하는 경우, 예: Django 서버 실행 (python manage.py runserver), 해당 포트를 허용해야 함.

 

 

 

# 로컬에서 테스트 시 8000번 포트를 사용할 수 있게 허용
sudo ufw allow 8000

 

 

 

✅ 3. Runner 보안

  • self-hosted runner는 외부 요청을 받아 실행하므로 다음을 고려해야 합니다:

    • 별도의 사용자 계정으로 실행 (루트 권한 X)

    • 실행 환경을 주기적으로 초기화하거나 컨테이너화 (예: Docker)하여 안전하게 유지

    • 필요시 CI 서버를 내부망에서만 접근 가능하게 구성

 

 

예: nextjs + UFW 환경에서 최소 설정

# 아웃바운드 허용 (기본적으로 허용되어 있음)
sudo ufw default allow outgoing

# 인바운드는 필요할 때만 허용 (예: Django 서버 테스트용 8000)
sudo ufw allow 8000

# UFW 상태 확인
sudo ufw status

 

 

 

 

 

 

 

 

 

about author

PHRASE

Level 60  라이트

Children have the qualities of the parents. (자식은 양친의 성격을 이어 받는다.)

댓글 ( 0)

댓글 남기기

작성