RevampIT는 현재 revampit.orangecat.ch에서 Hetzner 위의 셀프 호스트 앱으로 실행됩니다. 공개 도메인 revamp-it.ch는 아직 오래된 Joomla/Apache 사이트를 가리키므로 새 플랫폼의 프로덕션 대상이 아닙니다.
당연한 질문은 이것이었습니다. 우리에게 Coolify, Dokploy, 또는 다른 Platform-as-a-Service 계층이 필요한가? 지금 우리의 답은 아니오입니다. 그런 도구들이 나빠서가 아니라, 그것들이 첫 번째 문제를 해결하지 않기 때문입니다.
실제 문제는 더 단순합니다. 배포는 재현 가능해야 하고, 명확한 품질 게이트를 가져야 하고, 오류 발생 시 롤백해야 하며, 지금 어떤 버전이 실행 중인지 보이게 만들어야 합니다. 이러한 속성들은 같은 프로덕션 서버 위에 새로운 컨트롤 플레인을 올리지 않고도, 우리의 기존 Caddy, systemd, rsync 구조가 직접 얻을 수 있습니다.
그래서 우리는 먼저 기존 경로를 강화합니다. 배포 스크립트는 계속해서 Next.js 스탠드얼론 아티팩트를 빌드하고, 이를 Hetzner 서버로 복사한 후 서비스를 재시작합니다. 새로워진 점은 활성화 전에 이전 릴리스가 보존된다는 것입니다. 서비스가 활성화되지 않거나 /api/health가 성공 상태를 반환하지 않으면 자동으로 롤백됩니다.
추가로 /api/version 엔드포인트가 있습니다. 이것은 앱 버전, Git SHA, 빌드 시간을 보여줍니다. 작지만 중요합니다. 운영과 모니터링은 실제로 무엇이 라이브로 실행 중인지에 대한 명확한 답이 필요합니다.
이 과정에서 한 가지 세부 사항이 결정적이었습니다. .env와 launch.sh 같은 런타임 파일은 Git 리포지토리에 속하지 않지만, 활성화되는 모든 릴리스에 존재해야 합니다. 그래서 배포 스크립트는 새 릴리스를 시작하기 전에 현재 앱 디렉터리에서 이 파일들을 서버 로컬로 가져옵니다.
Meilisearch도 이제 다시 운영 그림의 일부입니다. 앱은 Meilisearch 없이 SQL 검색으로 폴백할 수 있었지만, 그로 인해 /api/health는 degraded 상태에 불과했습니다. 그래서 Hetzner 서버에서 Meilisearch는 서버 로컬 키를 가진 localhost 전용 Docker 서비스로 실행됩니다.
GitHub 배포 워크플로도 더 명확한 게이트를 얻습니다. 린트와 타입체크가 프로덕션 배포 전에 실행됩니다. 로컬 푸시 배포는 편리하게 유지되지만, 장기적으로 유일한 진실이 되어서는 안 됩니다. 목표 상태는 이것입니다. GitHub가 빌드하고, 검사하고, 배포하며, 로컬 배포는 예외적인 경우를 위한 수동 도구로 남는 것입니다.
나중에 올 수 있는 것은 이것입니다. 많은 앱, 고객 환경, 셀프 서비스 배포를 운영하게 되면 컨트롤 플레인이 합리적일 수 있습니다. 그때 우리는 Coolify, Dokploy, 또는 Kamal을 냉정하게 검토합니다. 그때까지는 이렇게 합니다. 플랫폼은 더 적게, 신뢰할 수 있는 운영 규율은 더 많이.
