- AcademyController에 serverKnowledge() 메서드 추가 - /academy/server-knowledge 라우트 등록 - 그린 테마 Blade 뷰 (5대 섹션, 18소 섹션) - SVG 이미지 12장 생성 - 이미지 생성 프롬프트 문서 작성
1348 lines
94 KiB
PHP
1348 lines
94 KiB
PHP
@extends('layouts.app')
|
|
|
|
@section('title', '서버지식 백과사전')
|
|
|
|
@push('styles')
|
|
<style>
|
|
/* 이미지 기본 스타일 */
|
|
.academy-img-hover {
|
|
transition: box-shadow 0.2s ease;
|
|
}
|
|
.academy-img-hover:hover {
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
}
|
|
.academy-img-wrap {
|
|
overflow: hidden;
|
|
border-radius: 0.75rem;
|
|
}
|
|
|
|
/* hover 프리뷰 오버레이 */
|
|
#hover-preview {
|
|
display: none;
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: 45;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: rgba(0, 0, 0, 0.6);
|
|
backdrop-filter: blur(3px);
|
|
pointer-events: none;
|
|
}
|
|
#hover-preview.is-active {
|
|
display: flex;
|
|
pointer-events: none;
|
|
}
|
|
#hover-preview img {
|
|
max-height: 80vh;
|
|
max-width: 85vw;
|
|
border-radius: 0.75rem;
|
|
box-shadow: 0 25px 60px rgba(0, 0, 0, 0.5);
|
|
opacity: 0;
|
|
transform: scale(0.3);
|
|
transition: opacity 0.25s ease, transform 0.25s ease;
|
|
}
|
|
#hover-preview.is-active img {
|
|
opacity: 1;
|
|
transform: scale(1);
|
|
}
|
|
#hover-preview .hover-caption {
|
|
position: absolute;
|
|
bottom: 2rem;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
color: rgba(255,255,255,0.85);
|
|
font-size: 0.8rem;
|
|
background: rgba(0,0,0,0.5);
|
|
padding: 0.4rem 1rem;
|
|
border-radius: 2rem;
|
|
white-space: nowrap;
|
|
opacity: 0;
|
|
transition: opacity 0.3s ease 0.15s;
|
|
}
|
|
#hover-preview.is-active .hover-caption {
|
|
opacity: 1;
|
|
}
|
|
|
|
/* 클릭 라이트박스 */
|
|
#lightbox {
|
|
display: none;
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: 50;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: rgba(0, 0, 0, 0.9);
|
|
backdrop-filter: blur(4px);
|
|
}
|
|
#lightbox.is-open {
|
|
display: flex;
|
|
}
|
|
#lightbox img {
|
|
max-height: 90vh;
|
|
max-width: 90vw;
|
|
border-radius: 0.5rem;
|
|
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.5);
|
|
}
|
|
|
|
/* 타임라인 스타일 */
|
|
.timeline-item {
|
|
position: relative;
|
|
padding-left: 2rem;
|
|
padding-bottom: 1.5rem;
|
|
}
|
|
.timeline-item:not(:last-child)::before {
|
|
content: '';
|
|
position: absolute;
|
|
left: 0.5rem;
|
|
top: 1.5rem;
|
|
bottom: 0;
|
|
width: 2px;
|
|
background: #d1d5db;
|
|
}
|
|
.timeline-item .timeline-dot {
|
|
position: absolute;
|
|
left: 0;
|
|
top: 0.25rem;
|
|
width: 1.25rem;
|
|
height: 1.25rem;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 0.65rem;
|
|
font-weight: bold;
|
|
color: white;
|
|
}
|
|
</style>
|
|
@endpush
|
|
|
|
@section('content')
|
|
<div class="max-w-6xl mx-auto">
|
|
|
|
<!-- 히어로 배너 -->
|
|
<div class="rounded-2xl overflow-hidden mb-8 shadow-lg" style="background: linear-gradient(135deg, #1a3a2a 0%, #0f172a 100%);">
|
|
<div class="flex items-center" style="flex-wrap: wrap;">
|
|
<div style="flex: 1 1 300px; padding: 2rem 2.5rem;">
|
|
<div class="flex items-center gap-2 text-sm mb-2" style="color: #86efac;">
|
|
<span>아카데미</span>
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" /></svg>
|
|
<span style="color: #ffffff;">서버지식</span>
|
|
</div>
|
|
<h1 class="text-3xl font-bold mb-2" style="color: #ffffff;">서버지식 백과사전</h1>
|
|
<p class="text-sm" style="color: #cbd5e1;">서버 협업에 필요한 핵심 지식 — 비개발자도 이해할 수 있는 실전 가이드</p>
|
|
</div>
|
|
<div class="shrink-0" style="width: 240px; padding: 1.5rem;">
|
|
<div class="overflow-hidden rounded-xl">
|
|
<img src="{{ asset('images/academy/server-knowledge/1.svg') }}" alt="서버실과 사용자 연결 일러스트"
|
|
class="w-full rounded-xl cursor-pointer academy-img-hover"
|
|
onclick="openLightbox(this)">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex gap-8">
|
|
<!-- 좌측 고정 목차 (TOC) -->
|
|
<nav class="hidden lg:block shrink-0" style="width: 220px;">
|
|
<div class="sticky top-24">
|
|
<div class="bg-green-50 border border-green-200 rounded-xl p-5">
|
|
<h2 class="font-semibold text-green-800 mb-3 flex items-center gap-2 text-sm">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 10h16M4 14h16M4 18h16" /></svg>
|
|
목차
|
|
</h2>
|
|
<div class="space-y-0.5 text-xs">
|
|
<a href="#server" class="block text-green-700 hover:text-green-900 py-1 font-medium">1. 서버란 무엇인가</a>
|
|
<a href="#server-definition" class="block text-green-600 hover:text-green-800 py-0.5 pl-3">서버의 정의</a>
|
|
<a href="#server-structure" class="block text-green-600 hover:text-green-800 py-0.5 pl-3">SAM 서버 구조</a>
|
|
<a href="#server-request" class="block text-green-600 hover:text-green-800 py-0.5 pl-3">요청의 여정</a>
|
|
|
|
<a href="#permission" class="block text-green-700 hover:text-green-900 py-1 font-medium mt-2">2. 파일 권한과 소유자</a>
|
|
<a href="#permission-user" class="block text-green-600 hover:text-green-800 py-0.5 pl-3">사용자와 그룹</a>
|
|
<a href="#permission-rwx" class="block text-green-600 hover:text-green-800 py-0.5 pl-3">파일 권한 읽기</a>
|
|
<a href="#permission-umask" class="block text-green-600 hover:text-green-800 py-0.5 pl-3">umask란</a>
|
|
<a href="#permission-incident" class="block text-green-600 hover:text-green-800 py-0.5 pl-3">실전 사고 사례</a>
|
|
|
|
<a href="#git" class="block text-green-700 hover:text-green-900 py-1 font-medium mt-2">3. Git과 배포의 원리</a>
|
|
<a href="#git-what" class="block text-green-600 hover:text-green-800 py-0.5 pl-3">Git이 하는 일</a>
|
|
<a href="#git-push" class="block text-green-600 hover:text-green-800 py-0.5 pl-3">push → 서버 반영</a>
|
|
<a href="#git-hook" class="block text-green-600 hover:text-green-800 py-0.5 pl-3">자동 배포 Hook</a>
|
|
<a href="#git-broken" class="block text-green-600 hover:text-green-800 py-0.5 pl-3">배포가 깨지는 이유</a>
|
|
|
|
<a href="#rules" class="block text-green-700 hover:text-green-900 py-1 font-medium mt-2">4. 서버 협업 필수 규칙</a>
|
|
<a href="#rules-forbidden" class="block text-green-600 hover:text-green-800 py-0.5 pl-3">절대 하면 안 되는 것</a>
|
|
<a href="#rules-chown" class="block text-green-600 hover:text-green-800 py-0.5 pl-3">소유자 변경 위험</a>
|
|
<a href="#rules-procedure" class="block text-green-600 hover:text-green-800 py-0.5 pl-3">올바른 절차</a>
|
|
<a href="#rules-checklist" class="block text-green-600 hover:text-green-800 py-0.5 pl-3">긴급 체크리스트</a>
|
|
|
|
<a href="#commands" class="block text-green-700 hover:text-green-900 py-1 font-medium mt-2">5. 핵심 명령어 사전</a>
|
|
<a href="#commands-safe" class="block text-green-600 hover:text-green-800 py-0.5 pl-3">안전한 명령어</a>
|
|
<a href="#commands-danger" class="block text-green-600 hover:text-green-800 py-0.5 pl-3">위험한 명령어</a>
|
|
<a href="#commands-faq" class="block text-green-600 hover:text-green-800 py-0.5 pl-3">FAQ</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<!-- 우측 콘텐츠 -->
|
|
<div class="flex-1 min-w-0 space-y-10">
|
|
|
|
<!-- 모바일 목차 -->
|
|
<div class="lg:hidden bg-green-50 border border-green-200 rounded-xl p-4 mb-6">
|
|
<details>
|
|
<summary class="font-semibold text-green-800 text-sm cursor-pointer flex items-center gap-2">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 10h16M4 14h16M4 18h16" /></svg>
|
|
목차 보기
|
|
</summary>
|
|
<nav class="mt-3 space-y-1 text-sm">
|
|
<a href="#server" class="block text-green-700 hover:text-green-900 py-1">1. 서버란 무엇인가</a>
|
|
<a href="#permission" class="block text-green-700 hover:text-green-900 py-1">2. 파일 권한과 소유자</a>
|
|
<a href="#git" class="block text-green-700 hover:text-green-900 py-1">3. Git과 배포의 원리</a>
|
|
<a href="#rules" class="block text-green-700 hover:text-green-900 py-1">4. 서버 협업 필수 규칙</a>
|
|
<a href="#commands" class="block text-green-700 hover:text-green-900 py-1">5. 핵심 명령어 사전</a>
|
|
</nav>
|
|
</details>
|
|
</div>
|
|
|
|
{{-- ============================================================ --}}
|
|
{{-- 1. 서버란 무엇인가 --}}
|
|
{{-- ============================================================ --}}
|
|
<section id="server" class="scroll-mt-20">
|
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
|
|
<h2 class="text-xl font-bold text-gray-800 mb-6 flex items-center gap-3">
|
|
<span class="w-8 h-8 bg-green-500 text-white rounded-lg flex items-center justify-center text-sm font-bold">1</span>
|
|
서버란 무엇인가
|
|
</h2>
|
|
|
|
<!-- 1-1. 서버의 정의 -->
|
|
<div id="server-definition" class="scroll-mt-20 mb-8">
|
|
<h3 class="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
|
|
<span class="w-2 h-2 bg-green-400 rounded-full"></span>
|
|
서버의 정의
|
|
</h3>
|
|
<div class="bg-green-50 rounded-lg p-5 border border-green-100 mb-4">
|
|
<p class="text-sm text-green-900 leading-relaxed">
|
|
<strong>서버(Server)</strong>란 네트워크를 통해 다른 컴퓨터(클라이언트)에게 서비스를 제공하는 컴퓨터다.
|
|
우리가 웹 브라우저에서 주소를 입력하면, 그 요청을 받아 처리하고 결과를 돌려주는 역할을 한다.
|
|
</p>
|
|
</div>
|
|
<div class="text-sm text-gray-700 space-y-3">
|
|
<div class="bg-amber-50 rounded-lg p-4 border border-amber-100">
|
|
<p class="font-semibold text-amber-800 mb-2">비유: 24시간 영업하는 식당</p>
|
|
<p class="text-xs text-amber-900 leading-relaxed">
|
|
서버는 <strong>24시간 문을 닫지 않는 식당</strong>과 같다. 손님(사용자)이 언제 와도 주문(요청)을 받고, 요리(처리)해서 내놓는다(응답).
|
|
식당이 문을 닫으면 손님이 밥을 못 먹듯, 서버가 꺼지면 웹사이트에 접속할 수 없다.
|
|
</p>
|
|
</div>
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-3 text-xs">
|
|
<div class="bg-gray-50 rounded-lg p-3 border text-center">
|
|
<p class="font-bold text-gray-800 mb-1">일반 PC</p>
|
|
<p class="text-gray-500">내가 사용하는 컴퓨터<br>필요할 때만 켠다</p>
|
|
</div>
|
|
<div class="bg-green-50 rounded-lg p-3 border border-green-200 text-center">
|
|
<p class="font-bold text-green-800 mb-1">서버</p>
|
|
<p class="text-green-700">다른 사람에게 서비스 제공<br>365일 24시간 가동</p>
|
|
</div>
|
|
<div class="bg-gray-50 rounded-lg p-3 border text-center">
|
|
<p class="font-bold text-gray-800 mb-1">클라이언트</p>
|
|
<p class="text-gray-500">서버에 요청하는 쪽<br>웹 브라우저, 앱 등</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 1-2. SAM 서버 구조 -->
|
|
<div id="server-structure" class="scroll-mt-20 mb-8">
|
|
<h3 class="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
|
|
<span class="w-2 h-2 bg-green-400 rounded-full"></span>
|
|
SAM 서버 구조
|
|
</h3>
|
|
<div class="flex flex-col lg:flex-row gap-5 items-start mb-4">
|
|
<div class="flex-1 min-w-0 text-sm text-gray-700 space-y-3">
|
|
<div class="bg-amber-50 rounded-lg p-4 border border-amber-100 mb-3">
|
|
<p class="font-semibold text-amber-800 mb-2">비유: 하나의 건물에 5개 가게 입점</p>
|
|
<p class="text-xs text-amber-900 leading-relaxed">
|
|
SAM 서버는 <strong>하나의 건물(서버 컴퓨터)</strong>에 여러 가게(서비스)가 입점한 것과 같다.
|
|
각 가게는 독립적으로 운영되지만, 건물의 전기(CPU)와 수도(메모리)를 공유한다.
|
|
</p>
|
|
</div>
|
|
<div class="mb-5 bg-gray-50 rounded-xl p-4 border flex justify-center academy-img-wrap">
|
|
<img src="{{ asset('images/academy/server-knowledge/2.svg') }}" alt="SAM 5개 서비스 건물 지도"
|
|
class="rounded-lg cursor-pointer academy-img-hover"
|
|
style="max-height: 280px; width: auto;"
|
|
onclick="openLightbox(this)">
|
|
</div>
|
|
<p class="text-xs text-gray-400 mb-4 text-center">SAM 서버 구조 — 건물 지도</p>
|
|
</div>
|
|
</div>
|
|
<div class="overflow-x-auto">
|
|
<table class="w-full text-sm border-collapse">
|
|
<thead>
|
|
<tr class="border-b-2 border-gray-200 bg-gray-50">
|
|
<th class="text-left py-2 px-3 font-medium text-gray-600">서비스</th>
|
|
<th class="text-left py-2 px-3 font-medium text-gray-600">비유</th>
|
|
<th class="text-left py-2 px-3 font-medium text-gray-600">역할</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="text-xs text-gray-700">
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-medium">Nginx</td>
|
|
<td class="py-2 px-3">입구 안내 데스크</td>
|
|
<td class="py-2 px-3">요청을 받아 적절한 서비스로 안내</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-medium">PHP-FPM</td>
|
|
<td class="py-2 px-3">요리사 팀</td>
|
|
<td class="py-2 px-3">실제 코드를 실행하여 결과를 만들어냄</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-medium">MySQL</td>
|
|
<td class="py-2 px-3">냉장고 (재료 창고)</td>
|
|
<td class="py-2 px-3">데이터를 저장하고 꺼내주는 데이터베이스</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-medium">MNG</td>
|
|
<td class="py-2 px-3">관리자 사무실</td>
|
|
<td class="py-2 px-3">직원들이 사용하는 관리 화면</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-medium">API</td>
|
|
<td class="py-2 px-3">택배 발송실</td>
|
|
<td class="py-2 px-3">앱/외부에 데이터를 전달하는 백엔드</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 1-3. 요청의 여정 -->
|
|
<div id="server-request" class="scroll-mt-20 mb-4">
|
|
<h3 class="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
|
|
<span class="w-2 h-2 bg-green-400 rounded-full"></span>
|
|
요청의 여정
|
|
</h3>
|
|
<p class="text-sm text-gray-700 mb-4">
|
|
사용자가 웹 브라우저에 <code class="bg-gray-100 px-1.5 py-0.5 rounded text-xs">https://sam.jooil.co.kr</code> 을 입력하면 어떤 일이 벌어지는지 따라가보자.
|
|
</p>
|
|
<div class="mb-5 bg-gray-50 rounded-xl p-4 border flex justify-center academy-img-wrap">
|
|
<img src="{{ asset('images/academy/server-knowledge/3.svg') }}" alt="요청 흐름도: 브라우저→Nginx→PHP→DB"
|
|
class="rounded-lg cursor-pointer academy-img-hover"
|
|
style="max-height: 280px; width: auto;"
|
|
onclick="openLightbox(this)">
|
|
</div>
|
|
<p class="text-xs text-gray-400 mb-4 text-center">요청의 여정 — URL 입력부터 화면 표시까지</p>
|
|
<div class="grid grid-cols-1 md:grid-cols-5 gap-2 text-xs">
|
|
<div class="bg-blue-50 rounded-lg p-3 border border-blue-100 text-center">
|
|
<p class="font-bold text-blue-700 text-sm mb-1">1</p>
|
|
<p class="font-semibold text-gray-800">URL 입력</p>
|
|
<p class="text-gray-500 mt-1">브라우저가 서버에 요청 전송</p>
|
|
</div>
|
|
<div class="bg-purple-50 rounded-lg p-3 border border-purple-100 text-center">
|
|
<p class="font-bold text-purple-700 text-sm mb-1">2</p>
|
|
<p class="font-semibold text-gray-800">Nginx 수신</p>
|
|
<p class="text-gray-500 mt-1">안내 데스크가 요청을 분류</p>
|
|
</div>
|
|
<div class="bg-orange-50 rounded-lg p-3 border border-orange-100 text-center">
|
|
<p class="font-bold text-orange-700 text-sm mb-1">3</p>
|
|
<p class="font-semibold text-gray-800">PHP 처리</p>
|
|
<p class="text-gray-500 mt-1">요리사가 코드를 실행</p>
|
|
</div>
|
|
<div class="bg-green-50 rounded-lg p-3 border border-green-100 text-center">
|
|
<p class="font-bold text-green-700 text-sm mb-1">4</p>
|
|
<p class="font-semibold text-gray-800">DB 조회</p>
|
|
<p class="text-gray-500 mt-1">냉장고에서 재료(데이터) 꺼냄</p>
|
|
</div>
|
|
<div class="bg-teal-50 rounded-lg p-3 border border-teal-100 text-center">
|
|
<p class="font-bold text-teal-700 text-sm mb-1">5</p>
|
|
<p class="font-semibold text-gray-800">화면 표시</p>
|
|
<p class="text-gray-500 mt-1">완성된 페이지를 브라우저에 전달</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{{-- ============================================================ --}}
|
|
{{-- 2. 파일 권한과 소유자 (핵심!) --}}
|
|
{{-- ============================================================ --}}
|
|
<section id="permission" class="scroll-mt-20">
|
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
|
|
<h2 class="text-xl font-bold text-gray-800 mb-6 flex items-center gap-3">
|
|
<span class="w-8 h-8 bg-green-500 text-white rounded-lg flex items-center justify-center text-sm font-bold">2</span>
|
|
파일 권한과 소유자
|
|
<span class="text-xs bg-red-100 text-red-700 px-2 py-0.5 rounded-full font-medium">핵심!</span>
|
|
</h2>
|
|
|
|
<!-- 2-1. 사용자와 그룹 -->
|
|
<div id="permission-user" class="scroll-mt-20 mb-8">
|
|
<h3 class="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
|
|
<span class="w-2 h-2 bg-green-400 rounded-full"></span>
|
|
사용자와 그룹
|
|
</h3>
|
|
<div class="bg-amber-50 rounded-lg p-4 border border-amber-100 mb-4">
|
|
<p class="font-semibold text-amber-800 mb-2">비유: 회사 직원과 부서</p>
|
|
<p class="text-xs text-amber-900 leading-relaxed">
|
|
Linux에서 <strong>사용자(User)</strong>는 회사의 직원, <strong>그룹(Group)</strong>은 부서와 같다.
|
|
한 직원이 여러 부서에 소속될 수 있듯, 한 사용자도 여러 그룹에 속할 수 있다.
|
|
</p>
|
|
</div>
|
|
<div class="flex flex-col lg:flex-row gap-5 items-start">
|
|
<div class="shrink-0 bg-gray-50 rounded-xl p-3 border academy-img-wrap" style="width: 240px;">
|
|
<img src="{{ asset('images/academy/server-knowledge/4.svg') }}" alt="Linux 사용자/그룹 = 회사 조직도"
|
|
class="w-full rounded-lg cursor-pointer academy-img-hover"
|
|
onclick="openLightbox(this)">
|
|
<p class="text-xs text-gray-400 mt-2 text-center">사용자와 그룹 — 회사 조직도</p>
|
|
</div>
|
|
<div class="flex-1 min-w-0 text-sm text-gray-700 space-y-3">
|
|
<div class="overflow-x-auto">
|
|
<table class="w-full text-sm border-collapse">
|
|
<thead>
|
|
<tr class="border-b-2 border-gray-200 bg-gray-50">
|
|
<th class="text-left py-2 px-3 font-medium text-gray-600">Linux</th>
|
|
<th class="text-left py-2 px-3 font-medium text-gray-600">회사 비유</th>
|
|
<th class="text-left py-2 px-3 font-medium text-gray-600">SAM에서의 역할</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="text-xs text-gray-700">
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-mono font-medium">root</td>
|
|
<td class="py-2 px-3">건물 관리인 (만능 열쇠)</td>
|
|
<td class="py-2 px-3">시스템 최고 관리자. 모든 권한 보유</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-mono font-medium">pro</td>
|
|
<td class="py-2 px-3">팀장 (개발팀 사무실 열쇠)</td>
|
|
<td class="py-2 px-3">배포/관리 담당. SSH 접속 계정</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-mono font-medium">www-data</td>
|
|
<td class="py-2 px-3">업무 처리 직원 (작업실 열쇠)</td>
|
|
<td class="py-2 px-3">웹 서버(Nginx/PHP)가 사용하는 계정</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div class="bg-red-50 rounded-lg p-3 border border-red-100">
|
|
<p class="text-xs text-red-700">
|
|
<strong>중요!</strong> <code class="bg-red-100 px-1 rounded">pro</code>와 <code class="bg-red-100 px-1 rounded">www-data</code>가 같은 그룹에 있어야 서로의 파일을 읽고 쓸 수 있다.
|
|
그룹이 다르면 "열쇠가 안 맞아서 사무실에 못 들어가는" 상황이 발생한다.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 2-2. 파일 권한 읽기 (rwx) -->
|
|
<div id="permission-rwx" class="scroll-mt-20 mb-8">
|
|
<h3 class="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
|
|
<span class="w-2 h-2 bg-green-400 rounded-full"></span>
|
|
파일 권한 읽기 (rwx)
|
|
</h3>
|
|
<p class="text-sm text-gray-700 mb-4">
|
|
Linux에서 <code class="bg-gray-100 px-1.5 py-0.5 rounded text-xs">ls -la</code> 명령을 실행하면 이런 문자열이 보인다:
|
|
</p>
|
|
<div class="bg-gray-900 rounded-lg p-4 mb-4 overflow-x-auto">
|
|
<code class="text-green-400 text-sm font-mono">drwxrwxr-x 2 pro www-data 4096 Feb 23 10:00 storage</code>
|
|
</div>
|
|
<div class="mb-5 bg-gray-50 rounded-xl p-4 border flex justify-center academy-img-wrap">
|
|
<img src="{{ asset('images/academy/server-knowledge/5.svg') }}" alt="drwxrwxr-x 해독 인포그래픽"
|
|
class="rounded-lg cursor-pointer academy-img-hover"
|
|
style="max-height: 280px; width: auto;"
|
|
onclick="openLightbox(this)">
|
|
</div>
|
|
<p class="text-xs text-gray-400 mb-4 text-center">권한 문자열 해독법</p>
|
|
<div class="text-sm text-gray-700 space-y-3">
|
|
<div class="bg-amber-50 rounded-lg p-4 border border-amber-100 mb-3">
|
|
<p class="font-semibold text-amber-800 mb-2">비유: 서류함의 스티커</p>
|
|
<p class="text-xs text-amber-900 leading-relaxed">
|
|
파일에 붙은 권한은 <strong>서류함에 붙은 스티커</strong>와 같다.
|
|
<strong>r</strong>(Read) = 열람 가능, <strong>w</strong>(Write) = 수정 가능, <strong>x</strong>(Execute) = 사용/실행 가능.
|
|
스티커가 없으면 해당 행위가 불가능하다.
|
|
</p>
|
|
</div>
|
|
<div class="overflow-x-auto">
|
|
<table class="w-full text-sm border-collapse">
|
|
<thead>
|
|
<tr class="border-b-2 border-gray-200 bg-gray-50">
|
|
<th class="text-left py-2 px-3 font-medium text-gray-600">위치</th>
|
|
<th class="text-left py-2 px-3 font-medium text-gray-600">문자</th>
|
|
<th class="text-left py-2 px-3 font-medium text-gray-600">의미</th>
|
|
<th class="text-left py-2 px-3 font-medium text-gray-600">비유</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="text-xs text-gray-700">
|
|
<tr class="border-b border-gray-100 bg-blue-50">
|
|
<td class="py-2 px-3 font-mono font-bold">1번째</td>
|
|
<td class="py-2 px-3 font-mono">d</td>
|
|
<td class="py-2 px-3">디렉토리(폴더)</td>
|
|
<td class="py-2 px-3">서류함 vs 서류 한 장</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100 bg-green-50">
|
|
<td class="py-2 px-3 font-mono font-bold">2~4번째</td>
|
|
<td class="py-2 px-3 font-mono">rwx</td>
|
|
<td class="py-2 px-3">소유자(Owner) 권한</td>
|
|
<td class="py-2 px-3">서류함 담당자: 열람+수정+사용</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100 bg-yellow-50">
|
|
<td class="py-2 px-3 font-mono font-bold">5~7번째</td>
|
|
<td class="py-2 px-3 font-mono">rwx</td>
|
|
<td class="py-2 px-3">그룹(Group) 권한</td>
|
|
<td class="py-2 px-3">같은 부서 직원: 열람+수정+사용</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100 bg-red-50">
|
|
<td class="py-2 px-3 font-mono font-bold">8~10번째</td>
|
|
<td class="py-2 px-3 font-mono">r-x</td>
|
|
<td class="py-2 px-3">기타(Others) 권한</td>
|
|
<td class="py-2 px-3">다른 부서 직원: 열람+사용만 가능</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div class="bg-green-50 rounded-lg p-4 border border-green-100">
|
|
<p class="font-semibold text-green-800 mb-2 text-sm">숫자로 표현하기</p>
|
|
<p class="text-xs text-green-700 mb-2">각 권한을 숫자로 환산: <strong>r=4, w=2, x=1</strong></p>
|
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-2 text-xs">
|
|
<div class="bg-white rounded-lg p-2 border text-center">
|
|
<p class="font-mono font-bold text-gray-800">rwx = 7</p>
|
|
<p class="text-gray-500">4+2+1</p>
|
|
</div>
|
|
<div class="bg-white rounded-lg p-2 border text-center">
|
|
<p class="font-mono font-bold text-gray-800">rw- = 6</p>
|
|
<p class="text-gray-500">4+2+0</p>
|
|
</div>
|
|
<div class="bg-white rounded-lg p-2 border text-center">
|
|
<p class="font-mono font-bold text-gray-800">r-x = 5</p>
|
|
<p class="text-gray-500">4+0+1</p>
|
|
</div>
|
|
<div class="bg-white rounded-lg p-2 border text-center">
|
|
<p class="font-mono font-bold text-gray-800">r-- = 4</p>
|
|
<p class="text-gray-500">4+0+0</p>
|
|
</div>
|
|
</div>
|
|
<p class="text-xs text-green-700 mt-2">따라서 <code class="bg-green-100 px-1 rounded">rwxrwxr-x</code> = <strong>775</strong>, <code class="bg-green-100 px-1 rounded">rw-r--r--</code> = <strong>644</strong></p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 2-3. umask란 무엇인가 -->
|
|
<div id="permission-umask" class="scroll-mt-20 mb-8">
|
|
<h3 class="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
|
|
<span class="w-2 h-2 bg-green-400 rounded-full"></span>
|
|
umask란 무엇인가
|
|
</h3>
|
|
<div class="bg-amber-50 rounded-lg p-4 border border-amber-100 mb-4">
|
|
<p class="font-semibold text-amber-800 mb-2">비유: 새 서류 만들 때 기본 스티커</p>
|
|
<p class="text-xs text-amber-900 leading-relaxed">
|
|
<strong>umask</strong>는 새 파일/폴더를 만들 때 <strong>기본적으로 어떤 권한을 빼는지</strong> 정하는 설정이다.
|
|
신입 직원이 서류를 만들면 회사 규정상 기본 스티커가 자동으로 붙는 것과 같다.
|
|
</p>
|
|
</div>
|
|
<div class="flex flex-col lg:flex-row gap-5 items-start mb-4">
|
|
<div class="shrink-0 bg-gray-50 rounded-xl p-3 border academy-img-wrap" style="width: 260px;">
|
|
<img src="{{ asset('images/academy/server-knowledge/6.svg') }}" alt="umask 계산법: 666 - 022 = 644"
|
|
class="w-full rounded-lg cursor-pointer academy-img-hover"
|
|
onclick="openLightbox(this)">
|
|
<p class="text-xs text-gray-400 mt-2 text-center">umask 계산 과정</p>
|
|
</div>
|
|
<div class="flex-1 min-w-0 text-sm text-gray-700 space-y-3">
|
|
<p><strong>계산법:</strong> 기본 권한에서 umask를 빼면 실제 권한이 된다.</p>
|
|
<div class="bg-gray-900 rounded-lg p-4 overflow-x-auto">
|
|
<pre class="text-green-400 text-xs font-mono leading-relaxed">파일 기본값: 666 (rw-rw-rw-)
|
|
umask 값: - 022 (----w--w-)
|
|
─────────────────────────
|
|
실제 권한: 644 (rw-r--r--)
|
|
|
|
폴더 기본값: 777 (rwxrwxrwx)
|
|
umask 값: - 022 (----w--w-)
|
|
─────────────────────────
|
|
실제 권한: 755 (rwxr-xr-x)</pre>
|
|
</div>
|
|
<div class="bg-red-50 rounded-lg p-3 border border-red-100">
|
|
<p class="text-xs text-red-700">
|
|
<strong>문제가 되는 경우:</strong> umask가 <code class="bg-red-100 px-1 rounded">022</code>이면 새 파일의 그룹 쓰기 권한이 빠진다.
|
|
즉 <code class="bg-red-100 px-1 rounded">pro</code> 계정이 만든 파일을 <code class="bg-red-100 px-1 rounded">www-data</code>가 수정할 수 없게 된다!
|
|
</p>
|
|
</div>
|
|
<div class="bg-green-50 rounded-lg p-3 border border-green-100">
|
|
<p class="text-xs text-green-700">
|
|
<strong>해결책:</strong> umask를 <code class="bg-green-100 px-1 rounded">002</code>로 설정하면 그룹 쓰기 권한이 유지된다.
|
|
666 - 002 = <strong>664</strong> (rw-rw-r--) → 같은 그룹이면 서로 수정 가능!
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 2-4. 실전 사고 사례 -->
|
|
<div id="permission-incident" class="scroll-mt-20 mb-4">
|
|
<h3 class="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
|
|
<span class="w-2 h-2 bg-green-400 rounded-full"></span>
|
|
실전 사고 사례
|
|
<span class="text-xs bg-red-100 text-red-700 px-2 py-0.5 rounded-full font-medium">2026-02-23</span>
|
|
</h3>
|
|
<div class="bg-red-50 rounded-lg p-4 border border-red-200 mb-4">
|
|
<p class="text-sm text-red-800 font-semibold mb-1">umask 사고 — 자동 배포 실패</p>
|
|
<p class="text-xs text-red-700 leading-relaxed">
|
|
개발팀장이 서버 폴더 권한을 조정한 후, 자동 배포가 실패한 사건.
|
|
비개발자인 대표가 원인을 파악할 수 없었던 실제 사례다.
|
|
</p>
|
|
</div>
|
|
<div class="mb-5 bg-gray-50 rounded-xl p-4 border flex justify-center academy-img-wrap">
|
|
<img src="{{ asset('images/academy/server-knowledge/7.svg') }}" alt="사고 타임라인 5단계"
|
|
class="rounded-lg cursor-pointer academy-img-hover"
|
|
style="max-height: 280px; width: auto;"
|
|
onclick="openLightbox(this)">
|
|
</div>
|
|
<p class="text-xs text-gray-400 mb-4 text-center">사고 타임라인 — 5단계</p>
|
|
|
|
<!-- 타임라인 -->
|
|
<div class="pl-2 mb-4">
|
|
<div class="timeline-item">
|
|
<div class="timeline-dot bg-blue-500">1</div>
|
|
<div class="bg-blue-50 rounded-lg p-3 border border-blue-100">
|
|
<p class="text-xs font-semibold text-blue-800">폴더 권한 변경</p>
|
|
<p class="text-xs text-blue-700 mt-1">팀장이 <code class="bg-blue-100 px-1 rounded">chmod</code>로 폴더 권한을 조정. 목적: 보안 강화</p>
|
|
</div>
|
|
</div>
|
|
<div class="timeline-item">
|
|
<div class="timeline-dot bg-yellow-500">2</div>
|
|
<div class="bg-yellow-50 rounded-lg p-3 border border-yellow-100">
|
|
<p class="text-xs font-semibold text-yellow-800">umask 영향 시작</p>
|
|
<p class="text-xs text-yellow-700 mt-1">계정의 umask(022)가 적용되어 새로 생성되는 파일의 그룹 쓰기 권한 제거</p>
|
|
</div>
|
|
</div>
|
|
<div class="timeline-item">
|
|
<div class="timeline-dot bg-orange-500">3</div>
|
|
<div class="bg-orange-50 rounded-lg p-3 border border-orange-100">
|
|
<p class="text-xs font-semibold text-orange-800">git pull 실행</p>
|
|
<p class="text-xs text-orange-700 mt-1">자동 배포 스크립트(Hook)가 <code class="bg-orange-100 px-1 rounded">git pull</code> 실행. 새 파일들이 644 권한으로 생성됨</p>
|
|
</div>
|
|
</div>
|
|
<div class="timeline-item">
|
|
<div class="timeline-dot bg-red-400">4</div>
|
|
<div class="bg-red-50 rounded-lg p-3 border border-red-100">
|
|
<p class="text-xs font-semibold text-red-800">Permission Denied 발생</p>
|
|
<p class="text-xs text-red-700 mt-1"><code class="bg-red-100 px-1 rounded">www-data</code>(웹 서버)가 새 파일을 읽기는 되지만 쓰기 불가. 캐시/로그 작성 실패</p>
|
|
</div>
|
|
</div>
|
|
<div class="timeline-item">
|
|
<div class="timeline-dot bg-red-600">5</div>
|
|
<div class="bg-red-50 rounded-lg p-3 border border-red-200">
|
|
<p class="text-xs font-semibold text-red-900">배포 실패 — 서비스 장애</p>
|
|
<p class="text-xs text-red-700 mt-1">사용자들이 페이지 접속 시 오류 발생. 대표는 "무엇이 잘못됐는지" 파악 불가</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bg-green-50 rounded-lg p-4 border border-green-100">
|
|
<p class="font-semibold text-green-800 mb-2 text-sm">교훈</p>
|
|
<ul class="text-xs text-green-700 space-y-1 list-disc list-inside">
|
|
<li>서버 권한 변경은 <strong>반드시 영향 범위를 확인</strong>한 후 실행해야 한다</li>
|
|
<li>umask 설정이 배포 전체에 연쇄적으로 영향을 준다</li>
|
|
<li>비개발자도 기본 원리를 알아야 "무엇이 잘못됐는지" 파악할 수 있다</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{{-- ============================================================ --}}
|
|
{{-- 3. Git과 배포의 원리 --}}
|
|
{{-- ============================================================ --}}
|
|
<section id="git" class="scroll-mt-20">
|
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
|
|
<h2 class="text-xl font-bold text-gray-800 mb-6 flex items-center gap-3">
|
|
<span class="w-8 h-8 bg-green-500 text-white rounded-lg flex items-center justify-center text-sm font-bold">3</span>
|
|
Git과 배포의 원리
|
|
</h2>
|
|
|
|
<!-- 3-1. Git이 하는 일 -->
|
|
<div id="git-what" class="scroll-mt-20 mb-8">
|
|
<h3 class="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
|
|
<span class="w-2 h-2 bg-green-400 rounded-full"></span>
|
|
Git이 하는 일
|
|
</h3>
|
|
<div class="bg-amber-50 rounded-lg p-4 border border-amber-100 mb-4">
|
|
<p class="font-semibold text-amber-800 mb-2">비유: 구글 드라이브 버전 기록</p>
|
|
<p class="text-xs text-amber-900 leading-relaxed">
|
|
<strong>Git</strong>은 코드의 <strong>변경 이력을 기록하는 시스템</strong>이다.
|
|
구글 드라이브에서 "버전 기록"을 클릭하면 과거 버전을 볼 수 있듯,
|
|
Git은 코드의 모든 변경 사항을 기록하고 필요하면 과거로 되돌릴 수 있다.
|
|
</p>
|
|
</div>
|
|
<div class="text-sm text-gray-700 space-y-3">
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-3 text-xs">
|
|
<div class="bg-gray-50 rounded-lg p-3 border text-center">
|
|
<p class="font-bold text-gray-800 mb-1">구글 드라이브</p>
|
|
<p class="text-gray-500">파일 하나의 버전 관리<br>자동 저장</p>
|
|
</div>
|
|
<div class="bg-green-50 rounded-lg p-3 border border-green-200 text-center">
|
|
<p class="font-bold text-green-800 mb-1">Git</p>
|
|
<p class="text-green-700">프로젝트 전체의 버전 관리<br>의도적으로 저장(commit)</p>
|
|
</div>
|
|
<div class="bg-gray-50 rounded-lg p-3 border text-center">
|
|
<p class="font-bold text-gray-800 mb-1">Gitea</p>
|
|
<p class="text-gray-500">Git 저장소 호스팅<br>(GitHub의 자체 버전)</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 3-2. git push → 서버 반영 -->
|
|
<div id="git-push" class="scroll-mt-20 mb-8">
|
|
<h3 class="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
|
|
<span class="w-2 h-2 bg-green-400 rounded-full"></span>
|
|
git push → 서버 반영
|
|
</h3>
|
|
<div class="bg-amber-50 rounded-lg p-4 border border-amber-100 mb-4">
|
|
<p class="font-semibold text-amber-800 mb-2">비유: 우체국 택배 시스템</p>
|
|
<p class="text-xs text-amber-900 leading-relaxed">
|
|
코드를 수정하고 <code class="bg-amber-100 px-1 rounded">git push</code>하는 것은 <strong>택배를 보내는 것</strong>과 같다.
|
|
개발자(발신자)가 코드(상품)를 포장해서 Gitea(우체국)에 맡기면,
|
|
서버(수신자)가 받아서 적용(개봉)한다.
|
|
</p>
|
|
</div>
|
|
<div class="mb-5 bg-gray-50 rounded-xl p-4 border flex justify-center academy-img-wrap">
|
|
<img src="{{ asset('images/academy/server-knowledge/8.svg') }}" alt="git push → Gitea → 서버 pull 택배 비유"
|
|
class="rounded-lg cursor-pointer academy-img-hover"
|
|
style="max-height: 280px; width: auto;"
|
|
onclick="openLightbox(this)">
|
|
</div>
|
|
<p class="text-xs text-gray-400 mb-4 text-center">코드 배포 흐름 — 택배 비유</p>
|
|
<div class="bg-gray-900 rounded-lg p-4 overflow-x-auto mb-3">
|
|
<pre class="text-green-400 text-xs font-mono leading-relaxed">개발자 PC Gitea 운영 서버
|
|
│ │ │
|
|
├── git push ──────────→ │ │
|
|
│ (택배 발송) ├── Hook 자동 실행 ───────→ │
|
|
│ │ (도착 알림) ├── git pull
|
|
│ │ │ (택배 수령)
|
|
│ │ ├── 코드 적용
|
|
│ │ │ (상품 개봉)</pre>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 3-3. 자동 배포 Hook -->
|
|
<div id="git-hook" class="scroll-mt-20 mb-8">
|
|
<h3 class="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
|
|
<span class="w-2 h-2 bg-green-400 rounded-full"></span>
|
|
자동 배포 Hook
|
|
</h3>
|
|
<p class="text-sm text-gray-700 mb-3">
|
|
<strong>Hook(훅)</strong>은 특정 이벤트가 발생했을 때 자동으로 실행되는 스크립트다.
|
|
SAM에서는 Gitea에 코드가 올라오면(push) <code class="bg-gray-100 px-1.5 py-0.5 rounded text-xs">post-update</code> 훅이 실행되어 서버에 자동 배포한다.
|
|
</p>
|
|
<div class="mb-5 bg-gray-50 rounded-xl p-4 border flex justify-center academy-img-wrap">
|
|
<img src="{{ asset('images/academy/server-knowledge/9.svg') }}" alt="Hook 동작 흐름 + 권한 체크 포인트"
|
|
class="rounded-lg cursor-pointer academy-img-hover"
|
|
style="max-height: 280px; width: auto;"
|
|
onclick="openLightbox(this)">
|
|
</div>
|
|
<p class="text-xs text-gray-400 mb-4 text-center">Hook 동작 흐름과 권한 체크 포인트</p>
|
|
<div class="bg-gray-900 rounded-lg p-4 overflow-x-auto mb-3">
|
|
<pre class="text-green-400 text-xs font-mono leading-relaxed">post-update Hook 동작 순서:
|
|
|
|
1. 개발자가 git push 실행
|
|
2. Gitea가 코드를 수신
|
|
3. post-update 훅이 pull_mng.sh 호출
|
|
4. pull_mng.sh가 운영 서버에 SSH 접속
|
|
5. git pull 로 최신 코드 다운로드 ← ⚠️ 이때 umask 적용!
|
|
6. composer install (패키지 설치)
|
|
7. config:clear (캐시 초기화)
|
|
8. 배포 완료</pre>
|
|
</div>
|
|
<div class="bg-red-50 rounded-lg p-3 border border-red-100">
|
|
<p class="text-xs text-red-700">
|
|
<strong>주의!</strong> 5단계에서 <code class="bg-red-100 px-1 rounded">git pull</code>로 새 파일이 생성될 때,
|
|
실행하는 사용자의 umask 설정이 적용된다. umask가 잘못되면 여기서 권한 문제가 시작된다.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 3-4. 왜 배포가 깨지는가 -->
|
|
<div id="git-broken" class="scroll-mt-20 mb-4">
|
|
<h3 class="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
|
|
<span class="w-2 h-2 bg-green-400 rounded-full"></span>
|
|
왜 배포가 깨지는가
|
|
</h3>
|
|
<p class="text-sm text-gray-700 mb-4">
|
|
<code class="bg-gray-100 px-1.5 py-0.5 rounded text-xs">Permission denied</code> 오류가 발생하는 3가지 전형적 원인:
|
|
</p>
|
|
<div class="space-y-3">
|
|
<div class="bg-red-50 rounded-lg p-4 border border-red-100">
|
|
<div class="flex items-start gap-3">
|
|
<span class="shrink-0 w-6 h-6 bg-red-500 text-white rounded-full flex items-center justify-center text-xs font-bold">1</span>
|
|
<div>
|
|
<p class="text-sm font-semibold text-red-800">잘못된 소유자 (Owner)</p>
|
|
<p class="text-xs text-red-700 mt-1">
|
|
<code class="bg-red-100 px-1 rounded">root</code>가 만든 파일을 <code class="bg-red-100 px-1 rounded">www-data</code>가 수정하려고 할 때.
|
|
마치 사장님 서류함을 일반 직원이 열려는 것과 같다.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="bg-red-50 rounded-lg p-4 border border-red-100">
|
|
<div class="flex items-start gap-3">
|
|
<span class="shrink-0 w-6 h-6 bg-red-500 text-white rounded-full flex items-center justify-center text-xs font-bold">2</span>
|
|
<div>
|
|
<p class="text-sm font-semibold text-red-800">잘못된 umask (권한 마스크)</p>
|
|
<p class="text-xs text-red-700 mt-1">
|
|
umask 022로 만든 파일(644)은 그룹 쓰기가 안 됨.
|
|
같은 부서인데 서류함에 "수정 금지" 스티커가 붙은 것.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="bg-red-50 rounded-lg p-4 border border-red-100">
|
|
<div class="flex items-start gap-3">
|
|
<span class="shrink-0 w-6 h-6 bg-red-500 text-white rounded-full flex items-center justify-center text-xs font-bold">3</span>
|
|
<div>
|
|
<p class="text-sm font-semibold text-red-800">그룹 불일치 (Group mismatch)</p>
|
|
<p class="text-xs text-red-700 mt-1">
|
|
<code class="bg-red-100 px-1 rounded">pro</code>와 <code class="bg-red-100 px-1 rounded">www-data</code>가 다른 그룹일 때.
|
|
다른 부서 직원이 접근하려는 것과 같다.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{{-- ============================================================ --}}
|
|
{{-- 4. 서버 협업 필수 규칙 --}}
|
|
{{-- ============================================================ --}}
|
|
<section id="rules" class="scroll-mt-20">
|
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
|
|
<h2 class="text-xl font-bold text-gray-800 mb-6 flex items-center gap-3">
|
|
<span class="w-8 h-8 bg-green-500 text-white rounded-lg flex items-center justify-center text-sm font-bold">4</span>
|
|
서버 협업 필수 규칙
|
|
</h2>
|
|
|
|
<!-- 4-1. 절대 하면 안 되는 것 -->
|
|
<div id="rules-forbidden" class="scroll-mt-20 mb-8">
|
|
<h3 class="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
|
|
<span class="w-2 h-2 bg-green-400 rounded-full"></span>
|
|
절대 하면 안 되는 것
|
|
</h3>
|
|
<div class="mb-5 bg-gray-50 rounded-xl p-4 border flex justify-center academy-img-wrap">
|
|
<img src="{{ asset('images/academy/server-knowledge/10.svg') }}" alt="금지 행위 경고 카드"
|
|
class="rounded-lg cursor-pointer academy-img-hover"
|
|
style="max-height: 280px; width: auto;"
|
|
onclick="openLightbox(this)">
|
|
</div>
|
|
<p class="text-xs text-gray-400 mb-4 text-center">절대 금지 행위 4가지</p>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
|
|
<div class="bg-red-50 rounded-lg p-4 border-2 border-red-200">
|
|
<div class="flex items-center gap-2 mb-2">
|
|
<span class="text-red-500 font-bold text-lg">✕</span>
|
|
<p class="font-semibold text-red-800 text-sm">chmod 777</p>
|
|
</div>
|
|
<p class="text-xs text-red-700">모든 사용자에게 모든 권한 부여. 보안이 완전히 무너진다.</p>
|
|
<div class="bg-red-100 rounded p-2 mt-2">
|
|
<p class="text-xs text-red-800">비유: 회사 모든 문을 열어놓기 — 도둑도 들어올 수 있음</p>
|
|
</div>
|
|
</div>
|
|
<div class="bg-red-50 rounded-lg p-4 border-2 border-red-200">
|
|
<div class="flex items-center gap-2 mb-2">
|
|
<span class="text-red-500 font-bold text-lg">✕</span>
|
|
<p class="font-semibold text-red-800 text-sm">chown root</p>
|
|
</div>
|
|
<p class="text-xs text-red-700">파일 소유자를 root로 변경. 웹 서버가 접근 불가능해진다.</p>
|
|
<div class="bg-red-100 rounded p-2 mt-2">
|
|
<p class="text-xs text-red-800">비유: 서류함 담당을 사장님으로 변경 — 일반 직원 접근 차단</p>
|
|
</div>
|
|
</div>
|
|
<div class="bg-red-50 rounded-lg p-4 border-2 border-red-200">
|
|
<div class="flex items-center gap-2 mb-2">
|
|
<span class="text-red-500 font-bold text-lg">✕</span>
|
|
<p class="font-semibold text-red-800 text-sm">서버 파일 직접 수정</p>
|
|
</div>
|
|
<p class="text-xs text-red-700">서버에서 직접 코드를 편집하면 Git 이력이 꼬이고, 다음 배포 시 충돌 발생.</p>
|
|
<div class="bg-red-100 rounded p-2 mt-2">
|
|
<p class="text-xs text-red-800">비유: 원본 서류를 복사본 없이 직접 수정 — 되돌리기 불가</p>
|
|
</div>
|
|
</div>
|
|
<div class="bg-red-50 rounded-lg p-4 border-2 border-red-200">
|
|
<div class="flex items-center gap-2 mb-2">
|
|
<span class="text-red-500 font-bold text-lg">✕</span>
|
|
<p class="font-semibold text-red-800 text-sm">rm -rf (대량 삭제)</p>
|
|
</div>
|
|
<p class="text-xs text-red-700">파일/폴더를 경고 없이 영구 삭제. 복구 불가능.</p>
|
|
<div class="bg-red-100 rounded p-2 mt-2">
|
|
<p class="text-xs text-red-800">비유: 서류함 채로 소각 — 안에 뭐가 있었는지도 모름</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 4-2. 소유자 변경의 위험성 -->
|
|
<div id="rules-chown" class="scroll-mt-20 mb-8">
|
|
<h3 class="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
|
|
<span class="w-2 h-2 bg-green-400 rounded-full"></span>
|
|
소유자 변경의 위험성
|
|
</h3>
|
|
<div class="bg-amber-50 rounded-lg p-4 border border-amber-100 mb-4">
|
|
<p class="font-semibold text-amber-800 mb-2">비유: 서류함 담당자 변경</p>
|
|
<p class="text-xs text-amber-900 leading-relaxed">
|
|
파일의 소유자를 변경하면(<code class="bg-amber-100 px-1 rounded">chown</code>), 기존 담당자가 해당 파일에 접근할 수 없게 될 수 있다.
|
|
마치 서류함 담당을 A에서 B로 바꾸면, A가 더 이상 그 서류함을 열 수 없는 것과 같다.
|
|
</p>
|
|
</div>
|
|
<div class="bg-gray-900 rounded-lg p-4 overflow-x-auto mb-3">
|
|
<pre class="text-xs font-mono leading-relaxed"><span class="text-gray-400"># 위험한 예시: 소유자를 root로 변경</span>
|
|
<span class="text-red-400">sudo chown root:root /home/webservice/mng/storage/logs/</span>
|
|
<span class="text-gray-400"># → www-data가 로그 파일을 쓸 수 없게 됨 → 500 에러 발생!</span>
|
|
|
|
<span class="text-gray-400"># 올바른 소유자 설정:</span>
|
|
<span class="text-green-400">sudo chown pro:www-data /home/webservice/mng/storage/logs/</span>
|
|
<span class="text-gray-400"># → pro가 소유하고, www-data 그룹이 접근 가능</span></pre>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 4-3. 올바른 문제 해결 절차 -->
|
|
<div id="rules-procedure" class="scroll-mt-20 mb-8">
|
|
<h3 class="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
|
|
<span class="w-2 h-2 bg-green-400 rounded-full"></span>
|
|
올바른 문제 해결 절차
|
|
</h3>
|
|
<div class="bg-amber-50 rounded-lg p-4 border border-amber-100 mb-4">
|
|
<p class="font-semibold text-amber-800 mb-2">비유: 엘리베이터 고장 → 관리실 연락</p>
|
|
<p class="text-xs text-amber-900 leading-relaxed">
|
|
엘리베이터가 고장나면 직접 고치려 하지 않고 관리실에 연락하는 것처럼,
|
|
서버 문제가 생기면 <strong>직접 고치려 하지 말고 개발팀에 연락</strong>해야 한다.
|
|
</p>
|
|
</div>
|
|
<div class="mb-5 bg-gray-50 rounded-xl p-4 border flex justify-center academy-img-wrap">
|
|
<img src="{{ asset('images/academy/server-knowledge/11.svg') }}" alt="올바른 절차 4단계 흐름도"
|
|
class="rounded-lg cursor-pointer academy-img-hover"
|
|
style="max-height: 280px; width: auto;"
|
|
onclick="openLightbox(this)">
|
|
</div>
|
|
<p class="text-xs text-gray-400 mb-4 text-center">올바른 문제 해결 4단계</p>
|
|
<div class="grid grid-cols-1 md:grid-cols-4 gap-3 text-xs">
|
|
<div class="bg-blue-50 rounded-lg p-4 border border-blue-100 text-center">
|
|
<p class="font-bold text-blue-700 text-lg mb-2">1</p>
|
|
<p class="font-semibold text-gray-800 mb-1">증상 확인</p>
|
|
<p class="text-gray-500">어떤 화면에서 무슨 오류가 나는지 스크린샷 촬영</p>
|
|
</div>
|
|
<div class="bg-green-50 rounded-lg p-4 border border-green-100 text-center">
|
|
<p class="font-bold text-green-700 text-lg mb-2">2</p>
|
|
<p class="font-semibold text-gray-800 mb-1">팀장에게 보고</p>
|
|
<p class="text-gray-500">스크린샷과 함께 언제부터 발생했는지 전달</p>
|
|
</div>
|
|
<div class="bg-yellow-50 rounded-lg p-4 border border-yellow-100 text-center">
|
|
<p class="font-bold text-yellow-700 text-lg mb-2">3</p>
|
|
<p class="font-semibold text-gray-800 mb-1">원인 분석</p>
|
|
<p class="text-gray-500">개발팀이 로그 확인, 권한 점검, 설정 검토</p>
|
|
</div>
|
|
<div class="bg-purple-50 rounded-lg p-4 border border-purple-100 text-center">
|
|
<p class="font-bold text-purple-700 text-lg mb-2">4</p>
|
|
<p class="font-semibold text-gray-800 mb-1">안전 조치</p>
|
|
<p class="text-gray-500">검증된 방법으로 수정, 결과 확인 후 보고</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 4-4. 긴급 상황 체크리스트 -->
|
|
<div id="rules-checklist" class="scroll-mt-20 mb-4">
|
|
<h3 class="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
|
|
<span class="w-2 h-2 bg-green-400 rounded-full"></span>
|
|
긴급 상황 체크리스트
|
|
</h3>
|
|
<p class="text-sm text-gray-700 mb-4">서버 장애 발생 시, 대표(비개발자)가 할 수 있는 것과 할 수 없는 것:</p>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div class="bg-green-50 rounded-lg p-4 border border-green-200">
|
|
<p class="font-semibold text-green-800 mb-3 text-sm flex items-center gap-2">
|
|
<span class="text-green-500 text-lg">✓</span>
|
|
할 수 있는 것
|
|
</p>
|
|
<ul class="text-xs text-green-700 space-y-2">
|
|
<li class="flex items-start gap-2">
|
|
<span class="shrink-0 mt-0.5 w-4 h-4 bg-green-200 rounded-full flex items-center justify-center text-green-800" style="font-size:0.6rem">✓</span>
|
|
오류 화면 스크린샷 찍기
|
|
</li>
|
|
<li class="flex items-start gap-2">
|
|
<span class="shrink-0 mt-0.5 w-4 h-4 bg-green-200 rounded-full flex items-center justify-center text-green-800" style="font-size:0.6rem">✓</span>
|
|
발생 시간/상황 기록
|
|
</li>
|
|
<li class="flex items-start gap-2">
|
|
<span class="shrink-0 mt-0.5 w-4 h-4 bg-green-200 rounded-full flex items-center justify-center text-green-800" style="font-size:0.6rem">✓</span>
|
|
다른 브라우저/기기에서 재현 확인
|
|
</li>
|
|
<li class="flex items-start gap-2">
|
|
<span class="shrink-0 mt-0.5 w-4 h-4 bg-green-200 rounded-full flex items-center justify-center text-green-800" style="font-size:0.6rem">✓</span>
|
|
개발팀장에게 즉시 연락
|
|
</li>
|
|
<li class="flex items-start gap-2">
|
|
<span class="shrink-0 mt-0.5 w-4 h-4 bg-green-200 rounded-full flex items-center justify-center text-green-800" style="font-size:0.6rem">✓</span>
|
|
안전한 조회 명령어 실행 (ls, cat 등)
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="bg-red-50 rounded-lg p-4 border border-red-200">
|
|
<p class="font-semibold text-red-800 mb-3 text-sm flex items-center gap-2">
|
|
<span class="text-red-500 text-lg">✕</span>
|
|
절대 하면 안 되는 것
|
|
</p>
|
|
<ul class="text-xs text-red-700 space-y-2">
|
|
<li class="flex items-start gap-2">
|
|
<span class="shrink-0 mt-0.5 w-4 h-4 bg-red-200 rounded-full flex items-center justify-center text-red-800" style="font-size:0.6rem">✕</span>
|
|
서버 파일 직접 수정/삭제
|
|
</li>
|
|
<li class="flex items-start gap-2">
|
|
<span class="shrink-0 mt-0.5 w-4 h-4 bg-red-200 rounded-full flex items-center justify-center text-red-800" style="font-size:0.6rem">✕</span>
|
|
chmod, chown 명령어 실행
|
|
</li>
|
|
<li class="flex items-start gap-2">
|
|
<span class="shrink-0 mt-0.5 w-4 h-4 bg-red-200 rounded-full flex items-center justify-center text-red-800" style="font-size:0.6rem">✕</span>
|
|
서비스 재시작 (systemctl restart)
|
|
</li>
|
|
<li class="flex items-start gap-2">
|
|
<span class="shrink-0 mt-0.5 w-4 h-4 bg-red-200 rounded-full flex items-center justify-center text-red-800" style="font-size:0.6rem">✕</span>
|
|
Nginx/PHP 설정 변경
|
|
</li>
|
|
<li class="flex items-start gap-2">
|
|
<span class="shrink-0 mt-0.5 w-4 h-4 bg-red-200 rounded-full flex items-center justify-center text-red-800" style="font-size:0.6rem">✕</span>
|
|
sudo 명령어 실행
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{{-- ============================================================ --}}
|
|
{{-- 5. 핵심 명령어 사전 --}}
|
|
{{-- ============================================================ --}}
|
|
<section id="commands" class="scroll-mt-20">
|
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
|
|
<h2 class="text-xl font-bold text-gray-800 mb-6 flex items-center gap-3">
|
|
<span class="w-8 h-8 bg-green-500 text-white rounded-lg flex items-center justify-center text-sm font-bold">5</span>
|
|
핵심 명령어 사전
|
|
</h2>
|
|
|
|
<!-- 5-1. 안전한 명령어 -->
|
|
<div id="commands-safe" class="scroll-mt-20 mb-8">
|
|
<h3 class="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
|
|
<span class="w-2 h-2 bg-green-400 rounded-full"></span>
|
|
안전한 명령어
|
|
<span class="text-xs bg-green-100 text-green-700 px-2 py-0.5 rounded-full font-medium">안전</span>
|
|
</h3>
|
|
<p class="text-sm text-gray-700 mb-4">
|
|
다음 명령어들은 <strong>읽기 전용</strong>이므로 서버에 영향을 주지 않는다. 자유롭게 사용 가능.
|
|
</p>
|
|
<div class="mb-5 bg-gray-50 rounded-xl p-4 border flex justify-center academy-img-wrap">
|
|
<img src="{{ asset('images/academy/server-knowledge/12.svg') }}" alt="안전 vs 위험 명령어 대비표"
|
|
class="rounded-lg cursor-pointer academy-img-hover"
|
|
style="max-height: 280px; width: auto;"
|
|
onclick="openLightbox(this)">
|
|
</div>
|
|
<p class="text-xs text-gray-400 mb-4 text-center">안전(초록) vs 위험(빨강) 명령어 대비표</p>
|
|
<div class="overflow-x-auto">
|
|
<table class="w-full text-sm border-collapse">
|
|
<thead>
|
|
<tr class="border-b-2 border-gray-200 bg-green-50">
|
|
<th class="text-left py-2 px-3 font-medium text-green-800">명령어</th>
|
|
<th class="text-left py-2 px-3 font-medium text-green-800">하는 일</th>
|
|
<th class="text-left py-2 px-3 font-medium text-green-800">비유</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="text-xs text-gray-700">
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-mono font-medium"><span class="bg-green-100 text-green-800 px-1.5 py-0.5 rounded">ls</span></td>
|
|
<td class="py-2 px-3">폴더 내용 목록 보기</td>
|
|
<td class="py-2 px-3">서류함 목차 훑어보기</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-mono font-medium"><span class="bg-green-100 text-green-800 px-1.5 py-0.5 rounded">cat</span></td>
|
|
<td class="py-2 px-3">파일 내용 보기</td>
|
|
<td class="py-2 px-3">서류 한 장 읽기</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-mono font-medium"><span class="bg-green-100 text-green-800 px-1.5 py-0.5 rounded">whoami</span></td>
|
|
<td class="py-2 px-3">현재 로그인 계정 확인</td>
|
|
<td class="py-2 px-3">내 사원증 확인</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-mono font-medium"><span class="bg-green-100 text-green-800 px-1.5 py-0.5 rounded">df -h</span></td>
|
|
<td class="py-2 px-3">디스크 사용량 확인</td>
|
|
<td class="py-2 px-3">창고 남은 공간 확인</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-mono font-medium"><span class="bg-green-100 text-green-800 px-1.5 py-0.5 rounded">docker ps</span></td>
|
|
<td class="py-2 px-3">실행 중인 컨테이너 확인</td>
|
|
<td class="py-2 px-3">영업 중인 가게 확인</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-mono font-medium"><span class="bg-green-100 text-green-800 px-1.5 py-0.5 rounded">tail -f 로그파일</span></td>
|
|
<td class="py-2 px-3">로그 실시간 보기</td>
|
|
<td class="py-2 px-3">CCTV 실시간 모니터링</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-mono font-medium"><span class="bg-green-100 text-green-800 px-1.5 py-0.5 rounded">git status</span></td>
|
|
<td class="py-2 px-3">변경된 파일 목록 확인</td>
|
|
<td class="py-2 px-3">수정된 서류 확인</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-mono font-medium"><span class="bg-green-100 text-green-800 px-1.5 py-0.5 rounded">free -m</span></td>
|
|
<td class="py-2 px-3">메모리 사용량 확인</td>
|
|
<td class="py-2 px-3">직원 업무량 확인</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 5-2. 위험한 명령어 -->
|
|
<div id="commands-danger" class="scroll-mt-20 mb-8">
|
|
<h3 class="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
|
|
<span class="w-2 h-2 bg-green-400 rounded-full"></span>
|
|
위험한 명령어
|
|
<span class="text-xs bg-red-100 text-red-700 px-2 py-0.5 rounded-full font-medium">위험</span>
|
|
</h3>
|
|
<p class="text-sm text-gray-700 mb-4">
|
|
다음 명령어들은 <strong>서버를 변경</strong>하므로 반드시 개발팀장의 확인 후 사용해야 한다.
|
|
</p>
|
|
<div class="overflow-x-auto">
|
|
<table class="w-full text-sm border-collapse">
|
|
<thead>
|
|
<tr class="border-b-2 border-gray-200 bg-red-50">
|
|
<th class="text-left py-2 px-3 font-medium text-red-800">명령어</th>
|
|
<th class="text-left py-2 px-3 font-medium text-red-800">하는 일</th>
|
|
<th class="text-left py-2 px-3 font-medium text-red-800">위험도</th>
|
|
<th class="text-left py-2 px-3 font-medium text-red-800">비유</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="text-xs text-gray-700">
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-mono font-medium"><span class="bg-red-100 text-red-800 px-1.5 py-0.5 rounded">rm -rf</span></td>
|
|
<td class="py-2 px-3">파일/폴더 영구 삭제</td>
|
|
<td class="py-2 px-3"><span class="bg-red-500 text-white px-1.5 py-0.5 rounded-full text-xs">극위험</span></td>
|
|
<td class="py-2 px-3">서류함 채로 소각</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-mono font-medium"><span class="bg-red-100 text-red-800 px-1.5 py-0.5 rounded">chmod</span></td>
|
|
<td class="py-2 px-3">파일 권한 변경</td>
|
|
<td class="py-2 px-3"><span class="bg-orange-500 text-white px-1.5 py-0.5 rounded-full text-xs">고위험</span></td>
|
|
<td class="py-2 px-3">서류함 스티커 변경</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-mono font-medium"><span class="bg-red-100 text-red-800 px-1.5 py-0.5 rounded">chown</span></td>
|
|
<td class="py-2 px-3">파일 소유자 변경</td>
|
|
<td class="py-2 px-3"><span class="bg-orange-500 text-white px-1.5 py-0.5 rounded-full text-xs">고위험</span></td>
|
|
<td class="py-2 px-3">서류함 담당자 교체</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-mono font-medium"><span class="bg-red-100 text-red-800 px-1.5 py-0.5 rounded">kill -9</span></td>
|
|
<td class="py-2 px-3">프로세스 강제 종료</td>
|
|
<td class="py-2 px-3"><span class="bg-orange-500 text-white px-1.5 py-0.5 rounded-full text-xs">고위험</span></td>
|
|
<td class="py-2 px-3">직원 즉시 해고 (인수인계 없이)</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-mono font-medium"><span class="bg-red-100 text-red-800 px-1.5 py-0.5 rounded">sudo</span></td>
|
|
<td class="py-2 px-3">관리자 권한으로 실행</td>
|
|
<td class="py-2 px-3"><span class="bg-yellow-500 text-white px-1.5 py-0.5 rounded-full text-xs">주의</span></td>
|
|
<td class="py-2 px-3">만능 열쇠 사용</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-mono font-medium"><span class="bg-red-100 text-red-800 px-1.5 py-0.5 rounded">systemctl restart</span></td>
|
|
<td class="py-2 px-3">서비스 재시작</td>
|
|
<td class="py-2 px-3"><span class="bg-yellow-500 text-white px-1.5 py-0.5 rounded-full text-xs">주의</span></td>
|
|
<td class="py-2 px-3">가게 문 닫았다 열기</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 5-3. FAQ -->
|
|
<div id="commands-faq" class="scroll-mt-20 mb-4">
|
|
<h3 class="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
|
|
<span class="w-2 h-2 bg-green-400 rounded-full"></span>
|
|
자주 묻는 질문 (FAQ)
|
|
</h3>
|
|
<div class="space-y-3">
|
|
<details class="bg-gray-50 rounded-lg border">
|
|
<summary class="cursor-pointer p-4 text-sm font-medium text-gray-800 hover:bg-gray-100 rounded-lg">
|
|
Q. 사이트가 갑자기 느려졌어요. 뭘 확인해야 하나요?
|
|
</summary>
|
|
<div class="px-4 pb-4 text-xs text-gray-700 space-y-2">
|
|
<p><strong>A.</strong> 서버 리소스를 확인한다:</p>
|
|
<div class="bg-gray-900 rounded p-3 overflow-x-auto">
|
|
<pre class="text-green-400 text-xs font-mono">free -m # 메모리 사용량 확인
|
|
df -h # 디스크 공간 확인
|
|
docker ps # 컨테이너 상태 확인</pre>
|
|
</div>
|
|
<p>메모리가 부족하거나 디스크가 가득 찼으면 개발팀장에게 보고한다.</p>
|
|
</div>
|
|
</details>
|
|
|
|
<details class="bg-gray-50 rounded-lg border">
|
|
<summary class="cursor-pointer p-4 text-sm font-medium text-gray-800 hover:bg-gray-100 rounded-lg">
|
|
Q. 502 Bad Gateway 에러가 나요.
|
|
</summary>
|
|
<div class="px-4 pb-4 text-xs text-gray-700 space-y-2">
|
|
<p><strong>A.</strong> PHP-FPM(요리사 팀)이 동작하지 않는 상태. "요리사가 전부 퇴근한 식당"이다.</p>
|
|
<p>원인:</p>
|
|
<ul class="list-disc list-inside space-y-1">
|
|
<li>PHP-FPM 서비스가 죽었음 (메모리 부족 등)</li>
|
|
<li>Nginx 설정 오류로 PHP-FPM에 연결 실패</li>
|
|
<li>서버 자체 과부하</li>
|
|
</ul>
|
|
<p class="text-red-600 font-semibold">→ 직접 해결하지 말고 개발팀장에게 즉시 연락!</p>
|
|
</div>
|
|
</details>
|
|
|
|
<details class="bg-gray-50 rounded-lg border">
|
|
<summary class="cursor-pointer p-4 text-sm font-medium text-gray-800 hover:bg-gray-100 rounded-lg">
|
|
Q. 코드를 push했는데 서버에 반영이 안 돼요.
|
|
</summary>
|
|
<div class="px-4 pb-4 text-xs text-gray-700 space-y-2">
|
|
<p><strong>A.</strong> 자동 배포(Hook)가 실패한 것. 세 가지를 확인한다:</p>
|
|
<ol class="list-decimal list-inside space-y-1">
|
|
<li><strong>Hook 오류</strong> — Gitea의 Hook 로그에서 에러 확인</li>
|
|
<li><strong>Permission denied</strong> — 파일 권한 문제 (이 문서의 섹션 2 참고)</li>
|
|
<li><strong>SSH 연결 실패</strong> — 서버 SSH 포트나 키 문제</li>
|
|
</ol>
|
|
<div class="bg-gray-900 rounded p-3 overflow-x-auto">
|
|
<pre class="text-green-400 text-xs font-mono"># 서버에서 직접 확인 (안전한 명령어)
|
|
git status # 현재 상태 확인
|
|
git log --oneline -5 # 최근 커밋 확인</pre>
|
|
</div>
|
|
</div>
|
|
</details>
|
|
|
|
<details class="bg-gray-50 rounded-lg border">
|
|
<summary class="cursor-pointer p-4 text-sm font-medium text-gray-800 hover:bg-gray-100 rounded-lg">
|
|
Q. Permission denied 에러가 나요.
|
|
</summary>
|
|
<div class="px-4 pb-4 text-xs text-gray-700 space-y-2">
|
|
<p><strong>A.</strong> "배지(권한)가 없어서 출입통제구역에 못 들어가는" 상황. 세 가지를 확인한다:</p>
|
|
<ol class="list-decimal list-inside space-y-1">
|
|
<li>파일 소유자가 누구인지 확인: <code class="bg-gray-200 px-1 rounded">ls -la 파일경로</code></li>
|
|
<li>파일 권한이 올바른지 확인: <code class="bg-gray-200 px-1 rounded">stat 파일경로</code></li>
|
|
<li>현재 사용자가 누구인지 확인: <code class="bg-gray-200 px-1 rounded">whoami</code></li>
|
|
</ol>
|
|
<p>확인 결과를 개발팀장에게 전달하면 빠른 해결이 가능하다.</p>
|
|
</div>
|
|
</details>
|
|
|
|
<details class="bg-gray-50 rounded-lg border">
|
|
<summary class="cursor-pointer p-4 text-sm font-medium text-gray-800 hover:bg-gray-100 rounded-lg">
|
|
Q. 서버 디스크가 가득 찼대요.
|
|
</summary>
|
|
<div class="px-4 pb-4 text-xs text-gray-700 space-y-2">
|
|
<p><strong>A.</strong> "창고가 가득 차서 새 물건을 넣을 수 없는" 상태.</p>
|
|
<div class="bg-gray-900 rounded p-3 overflow-x-auto">
|
|
<pre class="text-green-400 text-xs font-mono"># 디스크 사용량 확인 (안전)
|
|
df -h
|
|
|
|
# 큰 파일 찾기 (안전)
|
|
du -sh /home/webservice/*/storage/logs/</pre>
|
|
</div>
|
|
<p>보통 로그 파일이 너무 커진 경우. 로그 정리는 개발팀장이 진행한다.</p>
|
|
</div>
|
|
</details>
|
|
</div>
|
|
|
|
<!-- 핵심 정리 -->
|
|
<div class="mt-6 bg-green-50 rounded-lg p-5 border border-green-100">
|
|
<h4 class="font-semibold text-green-800 mb-2 text-sm">핵심 정리</h4>
|
|
<p class="text-xs text-green-700 leading-relaxed">
|
|
서버는 <strong>"24시간 영업하는 회사 건물"</strong>이다.
|
|
건물 안의 서류함(파일)에는 담당자(소유자)와 스티커(권한)가 붙어있다.
|
|
스티커가 맞아야 서류를 보거나 수정할 수 있다.
|
|
건물에 문제가 생기면 <strong>직접 고치려 하지 말고, 관리실(개발팀)에 연락</strong>하는 것이 올바른 절차다.
|
|
안전한 명령어(ls, cat, whoami)로 상황을 파악하고, 위험한 명령어(rm, chmod, chown)는 절대 혼자 사용하지 않는다.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- hover 프리뷰 오버레이 -->
|
|
<div id="hover-preview">
|
|
<img id="hover-preview-img" src="" alt="">
|
|
<span class="hover-caption" id="hover-preview-caption"></span>
|
|
</div>
|
|
|
|
<!-- 클릭 라이트박스 -->
|
|
<div id="lightbox" onclick="closeLightbox()">
|
|
<button onclick="closeLightbox()" style="position:absolute; top:1rem; right:1rem; background:none; border:none; cursor:pointer; color:rgba(255,255,255,0.8); padding:0.5rem;">
|
|
<svg style="width:2rem; height:2rem;" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /></svg>
|
|
</button>
|
|
<img id="lightbox-img" onclick="event.stopPropagation()">
|
|
</div>
|
|
<script>
|
|
(function() {
|
|
var preview = document.getElementById('hover-preview');
|
|
var previewImg = document.getElementById('hover-preview-img');
|
|
var previewCaption = document.getElementById('hover-preview-caption');
|
|
var hoverTimer = null;
|
|
var isPreviewActive = false;
|
|
var HOVER_DELAY = 350;
|
|
|
|
document.querySelectorAll('.academy-img-hover').forEach(function(img) {
|
|
img.addEventListener('mouseenter', function() {
|
|
var el = this;
|
|
hoverTimer = setTimeout(function() {
|
|
showPreview(el);
|
|
}, HOVER_DELAY);
|
|
});
|
|
|
|
img.addEventListener('mouseleave', function() {
|
|
clearTimeout(hoverTimer);
|
|
if (isPreviewActive) {
|
|
hidePreview();
|
|
}
|
|
});
|
|
});
|
|
|
|
function showPreview(el) {
|
|
previewImg.src = el.src;
|
|
previewImg.alt = el.alt || '';
|
|
var caption = el.alt || '';
|
|
var nextP = el.parentElement && el.parentElement.querySelector('p');
|
|
if (nextP) caption = nextP.textContent;
|
|
previewCaption.textContent = caption;
|
|
|
|
preview.classList.add('is-active');
|
|
isPreviewActive = true;
|
|
}
|
|
|
|
function hidePreview() {
|
|
preview.classList.remove('is-active');
|
|
isPreviewActive = false;
|
|
}
|
|
|
|
window.openLightbox = function(el) {
|
|
var lb = document.getElementById('lightbox');
|
|
var img = document.getElementById('lightbox-img');
|
|
img.src = el.src;
|
|
img.alt = el.alt;
|
|
lb.classList.add('is-open');
|
|
document.body.style.overflow = 'hidden';
|
|
hidePreview();
|
|
};
|
|
|
|
window.closeLightbox = function() {
|
|
var lb = document.getElementById('lightbox');
|
|
lb.classList.remove('is-open');
|
|
document.body.style.overflow = '';
|
|
};
|
|
|
|
document.addEventListener('keydown', function(e) {
|
|
if (e.key === 'Escape') {
|
|
if (isPreviewActive) hidePreview();
|
|
closeLightbox();
|
|
}
|
|
});
|
|
})();
|
|
</script>
|
|
@endsection
|