아이패드에서 사용할 웹 IDE 구축하기

회사 동료로부터 아이패드를 저렴하게 중고로 구매한 이후에 문득 든 생각이 있었습니다. 왜 아이패드로는 개발을 하지 않는가? 못하는건가? 제가 생각하기에 다음의 두 가지 방법이 가능할 것으로 기대됩니다. VDI 환경을 구축하고 원격으로 화면만 연동하거나 원격 서버에 연결되는 웹 IDE를 사용하는 것입니다. 전자는 작업 크기에 비해서 너무 많은 것들을 요구하기 때문에 저는 후자를 관심있게 살펴보았고, 이미 많은 분들이 관련해서 남겨주신 글들을 확인할 수 있었습니다.

이 구글패드를 어찌할꼬? 게임만 할 수는 없다!

웹 IDE를 이용하는 방법도 크게 두 가지로 나눌 수 있었습니다. 오픈소스를 이용해서 직접 원격지 서버를 구축하는 방법과 상용 솔루션을 이용하는 방법입니다. 물론 가격면에서는 직접 구축하는 편이 유리하겠으나, 서버를 사용할 때만 직접 켜거나 끄는 등의 불편함을 감수할 수 있는지같은 편의성도 고려를 해봐야 합니다.

VS Code에는 아주 훌륭한 플러그인들이 많은데, 저는 그 중에서도 컨테이너를 이용하여 개발할 수 있도록 도와주는 플러그인을 주로 사용해왔습니다. 호스트 머신에 다양한 바이너리를 설치하지 않고도 컨테이너 내부의 환경에서 미리 정의되고 설치된 바이너리를 이용한 개발을 할 수 있습니다. 이러한 개발의 장점은 개발 환경을 다른 사람에게 구두로 또는 문서로 알려줄 필요가 없고, 미리 정의된 .devcontainer 파일만 소스에 담아서 전달하면 끝입니다. 아무튼, 컨테이너 개발 환경을 구축하다 보면 컨테이너 내부에 VS Code Server가 설치되는 것을 알 수 있습니다. 그래서 이 부분만 별도로 분리해서 설치하고 웹소켓을 제공하는 code-server를 이용한다면, 웹 브라우저를 통해서도 IDE 환경을 구현하는 것이 가능합니다. 게다가 자주 사용하는 VS Code의 UI와 기능 그대로 제공되므로 매우 익숙한 환경이 될 것입니다.

AWS의 Cloud9은 위와 같은 웹 IDE 환경을 손쉽게 구축, 관리할 수 있도록 도와주는 서비스입니다. 무료로 제공되기 때문에 오직 원격 서버 비용만 지불하면 되는데, 평가가 좀 애매합니다. AWS와의 Integration은 강력하지만, IDE 자체로는 어중간하기 때문입니다. 흥미롭게도 Cloud9 환경에서 제공되는 비용 절감 옵션을 사용하면 특정 시간동안 작업이 없을 경우에 인스턴스가 자동으로 Hibernate된다고 합니다. 비용에 신경쓰이는 저로서는 매우 훌륭한 옵션입니다.

이러한 점들을 종합하여 저는 VS Code의 code-server를 직접 설치하되, AWS Cloud9을 사용하여 인스턴스를 관리해보기로 합니다. 글을 마무리할 무렵에 Cloud9은 제가 기대했던 것처럼 동작하지 않는다는 것을 깨닫고 결론적으로, Cloud9은 모두 제거하고 결국 EC2로만 구축하기로 결정했습니다.

구축

EC2

EC2는 t3.medium 타입, OS는 Ubuntu 20.04 버전으로 생성하였습니다. 해당 인스턴스 타입을 한 달에 100시간 사용을 가정하면 어지간한 카페의 커피 한 잔 값이 나올 것으로 기대합니다. 보안그룹은 뒤에서 다시 언급하겠지만, SSL 인증서를 취득할 때 인증을 위한 80 포트의 퍼블릭 인바운드와 실제 code-server에서 사용하게 될 443 포트에 대한 내 아이피 대역을 인바운드 룰에 추가하였습니다.

EC2의 보안그룹 설정

인스턴스는 퍼블릭 서브넷에 배포하였기 때문에, EIP를 할당하여 고정된 아이피를 얻을 수 있습니다. 저는 여기에 개인 도메인을 할당하였습니다. 그래야 추후 SSL 인증서를 발급받을 수 있고, https 사용이 가능합니다. 인스턴스 생성시에 특이사항으로는 ssh 키를 설정하지 않은 것입니다. 저는 SSM의 Session Manager를 사용하기 때문에 인스턴스의 역할을 생성하고 AmazonEC2RoleforSSM 정책을 연결해줍니다. 이렇게 하면 SSM Agent가 사전 설치된 Ubuntu 환경에서는 자동으로 EC2가 Managed 인스턴스로 등록됩니다. 이러한 인스턴스들은 ssh에 대한 인바운드 없이, 콘솔 또는 CLI의 Session Manager를 이용하여 인스턴스에 접속할 수 있습니다. 보안적으로 매우 훌륭하고, IAM 기반의 인증을 이용할 수 있게 됩니다.

code-server

모든 과정이 정상적으로 완료되었으면 이제 code-server를 설치하기 위한 스크립트를 실행합니다.

curl -fsSL https://code-server.dev/install.sh | sh
Code language: JavaScript (javascript)

스크립트가 실행이 완료되고 나면, 추후 자동시작을 위해 systemctl에 등록을 하도록 합니다.

sudo systemctl enable --now code-server@$USER
Code language: PHP (php)

code-server의 설정은 이것으로 끝입니다.

Nginx

기본적으로 code-server는 서버의 bind ip를 127.0.0.1로 제한하고 있습니다. 그리고 그 앞에 reverse proxy를 설정하도록 권장하고 있으므로 저는 도메인을 인스턴스의 EIP에 연결하고, Nginx와 Let’s Encrypt를 사용하여 https를 구성할 것입니다. [참고]

다음 명령을 통해서 Nginx와 관련 패키지를 설치합니다.

sudo apt update
sudo apt install -y nginx certbot python3-certbot-nginx

정상적으로 도메인을 인식할 수 있도록, Nginx 설정 파일을 생성합니다.

sudo vi /etc/nginx/sites-available/code-server

code-server 파일 안에는 다음과 같은 설정값들을 채워넣으면 됩니다. 본인의 도메인을 지정하거나 server_name을 제외함으로써 아이피를 받을 수도 있습니다.

server {
    listen 80;
    server_name <my_domain>;

    location / {
      proxy_pass http://localhost:8080/;
      proxy_set_header Host $host;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection upgrade;
      proxy_set_header Accept-Encoding gzip;
    }
}
Code language: PHP (php)

이제 설정값을 Nginx에 연결하고 기존에 연결된 default는 삭제합니다.

sudo ln -s /etc/nginx/sites-available/code-server /etc/nginx/sites-enabled/code-server
sudo rm /etc/nginx/sites-enabled/default
Code language: JavaScript (javascript)

Nginx도 설정이 완료되었습니다.

Let’s Encrypt

무료 SSL 인증서를 제공받기 위한 가장 간단한 옵션인 Let’s Encrypt를 위해서는 가장 먼저 도메인 설정에서 레코드를 생성, 앞서 설정한 EIP에 연결합니다. Let’s Encrypt의 도메인 인증 과정을 진행하려면 필수입니다. 그리고 Nginx를 80포트로 사용해야 하고, 퍼블릭 인바운드가 열려있어야 합니다. 이후에 https 연결을 할 것이므로 443 포트에 대한 인바운드도 허용해야 합니다. 방화벽이 준비가 완료되면 다음 명령을 통해서 인증을 진행합니다.

sudo certbot --non-interactive --redirect --agree-tos --nginx -d <my_domain> -m <my_email>
Code language: HTML, XML (xml)

정상적으로 인증이 진행되었다면, 다음과 같은 내용을 확인할 수 있습니다.

/usr/lib/python3/dist-packages/requests/__init__.py:80: RequestsDependencyWarning: urllib3 (1.26.6) or chardet (3.0.4) doesn't match a supported version!
  RequestsDependencyWarning)
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for <my_domain>
Waiting for verification...
Cleaning up challenges
Deploying Certificate to VirtualHost /etc/nginx/sites-enabled/code-server
Redirecting all traffic on port 80 to ssl in /etc/nginx/sites-enabled/code-server

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations! You have successfully enabled <my_domain>

You should test your configuration at:
https://www.ssllabs.com/ssltest/analyze.html?d=<my_domain>
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/<my_domain>/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/<my_domain>/privkey.pem
   Your cert will expire on 2021-12-04. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot again
   with the "certonly" option. To non-interactively renew *all* of
   your certificates, run "certbot renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le
Code language: HTML, XML (xml)

앞으로 90일은 문제가 없지만, 갱신을 수동으로 할 수는 없으므로 갱신에 관한 crontab을 설정해두는 것이 좋습니다.

sudo crontab -e

cron은 다음과 같이 추가하여 매주 일요일 새벽에 갱신하도록 설정한 다음에 Nginx를 재시작할 수 있도록 합니다.

0 19 * * 6 /usr/bin/certbot renew --renew-hook="sudo systemctl restart nginx"
Code language: JavaScript (javascript)

Let’s Encrypt도 설정이 완료되었습니다.

접속

모든 구축이 완료되었으므로, 앞서 설정한 도메인으로 연결합니다. https://으로 접속하면 다음과 같이 로그인 화면이 나타나게 됩니다.

code-server의 로그인 화면

비밀번호는 code-server를 설치한 인스턴스, 즉 Cloud9에서 확인할 수 있습니다. 물론 비밀번호는 변경 가능하나, Plain text로 이루어져 있어서 외부인이 인스턴스에 접근하는 것을 차단하는 것이 좋습니다. 혹은 Nginx 자체의 로그인 기능을 이용하는 것도 방법입니다. [참고]

vi ~/.config/code-server/config.yaml

bind-addr: 127.0.0.1:8080
auth: password
password: xxxxxxxxxxxxxxxxxxxxxxxx
cert: false
Code language: JavaScript (javascript)

비밀번호를 복사하여 로그인하면 드디어 웹 IDE 화면을 볼 수 있습니다.

웹 IDE

결론

본래 계획은 Cloud9을 사용하여 Idle 상태일 경우에 저절로 환경이 중지되도록 하고자 하였습니다. 그래서 작업하던 모든 내용을 종료하고 기다려보니, 30분 정도 후에 정상적으로 인스턴스가 멈추는 것을 확인할 수 있었습니다. 이번에는 Cloud9을 실행하지 않고 단순히 EC2를 실행하여 code-server만 계속 사용을 했는데, 30분 뒤에 인스턴스가 멈춰버렸습니다. 제가 생각했던 것은 어떻게든 인스턴스를 사용하면 상관 없을 것으로 기대했지만, 그렇지 않았습니다.

즉, Cloud9을 정상적으로 이용하기 위해서는 반드시 Cloud9 IDE를 열어두어야 한다는 뜻입니다. 😢 EC2에 처음부터 직접 설치하고 사용하는 것보다는 미사용시에 자동으로 꺼주는 부분은 마음에 들지만, 번거로움은 EC2를 수동으로 실행/중지 하는것과 크게 다를바가 없었습니다. 그래서 저는 Cloud9의 사용을 재고하고 EC2로만 다시 구축하기로 마음먹고 글도 처음 부분부터 다시 작성하였습니다.

최종적으로, code-server를 이용하고자 하는 경우에는 EC2를 수동으로 켜고 끄는 절차를 가져야 합니다. 비용에 큰 걱정이 없다면, 주중에 항상 켜놓고 주말에만 끄는 Lambda를 구성하는 것도 방법이겠지요.

맺음말

아이패드에서 접속한 code-server

자, 우여곡절끝에 이렇게 아이패드에서도 개발할 수 있는 웹 IDE가 구축이 완료되었습니다. 최초로 인스턴스를 실행하는 것은 AWS 콘솔 또는 CLI를 이용할 수 있는데, 아이패드에서는 콘솔을 이용하는 것이 나을 것 같습니다. 중간에 이리저리 헤매기는 했지만, 새롭고 재밌는 환경을 구축했기 때문에 여전히 즐겁습니다. 이 글이 단순히 아이패드를 대상으로 하는 것은 아닙니다. 다만 컴퓨팅 스펙이 떨어지거나 개발이 어려운 환경에서 웹 IDE를 제공할 수 있는 단초가 될 것입니다. 여러분도 꼭 한번은 웹 IDE를 이용해보시길 바라며 글을 마칩니다. 👏

Leave a Reply

Your email address will not be published. Required fields are marked *