471 lines
18 KiB
Markdown
471 lines
18 KiB
Markdown
# Genesis_GameServer
|
|
|
|
유니티 게임(Genesis) 서버 + 개인 포트폴리오 사이트.
|
|
|
|
하나의 ASP.NET Core 프로세스가 두 가지를 함께 서빙합니다.
|
|
|
|
| 경로 | 내용 |
|
|
|---|---|
|
|
| `/myGame/*` | 유니티 게임 클라이언트가 쓰는 기존 API (변경 없음) |
|
|
| `/api/portfolio/*` | 포트폴리오 REST API |
|
|
| `/` 그 밖의 모든 경로 | 포트폴리오 웹사이트 (정적 SPA) |
|
|
|
|
---
|
|
|
|
## 1. 처음 실행하기
|
|
|
|
### 관리자 비밀번호부터 바꾸세요
|
|
|
|
`GameServer/appsettings.json` 의 `Portfolio.AdminPassword` 가 `CHANGE_ME` 로 되어 있으면
|
|
**로그인 자체가 막혀 있습니다**(503). 원하는 비밀번호로 바꾸고 서버를 다시 시작하세요.
|
|
|
|
```json
|
|
"Portfolio": {
|
|
"AdminPassword": "여기에-원하는-비밀번호",
|
|
"SiteTitle": "사이트 이름",
|
|
"SiteTagline": "한 줄 소개",
|
|
"MaxUploadBytes": 10485760
|
|
}
|
|
```
|
|
|
|
> `SiteTitle` · `SiteTagline` 은 지금 어느 코드도 읽지 않습니다.
|
|
> 화면에 나오는 이름과 문구는 `GameServer/wwwroot/index.html` 에 직접 들어 있습니다.
|
|
|
|
파일에 비밀번호를 두고 싶지 않다면 환경변수가 우선합니다.
|
|
|
|
```bash
|
|
# Windows (PowerShell)
|
|
$env:Portfolio__AdminPassword = "비밀번호"
|
|
# Linux / macOS
|
|
export Portfolio__AdminPassword="비밀번호"
|
|
```
|
|
|
|
### 실행
|
|
|
|
```bash
|
|
dotnet run --project GameServer/GameServer.csproj
|
|
```
|
|
|
|
브라우저에서 `http://localhost:5281` 을 열면 포트폴리오가 뜹니다.
|
|
우측 상단 **관리자** 버튼 → 비밀번호 입력 → 글을 쓸 수 있습니다.
|
|
|
|
> 이 프로젝트는 `net9.0` 을 대상으로 합니다. .NET 9 런타임이 없고 상위 버전만 있다면
|
|
> `DOTNET_ROLL_FORWARD=LatestMajor` 를 주고 실행하거나, .NET 9 런타임을 설치하세요.
|
|
|
|
---
|
|
|
|
## 2. 데이터베이스
|
|
|
|
포트폴리오 테이블은 **서버가 시작할 때 자동으로 만들어집니다**
|
|
(`Data/PortfolioSchemaInitializer.cs`, `CREATE TABLE IF NOT EXISTS`).
|
|
따로 마이그레이션을 돌릴 필요가 없습니다.
|
|
|
|
- `tb_portfolio_category` — 카테고리 (처음 한 번 `게임 / 개발 / 아트 / 기록` 4개가 시드됩니다)
|
|
- `tb_portfolio_post` — 게시물
|
|
- `tb_portfolio_post_image` — 게시물 이미지
|
|
|
|
수동으로 만들고 싶다면 `GameServer/sql/portfolio_schema.sql` 을 쓰세요.
|
|
DB 연결이 실패해도 **게임 서버 부팅은 막지 않습니다**(로그만 남기고 넘어갑니다).
|
|
|
|
---
|
|
|
|
## 3. 화면
|
|
|
|
| 주소 | 화면 |
|
|
|---|---|
|
|
| `#/` | 작업 인덱스 (히어로 + 카테고리 필터 + 번호 매긴 목록) |
|
|
| `#/?cat=game` | 카테고리로 걸러진 목록 |
|
|
| `#/post/12` | 게시물 상세 (마크다운 본문 + 이미지 갤러리 + 라이트박스) |
|
|
| `#/about` | 소개 |
|
|
| `#/admin` | 관리자 로그인 / 대시보드 |
|
|
| `#/admin/new` | 새 글 |
|
|
| `#/admin/edit/12` | 글 수정 |
|
|
| `#/admin/categories` | 카테고리 관리 |
|
|
|
|
### 글쓰기
|
|
|
|
본문은 **마크다운**입니다. 왼쪽에 쓰면 오른쪽에 바로 미리보기가 나옵니다.
|
|
|
|
이미지는 세 가지 방법으로 올립니다.
|
|
|
|
1. 이미지 영역을 **클릭**해서 파일 고르기
|
|
2. 파일을 **끌어다 놓기**
|
|
3. 클립보드에서 **Ctrl+V** 로 붙여넣기
|
|
|
|
올린 이미지마다 세 개의 버튼이 있습니다.
|
|
|
|
- **대표** — 목록에서 커서를 따라 뜨는 썸네일과 상세 표지로 지정
|
|
- **본문삽입** — 커서 위치에 `` 를 끼워 넣기
|
|
- **삭제** — 목록에서 빼기 (이번에 올린 파일이면 서버에서도 지웁니다)
|
|
|
|
저장하지 않고 페이지를 벗어나려 하면 경고가 뜹니다.
|
|
|
|
### 화면 구성
|
|
|
|
목록은 카드 그리드가 아니라 **작품집 목차(인덱스)** 형태입니다.
|
|
번호 → 제목 → 요약 → 카테고리 · 날짜 순으로 한 줄씩 늘어놓고,
|
|
행에 마우스를 올리면 행이 살짝 밀려 들어오면서 대표 이미지가 커서 옆에 떠오릅니다
|
|
(마우스가 있는 기기에서만. 터치 기기에서는 뜨지 않습니다).
|
|
|
|
배경 장식은 쓰지 않습니다. 위계는 글자 크기 대비와 얇은 괘선으로 만들고,
|
|
색은 카테고리 강조색으로만 들어옵니다. 한글은 산세리프, 숫자·라벨은 모노스페이스입니다.
|
|
|
|
카테고리 색은 `#/admin/categories` 에서 바꿀 수 있고, 그 색이 목록·상세·관리자 화면에
|
|
그대로 반영됩니다.
|
|
|
|
### 샘플 글 지우기
|
|
|
|
화면이 어떻게 보이는지 확인할 수 있도록 제목이 `[샘플]` 로 시작하는 글 5건을
|
|
자리표시 이미지와 함께 넣어 두었습니다. **직접 쓴 글이 아니니 지우고 시작하세요.**
|
|
|
|
`#/admin` 에서 로그인한 뒤 각 줄의 **삭제** 를 누르면 됩니다.
|
|
글을 지워도 업로드된 자리표시 이미지 파일은 남으므로, 함께 비우려면
|
|
`GameServer/wwwroot/uploads/` 아래 폴더를 통째로 지우면 됩니다
|
|
(`.gitkeep` 은 남겨 두세요).
|
|
|
|
### 소개 화면 내용 바꾸기
|
|
|
|
`GameServer/wwwroot/js/views/about.js` 의 `ABOUT_MD` 상수 하나만 고치면 됩니다.
|
|
빌드가 필요 없고 새로고침하면 바로 반영됩니다.
|
|
|
|
---
|
|
|
|
## 4. 구조
|
|
|
|
```
|
|
GameServer/
|
|
├─ Controllers/
|
|
│ ├─ CharacterController.cs 게임 API (기존)
|
|
│ ├─ UserController.cs 게임 API (기존)
|
|
│ └─ Portfolio/
|
|
│ ├─ PortfolioAuthController.cs 로그인 · 로그아웃 · 상태
|
|
│ ├─ PortfolioCategoryController.cs 카테고리 CRUD
|
|
│ ├─ PortfolioPostController.cs 게시물 CRUD
|
|
│ └─ PortfolioUploadController.cs 이미지 업로드 · 삭제
|
|
├─ Models/Portfolio/ 모델 + DTO
|
|
├─ Services/PortfolioAdminAuth.cs 관리자 비밀번호 검증
|
|
├─ Data/PortfolioSchemaInitializer.cs 테이블 자동 생성 + 시드
|
|
├─ sql/portfolio_schema.sql 참고용 DDL
|
|
└─ wwwroot/ 포트폴리오 사이트 (빌드 단계 없음)
|
|
├─ index.html
|
|
├─ css/style.css 디자인 시스템 한 파일
|
|
├─ js/
|
|
│ ├─ app.js 진입점 · 라우트 표
|
|
│ ├─ router.js 해시 라우터
|
|
│ ├─ api.js REST 래퍼
|
|
│ ├─ ui.js 토스트 · 모달 · 헬퍼
|
|
│ ├─ markdown.js 자체 제작 마크다운 렌더러
|
|
│ └─ views/ home · post · about · admin
|
|
└─ uploads/ 업로드된 이미지 (git 에서 제외됨)
|
|
```
|
|
|
|
프론트엔드에 **빌드 단계가 없습니다**. npm 도, 번들러도, 외부 CDN 요청도 없습니다.
|
|
배포는 그대로 `dotnet publish` 하나로 끝납니다.
|
|
|
|
---
|
|
|
|
## 5. 리눅스에 배포하기 — 도커 없이
|
|
|
|
런타임까지 통째로 묶은 **자체 포함(self-contained) 실행 파일**을 만들어 올리는 방식입니다.
|
|
**서버에 .NET 을 설치할 필요가 없습니다.** Visual Studio 게시 대화상자의
|
|
"배포 모드: 자체 포함 / 대상 런타임: linux-x64" 와 같은 결과물입니다.
|
|
|
|
### 만들기
|
|
|
|
윈도우에서 만들어도 됩니다. 리눅스용 실행 파일이 나옵니다.
|
|
|
|
**PowerShell** (VS Code 기본 터미널)
|
|
```powershell
|
|
.\deploy\publish-linux.cmd
|
|
```
|
|
|
|
**Git Bash · WSL · 맥 · 리눅스**
|
|
```bash
|
|
./deploy/publish-linux.sh
|
|
```
|
|
|
|
셋 다 같은 일을 합니다. 상황에 맞는 것을 쓰세요.
|
|
|
|
| 파일 | 쓰는 곳 |
|
|
|---|---|
|
|
| `publish-linux.cmd` | PowerShell·cmd. 실행 정책을 건드리지 않아도 됩니다 |
|
|
| `publish-linux.ps1` | 실제 내용. 아래 정책 문제를 해결했다면 직접 실행해도 됩니다 |
|
|
| `publish-linux.sh` | Git Bash · WSL · 맥 · 리눅스 |
|
|
|
|
#### `.ps1` 이 "이 시스템에서 스크립트를 실행할 수 없으므로" 오류가 날 때
|
|
|
|
윈도우 기본 실행 정책이 `Restricted` 라 `.ps1` 이 막힙니다. 세 가지 방법이 있습니다.
|
|
|
|
1. **`.cmd` 를 쓴다** — 가장 간단합니다. 정책을 바꾸지 않습니다.
|
|
```powershell
|
|
.\deploy\publish-linux.cmd
|
|
```
|
|
> `cmd` 파일은 앞에 `.\` 를 꼭 붙이세요. 없으면 현재 폴더를 찾지 못합니다.
|
|
|
|
2. **한 번만 우회한다** — 시스템 설정을 바꾸지 않습니다.
|
|
```powershell
|
|
powershell -ExecutionPolicy Bypass -File .\deploy\publish-linux.ps1
|
|
```
|
|
|
|
3. **내 계정에만 정책을 푼다** — 앞으로 계속 `.ps1` 을 쓰고 싶다면.
|
|
```powershell
|
|
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
|
|
```
|
|
`RemoteSigned` 는 직접 만든 스크립트는 실행하고, 인터넷에서 받은 것은
|
|
서명을 요구합니다. 관리자 권한이 필요 없고 이 계정에만 적용됩니다.
|
|
|
|
`artifacts/linux-x64/` 에 이런 결과가 나옵니다. **53MB, 파일 네 개뿐입니다.**
|
|
|
|
```
|
|
GameServer 리눅스 실행 파일 (런타임 포함, 단일 파일)
|
|
GameServer.staticwebassets.endpoints.json
|
|
appsettings.json
|
|
wwwroot/ 사이트 (html · css · js)
|
|
```
|
|
|
|
스크립트가 쓰는 명령은 이것 하나입니다.
|
|
|
|
```bash
|
|
dotnet publish GameServer/GameServer.csproj -c Release -r linux-x64 --self-contained true -p:PublishSingleFile=true -p:EnableCompressionInSingleFile=true -o artifacts/linux-x64
|
|
```
|
|
|
|
> `PublishTrimmed` 는 켜지 마세요. 용량은 더 줄지만 EF Core 가 리플렉션으로 찾는 타입이
|
|
> 잘려 나가 실행 중에 터집니다.
|
|
|
|
### 서버에서 바로 실행해 보기
|
|
|
|
복사한 폴더로 들어가 `run.sh` 를 실행하면 끝입니다. 서버에 .NET 을 깔 필요가 없습니다.
|
|
|
|
```bash
|
|
cd /srv/genesis
|
|
chmod +x run.sh
|
|
./run.sh # PORT=8080 ./run.sh 처럼 포트를 바꿀 수 있습니다
|
|
```
|
|
|
|
`run.sh` 가 두 가지를 대신 해 줍니다.
|
|
|
|
- **실행 권한** — 윈도우에서 복사하면 실행 비트가 사라져 `Permission denied` 가 납니다.
|
|
- **바인딩 주소** — `ASPNETCORE_URLS` 를 주지 않으면 `localhost:5000` 에만 묶여
|
|
서버 안에서만 보이고 브라우저로는 안 열립니다. `0.0.0.0:5281` 로 열어 줍니다.
|
|
|
|
클라우드 서버라면 방화벽도 열어야 합니다. `sudo ufw allow 5281/tcp`
|
|
|
|
SSH 를 끊으면 함께 종료되므로, 계속 띄워 두려면 아래 systemd 등록을 하세요.
|
|
|
|
### 이미 돌고 있는 서버 멈추기
|
|
|
|
새로 올린 것이 같은 포트를 쓰려면 기존 프로세스를 먼저 내려야 합니다.
|
|
`Address already in use` 가 뜨면 이 경우입니다.
|
|
|
|
**1) 무엇이 포트를 잡고 있는지 본다**
|
|
|
|
```bash
|
|
sudo ss -tlnp | grep 5281 # 없으면: sudo lsof -i :5281
|
|
ps aux | grep -iE 'GameServer|dotnet' | grep -v grep
|
|
systemctl list-units --type=service | grep -iE 'genesis|game|portfolio'
|
|
docker ps # 도커로 띄웠다면
|
|
```
|
|
|
|
**2) 나온 결과에 맞춰 끈다**
|
|
|
|
| 어떻게 떠 있나 | 끄는 법 |
|
|
|---|---|
|
|
| systemd 서비스 | `sudo systemctl stop 이름` |
|
|
| 도커 컨테이너 | `docker stop 이름` |
|
|
| 그냥 실행한 프로세스 | `kill -INT <PID>` |
|
|
| screen · tmux 안 | `screen -r` / `tmux attach` 후 `Ctrl+C` |
|
|
|
|
**systemd 로 등록돼 있다면 `kill` 은 소용없습니다.** `Restart=always` 때문에
|
|
바로 되살아납니다. 반드시 `systemctl stop` 을 쓰고, 다시 안 뜨게 하려면
|
|
`sudo systemctl disable 이름` 까지 하세요.
|
|
|
|
**3) 정말 내려갔는지 확인**
|
|
|
|
```bash
|
|
sudo ss -tlnp | grep 5281 # 아무것도 안 나오면 성공
|
|
```
|
|
|
|
> .NET 은 `SIGINT`(`kill -INT`) 를 받아야 정상 종료합니다.
|
|
> 그냥 `kill` (SIGTERM) 이나 `kill -9` 는 쓰던 파일을 정리하지 못하고 끊길 수 있습니다.
|
|
|
|
### 서버 준비 (처음 한 번)
|
|
|
|
```bash
|
|
sudo useradd -r -s /usr/sbin/nologin genesis
|
|
sudo mkdir -p /srv/genesis/wwwroot/uploads
|
|
sudo chown -R genesis:genesis /srv/genesis
|
|
|
|
# 비밀값
|
|
sudo cp deploy/genesis.env.example /srv/genesis/genesis.env
|
|
sudo nano /srv/genesis/genesis.env
|
|
sudo chown genesis:genesis /srv/genesis/genesis.env
|
|
sudo chmod 600 /srv/genesis/genesis.env
|
|
|
|
# 서비스 등록
|
|
sudo cp deploy/genesis.service /etc/systemd/system/
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl enable --now genesis
|
|
```
|
|
|
|
### 올리기 · 갱신
|
|
|
|
```powershell
|
|
.\deploy\publish-linux.ps1 -Target user@서버주소 # PowerShell
|
|
```
|
|
```bash
|
|
./deploy/publish-linux.sh user@서버주소 # bash
|
|
```
|
|
|
|
빌드 → 전송 → 실행 권한 부여까지 한 번에 합니다.
|
|
(bash 판은 rsync 를, PowerShell 판은 scp 를 씁니다. 둘 다 서버의 사진을 지우지 않습니다.)
|
|
**업로드된 사진(`wwwroot/uploads`)과 `genesis.env` 는 건드리지 않습니다.**
|
|
|
|
수동으로 할 때도 이 두 가지는 반드시 지켜야 합니다.
|
|
|
|
```bash
|
|
rsync -avz --delete --exclude 'wwwroot/uploads/' --exclude 'genesis.env' artifacts/linux-x64/ user@서버:/srv/genesis/
|
|
|
|
ssh user@서버 "chmod +x /srv/genesis/GameServer && sudo systemctl restart genesis"
|
|
```
|
|
|
|
> `chmod +x` 를 빼먹기 쉽습니다. 윈도우에서 복사하면 실행 권한이 사라져
|
|
> `Permission denied` 로 서비스가 안 뜹니다.
|
|
|
|
### 배포 후 확인
|
|
|
|
산출물에 들어 있는 `healthcheck.sh` 를 서버에서 실행하면 한 번에 점검합니다.
|
|
|
|
```bash
|
|
cd /home/ubuntu/gameserver # 앱이 있는 폴더
|
|
./healthcheck.sh 5000 GameServer # 포트, 서비스 이름
|
|
```
|
|
|
|
이런 것들을 확인합니다.
|
|
|
|
1. 서비스가 `active (running)` 인지, 반복 재시작 중은 아닌지
|
|
2. 포트를 실제로 듣고 있는지
|
|
3. **기존 게임 API (`/myGame/*`) 가 그대로 되는지**
|
|
4. 포트폴리오 API 와 카테고리 개수 (0 개면 DB 스키마 생성 실패)
|
|
5. 사이트 정적 파일 (`/`, `css`, `js`)
|
|
6. 업로드 폴더 쓰기 권한
|
|
7. 최근 로그의 오류
|
|
|
|
실패한 항목이 있으면 종료 코드 1 을 돌려주므로 자동화에도 쓸 수 있습니다.
|
|
|
|
직접 보고 싶다면:
|
|
|
|
```bash
|
|
sudo systemctl status GameServer
|
|
sudo journalctl -u GameServer -n 100 --no-pager
|
|
sudo journalctl -u GameServer -f # 실시간
|
|
sudo ss -tlnp | grep 5000
|
|
curl -s localhost:5000/api/portfolio/categories
|
|
```
|
|
|
|
정상이라면 로그에 이 세 줄이 보입니다.
|
|
|
|
```
|
|
포트폴리오 스키마 준비 완료 (카테고리 N건).
|
|
Now listening on: http://0.0.0.0:5000
|
|
Application started. Press Ctrl+C to shut down.
|
|
```
|
|
|
|
> `Failed to determine the https port for redirect.` 경고는 무시해도 됩니다.
|
|
> HTTP 로만 띄웠을 때 늘 나오는 안내입니다.
|
|
|
|
### 어느 방식을 고를까
|
|
|
|
| | 자체 포함 배포 | 도커 |
|
|
|---|---|---|
|
|
| 서버에 필요한 것 | 없음 | Docker |
|
|
| 전송량 | 53MB | 이미지 레이어 |
|
|
| 격리 | systemd 수준 | 컨테이너 |
|
|
| 롤백 | 이전 폴더로 교체 | 이전 이미지 태그 |
|
|
|
|
혼자 쓰는 서버라면 **자체 포함 배포가 더 단순합니다.** 도커 쪽은 아래 6절에 있습니다.
|
|
|
|
---
|
|
|
|
## 6. 리눅스 컨테이너로 배포하기
|
|
|
|
### 준비물
|
|
|
|
로컬(윈도우)에서 이미지를 만들 필요는 없습니다. **서버에서 바로 빌드하는 쪽이 간단합니다.**
|
|
|
|
- 서버: Docker Engine + Compose 플러그인
|
|
```bash
|
|
curl -fsSL https://get.docker.com | sudo sh
|
|
sudo usermod -aG docker $USER # 다시 로그인해야 적용됩니다
|
|
```
|
|
- VS Code(선택): 확장 두 개
|
|
- **Docker** (`ms-azuretools.vscode-docker`) — Dockerfile 문법 지원, 이미지·컨테이너 목록, 우클릭 빌드/실행
|
|
- **Remote - SSH** (`ms-vscode-remote.remote-ssh`) — 서버에 붙어서 그대로 편집·실행
|
|
|
|
Visual Studio 의 "Docker 지원 추가 → 게시" 같은 원클릭 배포는 VS Code 에 없습니다.
|
|
대신 Remote-SSH 로 서버에 붙어 아래 명령을 터미널에서 실행하는 흐름이 표준입니다.
|
|
|
|
### 첫 배포
|
|
|
|
```bash
|
|
git clone <저장소 주소> genesis && cd genesis
|
|
|
|
cp .env.example .env
|
|
nano .env # DB 연결 문자열 · 관리자 비밀번호 입력
|
|
|
|
mkdir -p uploads
|
|
sudo chown -R 1654:1654 uploads # 컨테이너의 app 사용자가 쓸 수 있게
|
|
|
|
docker compose up -d --build
|
|
```
|
|
|
|
`http://서버주소:5281` 로 접속됩니다.
|
|
|
|
### 다시 배포
|
|
|
|
```bash
|
|
git pull
|
|
docker compose up -d --build
|
|
```
|
|
|
|
업로드된 사진은 호스트의 `./uploads` 에 있으므로 재배포해도 그대로 남습니다.
|
|
|
|
### 확인 · 문제 해결
|
|
|
|
```bash
|
|
docker compose ps # 상태 (healthy 여야 정상)
|
|
docker compose logs -f # 로그
|
|
docker compose down # 중지
|
|
```
|
|
|
|
- **업로드가 403/500 으로 실패** → `uploads` 폴더 소유자 문제입니다.
|
|
`sudo chown -R 1654:1654 uploads` 를 다시 확인하세요.
|
|
- **DB 에 못 붙음** → 컨테이너 안에서 `localhost` 는 컨테이너 자신입니다.
|
|
DB 가 같은 서버에 있어도 `.env` 에는 실제 IP 를 적어야 합니다.
|
|
- **앞에 nginx 를 두는 경우** → `docker-compose.yml` 의 포트를
|
|
`"127.0.0.1:5281:8080"` 으로 바꿔 외부 직접 접근을 막으세요.
|
|
|
|
### 컨테이너 없이 배포할 때
|
|
|
|
`dotnet publish` 산출물만 올려도 됩니다. 이때 **업로드 폴더는 덮어쓰지 마세요.**
|
|
`GameServer.csproj` 에서 `wwwroot/uploads` 를 배포 산출물에서 빼 두었으므로
|
|
publish 결과에는 사진이 들어가지 않습니다(12MB). 서버의 기존 `wwwroot/uploads` 는
|
|
그대로 두고 나머지 파일만 교체하면 됩니다.
|
|
|
|
---
|
|
|
|
## 7. 보안 메모
|
|
|
|
- 조회는 누구나, **작성 · 수정 · 삭제는 로그인한 관리자만** 가능합니다 (쿠키 세션).
|
|
- 로그인은 IP별 **5분에 8회**로 제한됩니다.
|
|
- 업로드는 확장자뿐 아니라 **매직 바이트**까지 검사합니다. 파일명은 서버가 GUID 로 새로 짓습니다.
|
|
- 이미지 삭제는 경로를 절대경로로 해석해 **`uploads` 폴더 밖이면 거부**합니다.
|
|
- 마크다운은 **먼저 escape 한 뒤 HTML 을 조립**하므로 본문에 넣은 태그가 실행되지 않습니다.
|
|
링크는 `http` · `https` · `mailto` 와 사이트 내부 경로만 허용합니다.
|
|
|
|
### 아직 남은 것
|
|
|
|
`appsettings.json` 에 **DB 비밀번호가 평문으로 들어 있고 git 에 커밋돼 있습니다.**
|
|
이 저장소를 공개할 계획이 있다면 연결 문자열을 환경변수
|
|
(`ConnectionStrings__DefaultConnection`)나 사용자 비밀로 옮기고,
|
|
노출된 DB 비밀번호를 교체하는 것을 권합니다.
|