TechFeedTechFeed
Open Source

Gitea 자체 깃 서버 구축 실전 튜토리얼 — Docker Compose 설치·SSH·Actions CI까지

Docker Compose로 Gitea 오픈소스 깃 서버를 설치하고, PostgreSQL 연동·SSH 키 등록·Gitea Actions CI 파이프라인 구성·Nginx HTTPS 설정·자동 백업까지 단계별로 구축하는 실전 가이드. 국내 VPS 환경에서 겪은 설정 함정과 깃허브에서 마이그레이션하는 방법도 포함. 깃허브 비용 절감 또는 사내 소스코드 보안이 필요한 개발팀을 위한 오픈소스 셀프호스팅 튜토리얼.

by

깃허브 월 사용료가 팀 규모와 함께 커지거나, 사내 소스코드를 외부 서버에 두기 껄끄럽다면 Gitea가 현실적인 대안입니다. Gitea는 Go 언어로 만든 가벼운 오픈소스 깃 서버로, 단일 바이너리 하나면 설치가 끝납니다. 이 글은 Docker Compose로 Gitea를 설치하고, SSH 키 등록 → 팀 권한 설정 → Gitea Actions CI 파이프라인 → Nginx HTTPS까지 실전 환경을 갖추는 단계별 튜토리얼입니다.


저는 실제로 이 스택을 개인 서버에서 수개월째 운영하고 있습니다. 국내 VPS 환경에서 겪은 설정 함정과 깃허브에서 마이그레이션하는 구체적인 방법도 함께 담았습니다. 코드 블록은 복사해서 바로 쓸 수 있도록 실제 동작하는 설정만 넣었습니다.


Gitea를 선택해야 할 때와 하지 말아야 할 때

Gitea가 선택받는 이유는 크게 세 가지입니다. 첫째, 비용입니다. 팀원이 늘어날수록 깃허브 조직 플랜 비용은 함께 커집니다. 소규모 팀이라도 연간 수십만 원이 나가는 구조입니다. Gitea는 무료 오픈소스이며 서버 비용만 부담하면 됩니다.


둘째, 규정 준수입니다. 금융·공공·의료 도메인 개발사는 소스코드를 외부 클라우드에 두기 어려운 경우가 있습니다. 온프레미스 깃 서버가 내부 규정상 필수인 환경이 실제로 많습니다.


셋째, 자원 효율입니다. GitLab과 달리 Gitea는 메모리 사용량이 적어 소형 VPS에서도 운영이 가능합니다. 2GB RAM VPS에서 Gitea와 PostgreSQL을 함께 돌려도 상시 메모리 점유율이 400MB 수준입니다.


반면, 다음 상황이라면 깃허브를 유지하는 편이 낫습니다.


  • 서버 운영 경험이 없고 배울 여유가 없는 경우
  • 팀 전원이 GitHub Actions 워크플로우에 깊이 의존하는 경우 (Gitea Actions로 이식 가능하나 학습 비용이 있음)
  • 외부 개발자와 PR 협업이 잦은 오픈소스 프로젝트인 경우 (깃허브 생태계가 훨씬 유리)

Gitea 오픈소스 깃 서버 대시보드 화면
Gitea는 깃허브와 유사한 웹 인터페이스를 제공한다. 이슈·PR·위키·Actions 탭이 동일한 구조로 배치된다

Docker Compose로 Gitea + PostgreSQL 설치하기

Docker Compose를 사용하면 Gitea와 데이터베이스를 한 파일에 정의하고 명령어 하나로 실행할 수 있습니다. SQLite도 지원하지만 팀 규모가 3명 이상이라면 PostgreSQL을 권장합니다. 동시 접속 처리와 백업 편의성이 훨씬 낫습니다.


아래 파일을 서버의 ~/gitea/docker-compose.yml 경로에 저장합니다.


docker-compose.yml
version: "3" networks: gitea: external: false services: server: image: gitea/gitea:1.21-rootless container_name: gitea environment: - USER_UID=1000 - USER_GID=1000 - GITEA__database__DB_TYPE=postgres - GITEA__database__HOST=db:5432 - GITEA__database__NAME=gitea - GITEA__database__USER=gitea - GITEA__database__PASSWD=gitea_password # 실서버에서는 강력한 비밀번호로 교체 restart: always networks: - gitea volumes: - ./gitea:/var/lib/gitea - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro ports: - "3000:3000" # 웹 UI - "222:22" # SSH (호스트 22는 서버 SSH가 점유하므로 222 사용) depends_on: - db db: image: postgres:16-alpine restart: always environment: - POSTGRES_USER=gitea - POSTGRES_PASSWORD=gitea_password - POSTGRES_DB=gitea networks: - gitea volumes: - ./postgres:/var/lib/postgresql/data

파일을 저장한 후 아래 명령으로 컨테이너를 시작합니다.


docker compose up -d


SSH 포트를 222로 설정한 이유는 호스트 서버의 22번 포트가 이미 SSH 접속용으로 사용 중이기 때문입니다. 나중에 클론 URL에서 포트를 명시해야 하는 점이 불편하다면, 호스트 SSH를 다른 포트로 먼저 변경한 뒤 Gitea가 22번을 사용하도록 설정할 수도 있습니다.


컨테이너가 올라오는 데 10~20초 정도 걸립니다. docker compose logs -f로 상태를 확인하고 에러 없이 서비스가 올라왔는지 확인하세요.


첫 접속 — 설치 화면 설정과 조직 만들기

컨테이너가 올라오면 브라우저에서 http://서버IP:3000으로 접속합니다. 첫 접속 시 설치 화면이 자동으로 나타납니다.


입력 항목에서 주의할 곳은 두 가지입니다.


  • 사이트 URL: 실제 도메인이나 IP 주소를 입력합니다. 이 값은 SSH 클론 URL, 이메일 링크 등 서비스 전체에서 사용됩니다. 나중에 변경하려면 app.iniROOT_URL을 수정하고 컨테이너를 재시작해야 합니다.
  • 데이터베이스 호스트: db:5432로 입력합니다. Docker 내부 서비스명이 db이기 때문입니다.

설치가 완료되면 관리자 계정으로 로그인합니다. 저장소를 개인 계정이 아닌 조직(Organization) 아래에 두는 것을 강력히 권장합니다. 팀원 추가·제거 시 저장소 권한이 자동으로 따라오기 때문에 관리가 훨씬 편합니다.


조직을 만들었으면 팀을 생성합니다. 기본 제공되는 오너(Owners) 팀 외에, 역할별 팀(개발자, 리뷰어)을 별도로 만들어 두면 나중에 권한 관리가 명확해집니다.


SSH 키 등록과 첫 번째 push 실전 절차

HTTPS 클론도 가능하지만, 개발 환경에서는 SSH 방식이 암호 입력 없이 push·pull을 할 수 있어 편합니다. SSH 설정은 두 단계입니다: 로컬 키 생성 → Gitea 프로필에 공개키 등록.


SSH 키 생성 및 ~/.ssh/config 설정
# 1. Ed25519 키 생성 (RSA보다 짧고 보안 수준 높음) ssh-keygen -t ed25519 -C "내 이메일" -f ~/.ssh/id_gitea # 2. 공개키 확인 (이 내용을 Gitea 프로필에 붙여넣음) cat ~/.ssh/id_gitea.pub # 3. ~/.ssh/config 에 호스트 별칭 추가 (포트 222 자동 적용) # Host gitea-server # HostName 서버IP_또는_도메인 # User git # Port 222 # IdentityFile ~/.ssh/id_gitea # 4. 연결 테스트 ssh -T git@gitea-server # "Hi 사용자명! You've successfully authenticated..." 메시지가 나오면 성공

공개키를 복사했으면 Gitea 프로필 → Settings → SSH / GPG Keys → Add Key에 붙여넣습니다. 키 타입은 자동으로 감지됩니다.


이후 저장소 클론 URL은 git@gitea-server:조직명/저장소명.git 형식을 사용합니다. 기존 로컬 저장소의 리모트를 변경하려면 아래 명령을 씁니다.


git remote set-url origin git@gitea-server:조직명/저장소명.git


SSH 키 등록 인증 설정 터미널
Ed25519 키 생성 후 공개키를 Gitea 프로필에 등록하면 암호 없이 push·pull이 가능하다

Gitea Actions로 CI 파이프라인 구성하기

Gitea는 1.19 버전부터 자체 CI 시스템인 Gitea Actions를 내장합니다. 문법이 GitHub Actions와 거의 동일해서 기존 워크플로우 파일을 대부분 수정 없이 재사용할 수 있습니다. 단, Gitea Actions는 Act Runner라는 별도 실행 에이전트가 필요합니다.


먼저 관리자 패널(사이트 관리 → 러너)에서 등록 토큰을 발급합니다. 그 다음 서버 또는 별도 머신에서 Act Runner를 실행합니다.


Act Runner — Docker로 실행
# Act Runner를 Docker로 실행 (Gitea 서버와 동일 머신 또는 별도 서버 가능) docker run -d \ --name act_runner \ --restart always \ -v /var/run/docker.sock:/var/run/docker.sock \ -v ./runner_data:/data \ -e GITEA_INSTANCE_URL=https://git.내도메인.com \ -e GITEA_RUNNER_REGISTRATION_TOKEN=관리자패널에서발급받은토큰 \ gitea/act_runner:latest # 러너 상태 확인 docker logs act_runner
.gitea/workflows/ci.yml (Node.js 예시)
name: CI on: push: branches: [ main, develop ] pull_request: branches: [ main ] jobs: test: runs-on: ubuntu-latest # Act Runner 등록 시 설정한 레이블과 일치해야 함 steps: - uses: actions/checkout@v4 - name: Node.js 설정 uses: actions/setup-node@v4 with: node-version: "20" cache: "npm" - name: 의존성 설치 run: npm ci - name: 린트 검사 run: npm run lint - name: 테스트 실행 run: npm test - name: 빌드 확인 run: npm run build

워크플로우 파일을 .gitea/workflows/ 경로에 넣고 push하면 Gitea가 자동으로 감지해 러너에 작업을 분배합니다. 관리자 패널 → 러너 메뉴에서 실행 로그를 실시간으로 확인할 수 있습니다.


GitHub Actions와의 주요 차이점은 runs-on에 지정하는 레이블입니다. 러너를 등록할 때 지정한 레이블을 워크플로우에서 정확히 써야 작업이 할당됩니다. 기본 레이블은 ubuntu-latest, windows-latest, macos-latest이며, 커스텀 레이블을 추가하면 특정 러너에만 작업을 라우팅할 수 있습니다.


⚠️ 러너와 Gitea 버전 호환성 주의
Act Runner 버전이 Gitea 버전과 맞지 않으면 워크플로우 트리거가 안 되는 경우가 있습니다. gitea/act_runner:latest 대신 Gitea 버전에 맞는 태그를 명시하는 것을 권장합니다. Gitea 1.21을 사용한다면 Act Runner 릴리즈 페이지에서 호환 버전을 확인하세요.

팀 권한 관리와 브랜치 보호 규칙 설정

Gitea의 권한은 조직 → 팀 → 저장소 계층 구조로 관리합니다. 자주 쓰는 팀 설정 패턴은 세 가지입니다.


  • 개발자 팀: 코드 읽기·쓰기, 이슈 관리, PR 머지 권한. 일반 개발자가 속하는 팀.
  • 리뷰어 팀: PR 리뷰 권한만 부여. 외부 전문가나 임시 기여자를 초대할 때 사용.
  • 봇 계정: CI 러너나 배포 스크립트용 서비스 계정. 최소 권한(읽기 전용 또는 특정 브랜치 push만)만 부여.

브랜치 보호는 저장소 Settings → Branches에서 설정합니다. main, develop 같은 주요 브랜치에 아래 규칙을 걸어두면 소규모 팀에서도 코드 품질을 유지할 수 있습니다.


  • PR을 통한 병합만 허용 (직접 push 차단)
  • 병합 전 최소 1명 승인 필수
  • CI 상태 체크 통과 필수 (Actions 워크플로우와 연결)
  • 최신 코드 기준 rebase 후 병합 필수

팀원이 3명 미만인 초기 단계라면 이 규칙들이 오히려 개발 속도를 늦출 수 있습니다. 코드베이스가 어느 정도 자리를 잡은 뒤 단계적으로 적용하는 것이 현실적입니다.


Nginx 리버스 프록시와 Let's Encrypt HTTPS 적용

인터넷에 노출된 서버라면 HTTPS가 필수입니다. Nginx를 리버스 프록시로 사용하고 Let's Encrypt 인증서를 적용합니다. 아래는 Certbot이 설치된 우분투(Ubuntu) 환경 기준 설정입니다.


/etc/nginx/sites-available/gitea.conf
server { listen 80; server_name git.내도메인.com; return 301 https://$host$request_uri; } server { listen 443 ssl http2; server_name git.내도메인.com; ssl_certificate /etc/letsencrypt/live/git.내도메인.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/git.내도메인.com/privkey.pem; ssl_session_timeout 1d; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; # 대형 파일 push 허용 (기본값 1m은 너무 작음) client_max_body_size 512m; location / { proxy_pass http://127.0.0.1:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }

설정 파일을 활성화하고 인증서를 발급합니다.


sudo ln -s /etc/nginx/sites-available/gitea.conf /etc/nginx/sites-enabled/


sudo certbot --nginx -d git.내도메인.com


HTTPS 접속이 정상이라면 Gitea의 gitea/custom/conf/app.ini에서 ROOT_URL도 HTTPS 주소로 업데이트하고, 컨테이너를 재시작합니다. 이 작업을 하지 않으면 이메일 링크와 클론 URL 안내가 여전히 HTTP로 나옵니다.


Nginx 웹서버 리버스 프록시 서버 설정
Nginx가 443 포트 HTTPS 요청을 내부 Gitea 3000 포트로 전달한다. client_max_body_size를 반드시 늘려야 대용량 push가 가능하다

백업과 마이그레이션 — 데이터를 잃지 않는 전략

자체 호스팅의 가장 큰 리스크는 데이터 손실입니다. 최소한 두 가지를 자동화해야 합니다: PostgreSQL 덤프저장소 디렉토리 백업. 아래 스크립트는 cron으로 매일 새벽 3시에 실행하고 결과물을 보관하는 패턴입니다.


backup-gitea.sh (cron 등록: 0 3 * * *)
#!/bin/bash set -e DATE=$(date +%Y%m%d) BACKUP_DIR="/backup/gitea" GITEA_DIR="/home/ubuntu/gitea" mkdir -p "$BACKUP_DIR" # 1. PostgreSQL 덤프 docker exec gitea-db-1 pg_dump -U gitea gitea | gzip > "$BACKUP_DIR/db-$DATE.sql.gz" # 2. 저장소 디렉토리 압축 (설정·저장소·첨부파일 포함) tar czf "$BACKUP_DIR/repos-$DATE.tar.gz" -C "$GITEA_DIR" . # 3. 오래된 백업 제거 (30일 초과 삭제) find "$BACKUP_DIR" -name "*.gz" -mtime +30 -delete # 4. 원격 스토리지 동기화 (선택 — rclone + Cloudflare R2 또는 AWS S3) # rclone sync "$BACKUP_DIR" r2:gitea-backup/ --max-age 30d echo "백업 완료: $DATE" # crontab -e 에 아래 줄 추가: # 0 3 * * * /home/ubuntu/backup-gitea.sh >> /var/log/gitea-backup.log 2>&1

Gitea에는 CLI로 전체 백업을 뽑는 내장 기능도 있습니다. 아래 명령은 데이터베이스·저장소·설정을 하나의 zip으로 묶어 줍니다.


docker exec -u git gitea gitea dump -c /var/lib/gitea/custom/conf/app.ini -t /tmp -o /tmp/gitea-dump.zip


복원은 gitea restore 명령을 사용합니다. 서버 이전 시에는 새 서버에 동일한 버전의 Gitea를 설치하고, 덤프 파일을 옮긴 뒤 복원 명령을 실행합니다.


깃허브에서 Gitea로 저장소를 이전할 때는 Gitea 웹 UI의 마이그레이션 기능을 사용합니다. 저장소 생성 시 "외부 저장소에서 마이그레이션" 옵션을 선택하면 이슈·PR·레이블·마일스톤까지 포함해 가져올 수 있습니다. 대규모 저장소는 API 속도 제한에 걸릴 수 있으니 깃허브 개인 액세스 토큰을 함께 입력하는 것이 안전합니다.


참고 자료

  • Gitea 공식 문서 — 설치·설정·API 레퍼런스 전체 포함. Docker 설치 가이드는 Installation 섹션에서 확인할 수 있습니다.
  • Gitea Actions 공식 문서 — GitHub Actions와의 차이점, 지원 이벤트 목록, Act Runner 설정 방법이 정리되어 있습니다.
  • Gitea GitHub 저장소 — 릴리즈 노트, 알려진 버그, 기여 가이드를 확인할 수 있습니다.

자주 묻는 질문

Gitea와 깃허브의 기능 차이가 얼마나 큰가요?

핵심 기능(저장소·브랜치·PR·이슈·위키·레이블·마일스톤)은 거의 동일합니다. 차이가 나는 부분은 크게 세 가지입니다. 첫째, GitHub Actions 마켓플레이스 규모입니다. Gitea Actions는 공식 마켓플레이스가 없어 액션을 직접 지정하거나 깃허브 마켓플레이스에서 호환 액션을 가져와야 합니다. 둘째, 코드스페이스·코파일럿 같은 깃허브 전용 부가 서비스는 사용할 수 없습니다. 셋째, 인라인 제안(suggestion) 같은 코드 리뷰 기능이 최근에야 추가됐습니다. 일반적인 팀 개발에는 부족함이 없지만, 깃허브 생태계에 깊이 의존하는 팀이라면 전환 비용을 먼저 따져보세요.


Gitea Actions가 GitHub Actions와 얼마나 호환되나요?

워크플로우 파일 문법의 약 80~90%가 호환됩니다. on 트리거, jobs, steps, uses, env, if 조건 등 핵심 구문은 동일합니다. 호환되지 않는 부분은 주로 깃허브 전용 컨텍스트 변수(github.event.inputs 일부), OIDC 토큰 기반 클라우드 인증, 깃허브 패키지 연동입니다. Node.js·파이썬 테스트 파이프라인이라면 파일을 그대로 복사해서 쓸 수 있는 경우가 많습니다.


깃허브에서 Gitea로 저장소를 통째로 이전할 수 있나요?

가능합니다. Gitea 웹 UI에서 새 저장소 생성 시 "외부 저장소에서 마이그레이션" 옵션을 선택하면 됩니다. 깃 히스토리는 물론 이슈, PR, 레이블, 마일스톤, 댓글, 리액션까지 가져올 수 있습니다. API 속도 제한을 피하려면 깃허브 개인 액세스 토큰(classic, repo 스코프)을 함께 입력하세요. 저장소 크기가 수 GB를 넘거나 이슈가 수천 개라면 시간이 꽤 걸릴 수 있으니 여유 있는 시점에 진행하는 것이 좋습니다.


소규모 팀(2~3명 미만)에도 자체 호스팅이 맞나요?

1~2인 팀이라면 자체 호스팅의 유지보수 부담이 이점보다 클 수 있습니다. 서버 패치, 백업 자동화, 인증서 갱신, 버전 업그레이드를 지속적으로 관리해야 하기 때문입니다. 아래 기준으로 판단하세요. 사내 규정상 소스코드를 외부에 두기 어렵다 → 자체 호스팅이 필수입니다. 이미 다른 서비스(Nextcloud, Nginx 등)를 위해 VPS를 운영 중이라면 Gitea 추가 비용이 거의 없으므로 고려할 수 있습니다. 서버 운영 경험이 없고 배울 여유가 없다면 깃허브를 유지하는 것이 낫습니다.


데이터베이스 백업은 얼마나 자주 해야 하나요?

팀의 커밋·이슈 생성 빈도에 따라 다르지만, 최소 하루 1회를 권장합니다. 저장소 데이터(Git 객체)보다 데이터베이스(이슈·PR·댓글)가 더 복원하기 어렵기 때문에 두 가지를 동시에 백업해야 합니다. 백업 보존 기간은 최소 30일이 안전합니다. 서버와 같은 디스크에만 보관하면 서버 장애 시 백업 자체가 소실될 수 있으니, Rclone과 클라우드 스토리지를 연동해 원격 복제를 필수로 설정하세요.


GitLab과 Gitea 중 어떤 것을 선택해야 하나요?

두 가지 기준으로 나눌 수 있습니다. 서버 자원이 제한적이거나(2GB RAM 이하), 설정의 단순함을 원한다면 Gitea를 선택합니다. GitLab CE는 최소 4GB RAM을 권장하며, 기본 설치 후 수십 개의 시스템 서비스가 올라옵니다. 반대로 내장 컨테이너 레지스트리, 패키지 레지스트리, 보안 스캐닝, 상세한 감사 로그가 필요하다면 GitLab CE가 맞습니다. 대기업 온프레미스 환경이라면 GitLab이 더 완성도 높은 엔터프라이즈 기능을 갖추고 있습니다.


Gitea깃서버셀프호스팅Docker오픈소스CI/CDNginx개발환경

관련 도구

함께 보면 좋은 문제 해결

EXPLORE / Open Source

이어서 읽어보기

전체 토픽 둘러보기