공개: KoTalk 최신 기준선
This commit is contained in:
commit
debf62f76e
572 changed files with 41689 additions and 0 deletions
11
deploy/.env.example
Normal file
11
deploy/.env.example
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
COMPOSE_PROJECT_NAME=kotalk
|
||||
ACME_EMAIL=admin@example.com
|
||||
API_HOST=api.example.com
|
||||
DOWNLOAD_HOST=download-vstalk.phy.kr
|
||||
DOWNLOAD_ROOT=/srv/kotalk/download
|
||||
WEBAPP_HOST=vstalk.phy.kr
|
||||
WEBAPP_RELEASE_ROOT=/srv/kotalk/webapp/current
|
||||
BOOTSTRAP_INVITE_CODE=change-me-in-private-env
|
||||
JWT_ISSUER=KoTalk
|
||||
JWT_AUDIENCE=KoTalk.Client
|
||||
JWT_SIGNING_KEY=change-me-to-a-long-random-value
|
||||
49
deploy/Caddyfile
Normal file
49
deploy/Caddyfile
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
email {$ACME_EMAIL}
|
||||
}
|
||||
|
||||
{$DOWNLOAD_HOST} {
|
||||
encode zstd gzip
|
||||
root * /srv/download
|
||||
redir /windows /windows/latest 302
|
||||
redir /android /android/latest 302
|
||||
redir /windows/latest /windows/latest/VsMessenger-win-x64.zip 302
|
||||
redir /android/latest /android/latest/VsMessenger-android-universal.apk 302
|
||||
redir /latest /latest/version.json 302
|
||||
header {
|
||||
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
|
||||
X-Content-Type-Options "nosniff"
|
||||
X-Frame-Options "DENY"
|
||||
Referrer-Policy "strict-origin-when-cross-origin"
|
||||
}
|
||||
file_server
|
||||
}
|
||||
|
||||
{$WEBAPP_HOST:vstalk.phy.kr} {
|
||||
encode zstd gzip
|
||||
header {
|
||||
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
|
||||
X-Content-Type-Options "nosniff"
|
||||
X-Frame-Options "DENY"
|
||||
Referrer-Policy "strict-origin-when-cross-origin"
|
||||
}
|
||||
handle /v1/* {
|
||||
reverse_proxy api:8080
|
||||
}
|
||||
handle /health {
|
||||
reverse_proxy api:8080
|
||||
}
|
||||
handle {
|
||||
reverse_proxy webapp:80
|
||||
}
|
||||
}
|
||||
|
||||
{$API_HOST} {
|
||||
encode zstd gzip
|
||||
header {
|
||||
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
|
||||
X-Content-Type-Options "nosniff"
|
||||
Referrer-Policy "strict-origin-when-cross-origin"
|
||||
}
|
||||
reverse_proxy api:8080
|
||||
}
|
||||
29
deploy/README.md
Normal file
29
deploy/README.md
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
# Deployment Guide
|
||||
|
||||
이 디렉터리는 KoTalk의 범용 배포 골격을 담습니다.
|
||||
|
||||
## Public Endpoints
|
||||
|
||||
- 모바일 웹: [vstalk.phy.kr](https://vstalk.phy.kr)
|
||||
- 공식 다운로드 미러: [download-vstalk.phy.kr](https://download-vstalk.phy.kr)
|
||||
- 버전 메타데이터: [download-vstalk.phy.kr/latest/version.json](https://download-vstalk.phy.kr/latest/version.json)
|
||||
|
||||
## Intended Shape
|
||||
|
||||
- `Caddyfile`: 웹 진입점, 다운로드 미러, API 프록시
|
||||
- `compose*.yml`: API, 정적 웹, 보조 서비스 구성
|
||||
- `docker/`: 이미지 빌드 정의
|
||||
|
||||
## Public Rules
|
||||
|
||||
- 실서비스 호스트 주소, 관리자 계정, 비밀값은 공개 문서에 적지 않습니다.
|
||||
- 운영 중인 컨테이너명과 네트워크명은 공개 표면의 필수 정보가 아닙니다.
|
||||
- 배포 예시는 범용 구조 중심으로 유지합니다.
|
||||
|
||||
## Download Layout
|
||||
|
||||
- `/windows/latest`
|
||||
- `/android/latest`
|
||||
- `/latest/version.json`
|
||||
|
||||
실제 공개 릴리즈 경로는 [RELEASING.md](../RELEASING.md)와 함께 봐야 합니다.
|
||||
42
deploy/compose.mvp.yml
Normal file
42
deploy/compose.mvp.yml
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
services:
|
||||
caddy:
|
||||
image: caddy:2.9-alpine
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- api
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
environment:
|
||||
ACME_EMAIL: ${ACME_EMAIL}
|
||||
API_HOST: ${API_HOST}
|
||||
DOWNLOAD_HOST: ${DOWNLOAD_HOST}
|
||||
WEBAPP_HOST: ${WEBAPP_HOST:-vstalk.phy.kr}
|
||||
volumes:
|
||||
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
||||
- caddy-data:/data
|
||||
- caddy-config:/config
|
||||
- ${DOWNLOAD_ROOT}:/srv/download:ro
|
||||
|
||||
api:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: deploy/docker/api.Dockerfile
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
ASPNETCORE_ENVIRONMENT: Production
|
||||
ASPNETCORE_URLS: http://0.0.0.0:8080
|
||||
ConnectionStrings__Main: Data Source=/data/vs-messenger.db
|
||||
Auth__Jwt__Issuer: ${JWT_ISSUER}
|
||||
Auth__Jwt__Audience: ${JWT_AUDIENCE}
|
||||
Auth__Jwt__SigningKey: ${JWT_SIGNING_KEY}
|
||||
Bootstrap__InviteCodes__0: ${BOOTSTRAP_INVITE_CODE}
|
||||
volumes:
|
||||
- api-data:/data
|
||||
expose:
|
||||
- "8080"
|
||||
|
||||
volumes:
|
||||
caddy-config:
|
||||
caddy-data:
|
||||
api-data:
|
||||
9
deploy/compose.webapp.yml
Normal file
9
deploy/compose.webapp.yml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
services:
|
||||
webapp:
|
||||
image: nginx:1.27-alpine
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ${WEBAPP_RELEASE_ROOT:-/srv/vs-messanger/webapp/current}:/usr/share/nginx/html:ro
|
||||
- ./docker/webapp.nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
||||
expose:
|
||||
- "80"
|
||||
25
deploy/docker/api.Dockerfile
Normal file
25
deploy/docker/api.Dockerfile
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||
WORKDIR /src
|
||||
|
||||
COPY ["PhysOn.sln", "./"]
|
||||
COPY ["global.json", "./"]
|
||||
COPY ["src/PhysOn.Api/PhysOn.Api.csproj", "src/PhysOn.Api/"]
|
||||
COPY ["src/PhysOn.Application/PhysOn.Application.csproj", "src/PhysOn.Application/"]
|
||||
COPY ["src/PhysOn.Contracts/PhysOn.Contracts.csproj", "src/PhysOn.Contracts/"]
|
||||
COPY ["src/PhysOn.Domain/PhysOn.Domain.csproj", "src/PhysOn.Domain/"]
|
||||
COPY ["src/PhysOn.Infrastructure/PhysOn.Infrastructure.csproj", "src/PhysOn.Infrastructure/"]
|
||||
|
||||
RUN dotnet restore "src/PhysOn.Api/PhysOn.Api.csproj"
|
||||
|
||||
COPY . .
|
||||
RUN dotnet publish "src/PhysOn.Api/PhysOn.Api.csproj" -c Release -o /app/publish /p:UseAppHost=false
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
|
||||
WORKDIR /app
|
||||
|
||||
ENV ASPNETCORE_URLS=http://0.0.0.0:8080
|
||||
EXPOSE 8080
|
||||
|
||||
COPY --from=build /app/publish .
|
||||
|
||||
ENTRYPOINT ["dotnet", "PhysOn.Api.dll"]
|
||||
23
deploy/docker/webapp.nginx.conf
Normal file
23
deploy/docker/webapp.nginx.conf
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
location /assets/ {
|
||||
expires 7d;
|
||||
add_header Cache-Control "public, max-age=604800, immutable";
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|svg|ico|webp|woff2?)$ {
|
||||
expires 7d;
|
||||
add_header Cache-Control "public, max-age=604800, immutable";
|
||||
try_files $uri =404;
|
||||
}
|
||||
}
|
||||
22
deploy/docker/worker.Dockerfile
Normal file
22
deploy/docker/worker.Dockerfile
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||
WORKDIR /src
|
||||
|
||||
COPY ["PhysOn.sln", "./"]
|
||||
COPY ["global.json", "./"]
|
||||
COPY ["src/PhysOn.Worker/PhysOn.Worker.csproj", "src/PhysOn.Worker/"]
|
||||
COPY ["src/PhysOn.Application/PhysOn.Application.csproj", "src/PhysOn.Application/"]
|
||||
COPY ["src/PhysOn.Contracts/PhysOn.Contracts.csproj", "src/PhysOn.Contracts/"]
|
||||
COPY ["src/PhysOn.Domain/PhysOn.Domain.csproj", "src/PhysOn.Domain/"]
|
||||
COPY ["src/PhysOn.Infrastructure/PhysOn.Infrastructure.csproj", "src/PhysOn.Infrastructure/"]
|
||||
|
||||
RUN dotnet restore "src/PhysOn.Worker/PhysOn.Worker.csproj"
|
||||
|
||||
COPY . .
|
||||
RUN dotnet publish "src/PhysOn.Worker/PhysOn.Worker.csproj" -c Release -o /app/publish /p:UseAppHost=false
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/runtime:8.0 AS runtime
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=build /app/publish .
|
||||
|
||||
ENTRYPOINT ["dotnet", "PhysOn.Worker.dll"]
|
||||
16
deploy/systemd/vs-messanger-mvp.service
Normal file
16
deploy/systemd/vs-messanger-mvp.service
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
[Unit]
|
||||
Description=vs-messanger MVP docker compose stack
|
||||
Requires=docker.service
|
||||
After=docker.service network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
WorkingDirectory=/srv/vs-messanger/app
|
||||
RemainAfterExit=yes
|
||||
ExecStart=/usr/bin/docker compose --project-name vs-messanger --env-file deploy/.env -f deploy/compose.mvp.yml up -d --build --remove-orphans
|
||||
ExecStop=/usr/bin/docker compose --project-name vs-messanger --env-file deploy/.env -f deploy/compose.mvp.yml down
|
||||
TimeoutStartSec=0
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
16
deploy/systemd/vs-messanger-webapp.service
Normal file
16
deploy/systemd/vs-messanger-webapp.service
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
[Unit]
|
||||
Description=vs-messanger mobile webapp compose stack
|
||||
Requires=docker.service
|
||||
After=docker.service network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
WorkingDirectory=/srv/vs-messanger/app
|
||||
RemainAfterExit=yes
|
||||
ExecStart=/usr/bin/docker compose --project-name vs-messanger --env-file deploy/.env -f deploy/compose.mvp.yml -f deploy/compose.webapp.yml up -d webapp caddy
|
||||
ExecStop=/usr/bin/docker compose --project-name vs-messanger --env-file deploy/.env -f deploy/compose.mvp.yml -f deploy/compose.webapp.yml stop webapp
|
||||
TimeoutStartSec=0
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Loading…
Add table
Add a link
Reference in a new issue