Ubuntu 18.04에 JupyterHub 설치 및 설정 완성

Ubuntu 18.04에 설치하며, domain이 있는 경우에 한해서 설치하는 방법을 기술한다.
분명 1~2년 뒤에 ubuntu 갈아엎을 일이 생길텐데, 이 때 까먹어서 시간낭비하는 것을 방지하기 위해서 기록한다.

  1. 도메인을 구입한다.

    • 나는 바보같이 http://hosting.kr 에서 비싼 돈 내고 구입했으나, 구글링을 하면 미국에서 아주 싸게 구입할 수 있다. 아무튼 구입은 해야 한다.
    • IP주소 연결과 서브도메인 설정하기. 추가한 서브도메인은 www.ohmycarpenter.comjpt.ohmycarpenter.com 이다.
      • hosting.kr에서는 '네임서버(서브도메인) 설정 관리' 메뉴로 들어가서 설정해야 한다.
      • 나는 ohmycarpenter.com, www.ohmycarpenter, jpt.ohmycarpenter.com 모두 같은 IP로 밀어넣었다.
  2. Let's Encrypt 를 설치한다.

    • apt로 설치한다.
      sudo -H ./letsencrypt-auto certonly --apache -d ohmycarpenter.com -d www.ohmycarpenter -d jpt.ohmycarpenter.com
      sudo add-apt-repository ppa:certbot/certbot
      sudo apt-get install certbot
      sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096
      ## pem 파일들 권한 조정한다.
    • 다음 명령어로 letsencrypt 인증서를 매월 1일마다 갱신하게 만든다.
      sudo crontab -e
      # 다음 줄을 추가한다.
      0 0 1 * * /bin/bash -l -c "certbot renew --quiet"
  3. Apache2 서버 설정을 한다.

    • 다음 명령어로 apache2 설치
      sudo apt install apache2
    • /etc/apache2/sites-available에 다음과 같이 네 개의 파일을 생성

      # file: http.jpt.ohmycarpenter.com.conf
      <VirtualHost *:80>
      ServerName jpt.ohmycarpenter.com
      Redirect / https://jpt.ohmycarpenter.com/
      ServerAlias jpt.ohmycarpenter.com
      </VirtualHost>
      # file: https.jpt.ohmycarpenter.com.conf
      <IfModule mod_ssl.c>
        <VirtualHost *:443>
          ServerName jpt.ohmycarpenter.com
          ServerAlias jpt.ohmycarpenter.com
      
            # configure SSL
          SSLEngine on
      
          SSLCertificateFile /some/where/ohmycarpenter.com/full_chain.pem
          SSLCertificateKeyFile /some/where/ohmycarpenter.com/priv_key.pem
          SSLProtocol All -SSLv2 -SSLv3
          SSLOpenSSLConfCmd DHParameters /etc/ssl/certs/dhparam.pem
          SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH
      
          # Use RewriteEngine to handle websocket connection upgrades
          RewriteEngine On
          RewriteCond %{HTTP:Connection} Upgrade [NC]
          RewriteCond %{HTTP:Upgrade} websocket [NC]
          RewriteRule /(.*) ws://127.0.0.1:8000/\ [P,L]
      
          <Location "/">
          # preserve Host header to avoid cross-origin problems
          ProxyPreserveHost on
          # proxy to JupyterHub
          ProxyPass         http://127.0.0.1:8000/
          ProxyPassReverse  http://127.0.0.1:8000/
          </Location>
      </VirtualHost>
      </IfModule>
      # file: http.www.ohmycarpenter.com.conf
      <VirtualHost *:80>
      ServerName www.ohmycarpenter.com
      ServerAlias www.ohmycarpenter.com ohmycarpenter.com
      
      ServerAdmin webmaster@localhost
      Redirect / https://www.ohmycarpenter.com/
      
      ErrorLog ${APACHE_LOG_DIR}/error.log
      CustomLog ${APACHE_LOG_DIR}/access.log combined
      </VirtualHost>
      # file: https.www.ohmycarpenter.com.conf
      <IfModule mod_ssl.c>
      # <VirtualHost _default_:443>
      <VirtualHost *:443>
              ServerAdmin webmaster@localhost
      
              DocumentRoot /home2/www/wordpress
              ErrorLog ${APACHE_LOG_DIR}/error.log
              CustomLog ${APACHE_LOG_DIR}/access.log combined
      
              SSLEngine on
              SSLCertificateFile      /some/where/ohmycarpenter.com/cert1.pem
              SSLCertificateKeyFile /some/where/ohmycarpenter.com/priv_key.pem
              SSLCertificateChainFile /some/where/ohmycarpenter.com/chain1.pem
              SSLProtocol All -SSLv2 -SSLv3
              SSLOpenSSLConfCmd DHParameters /etc/ssl/certs/dhparam.pem
              SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH
      
              ServerAdmin oh.donghyun77@gmail.com
              ServerName ohmycarpenter.com
              ServerAlias www.ohmycarpenter.com
      
              <Directory /home2/www/wordpress/>
              AllowOverride All
              </Directory>
      
              <FilesMatch "\.(cgi|shtml|phtml|php)$">
                              SSLOptions +StdEnvVars
              </FilesMatch>
              <Directory /usr/lib/cgi-bin>
                              SSLOptions +StdEnvVars
              </Directory>
      </VirtualHost>
      </IfModule>
      #위 네개의 파일에 대해 symbolic link를 만든다.
      ln -s /etc/apache2/sites-available/http.www.ohmycarpenter.com /etc/apache2/sites-enabled/http.www.ohmycarpenter.com
      ln -s /etc/apache2/sites-available/https.www.ohmycarpenter.com /etc/apache2/sites-enabled/https.www.ohmycarpenter.com
      ln -s /etc/apache2/sites-available/http.jpt.ohmycarpenter.com /etc/apache2/sites-enabled/httpjpt.ohmycarpenter.com
      ln -s /etc/apache2/sites-available/https.jpt.ohmycarpenter.com /etc/apache2/sites-enabled/https.jpt.ohmycarpenter.com
  4. wordpress 를 설치한다.

    • 웹사이트 돌아다니면서 가장 간단하게 설명해 놓은 것을 참조해서 설치한다.
    • wordpress 루트 디렉토리를 www-data user, group으로 한정 및 755로 권한 조정하고, wp-config.php 파일은 640으로 권한 조정
    • 필수 설치 플러그인: all in one wp security, cc-syntax-highlight, easy updates manager, jetpack, really simple ssl (돈 안 내도 됨), 고전 편집기, WP Githuber MD
    • All In One WP Security로 보안 테스트 및 설정한다.
  5. JupyterHub를 설치한다.

    • 다음 명령어로 TLJH를 설치한다.
      sudo apt install python3 python3-dev git curl
      sudo adduser jpthub_admin_id
      curl https://raw.githubusercontent.com/jupyterhub/the-littlest-jupyterhub/master/bootstrap/bootstrap.py | sudo -E python3 - --admin jpthub_admin_id
    • 다음 명령어로 아파치 서버와 jupyterhub를 시작한다.
      sudo systemctl start apache2
    • 다음 명령어로 jupyterhub 설정을 한다.
      sudo tljh-config set https.tls.key /some/where//ohmycarpenter.com/priv_key.pem
      sudo tljh-config set https.tls.cert /some/where/ohmycarpenter.com/chain.pem
      sudo tljh-config reload proxy
      sudo tljh-config set user_environment.default_app jupyterlab
      sudo tljh-config set limits.memory 40G
      sudo tljh-config add-item users.admin another_admin_id_existed_in_ubuntu
      sudo tljh-config reload
  6. Tensorflow 설치를 한다.

    • NVIDIA GPU driver 410, CUDA toolkit 10.0, cuDNN 7.4 를 매뉴얼을 따라서 설치한다. Tensorflow 버전마다 지원하는 CUDA가 다른 듯 하니 버전을 잘 살펴가면서 설치해야 할 듯. 참고 사이트: https://www.tensorflow.org/install/gpu
      apt로 cuda-10-0, cudnn-7-4-2, nvidia-driver-410 설치하면 tensorflow-2.0.0 설치 가능
    • pip로 tensorflow-gpu를 설치한다.
      sudo apt-get -y install python3-pip
      sudo pip3 install tensorflow-gpu==2.0.0 # 2.0.0 버전 설치 명기
  7. Jupyterhub에 jpt_admin_id로 로긴을 하고 python 필수 패키지들과 Anaconda, iRkernel을 설치한다.

    • New -> Terminal로 들어가서 다음 명령어로 python 패키지들 설치
      sudo -E pip3 install packages # keras, coffee, pandas, etc.
    • 다음 명령어로 Anaconda3 설치: 이미 R이 설치도어 있으면, 사실 iRKernel 설치하는데 Anaconda는 필요하지 않은 듯
      cd ~/tmp
      curl -O https://repo.anaconda.com/archive/Anaconda3-2019.10-Linux-x86_64.sh
      bash Anaconda3-2019.10-Linux-x86_64.sh
      conda update --all
    • 다음 명령어로 R에서 다음 명령어를 넣어서 iRKernel을 설치
      install.packages('IRkernel')
      IRkernel::installspec() 
      ## remove unnecessary environment settings in $HOME/.Rprofile, such as options(device = "x11").
  8. JupyterHub에서 admin -> user 관리는 메뉴가 뜨기도 했다가 안 뜨기도 했다가 하는 듯. 나중에 버전 업데이트 되면서 고쳐지면 좋을 듯 하다.

2019년 겨울방학

2019년 2학기를 마치고 완전히 녹초가 되었다.
내 인생 계획에도 없던 공업수학을 가르치지를 않나,
여기저기 생각지도 않았던 회의에도 끌려다니고,
학생들은 쉴새없이 찾아오고,
자잘한 프로젝트에,
학교 회의까지.

늦는 날은 새벽 2시에 퇴근을 하고,
일찍 퇴근하는 날에는 사람들과 술을 먹게 되었다.
내가 술을 마시는 건지,
술이 나를 마시는 건지 모를 때까지 마시는게 다반사가 되었고,
아침에 일어나서 전날 과음을 후회하고는 했다.

술을 먹고 나면 숙취가 며칠을 가는데,
술이 제대로 깨지도 않은 상태에서 또 술을 마시니,
몸이 슬슬 맛이 가기 시작했다.

안 그래도 몸이 힘들어 죽겠는데,
술을 안 마시고 집에 들어가는 날에는 스트레스 때문에 잠이 오지 않아,
소주 한두병 혼술하고 자는게 거의 일상이 되고 말았다.

2019년 12월 20일 정성도 박사네 집에서 송년 모임을 하면서 과음을 한 나머지,
담배를 피러 밖에 나갔다가 정박사네 집을 못 찾아가는 지경에 이르게 되었다.
다음날 아침에 제대로 일어나지도 못했을 뿐더러,
속이 너무 쓰리다 못해 명치까지 한대 후려맞은 것처럼 아파와서 밀린 일들을 제대로 처리할 수가 없었다.

===============================

그 동안 너무 가족에게 소홀히 한 것 같아서,
2019년 12월 22일 가족들과 함께 대전 유성온천에 놀러갔다.

"상훈아, 엄마랑 온천할래, 아빠랑 온천할래?"

너무 피곤하고 힘들어서 내심 상훈이가 와이프와 목욕하기를 바래면서 물어봤다.
다행히 상훈이는 누나들, 와이프랑 목욕을 한다고 했고,
나는 혼자 남탕에 들어갔다.

너무 머리가 아프고 어지러워서 온천에 오래 앉아있지도 못하고 일찍 목욕을 마쳤다.
시간이 남아서 TV를 보다가 혈압을 재봤는데, 161에 98.

그 동안 너무 내 몸을 막 대했다는 자책감이 들었다.
이러다가 금방 죽을 수 있겠다는 두려움이 들었고,
나 죽으면 우리 가족 뿔뿔이 흩어진다는 겁이 났다.

온천을 나와서 담배와 라이터를 쓰레기통에 버렸다.

"아빠 오늘부터 술이랑 담배 끊어볼게."

수도없이 했던 말이라 가족들이 믿지 않는 것도 너무나 당연했다.

===============================

술과 담배를 하지 않은지 2주가 지났다.

술을 마시지 않으니 사리판단을 하기가 쉬워졌다.
그리고 술마시는 행위 자체가 나를 행복하게 만들어주지 않는다는 것을 깨달았다.
술을 마시지 않으니 다른 사람의 이야기를 더 잘 들을 수 있게 되었다.

담배를 피지 않으니 머리와 가슴이 아프지 않다.
그리고 가끔씩은 담배를 피지 못해서 초조해지지만, 담배를 피지 못해서 나던 짜증은 없어졌다.
그리고 옷에서 담배 냄새가 없어졌다.

내 인생에서 술을 끊어 본 기간 중에 제일 긴 기간은 2년,
담배를 피지 않은 기간 중에 제일 긴 기간은 4년이다.

이번 금주, 금연 결심도 얼마나 갈지는 모르겠다.
그래도 최대한 길게 가져가 볼 생각이다.

===============================

학교일과 과제들을 어느 정도 일단락을 해 놓고 보니,
와이프와 상협이, 주윤이, 유주가 베트남에 놀라가는 날짜에 매우 근접해 있었다.

1월 2일부터 상훈이와 함께 제주도에 내려와 있다.
오랜만에 친구들과도 만나서 밥도 먹고,
낚시도 다니고 있다.

그저께 고등학교 반창회에서는 사이다 2리터, 물 1리터를 마시면서 술자리를 마쳤다.
중간에 갑자기 담배를 피고 싶은 생각이 들어서, 담배를 피러 나가는 친구들 사이에 껴서 담배 연기 냄새를 맡았다.
냄새 맡을 때는 솔직히 좀 좋기는 했지만,
술집으로 들어가면서 내 자신이 너무 구질구질해보였다.

오늘은 동현이와 낚시를 갔다.
동현이가 맥주 2캔을 까고 담배를 필 때,
솔직히 맥주 한모금은 마시고 싶었다.
꾸역꾸역 새우깡을 입 안으로 쑤셔넣으면서 참았다.

낚시를 마치고 횟집에서 소주 한병에 정신이 조금씩 조금씩 무너져 가는 동현이를 보면서 안타까운 마음도 들기는 했지만,
사이다 1리터와 물 1리터를 마시면서까지 술자리에 있어야 하나 하는 마음도 일었다.
그리고, 동현이가 취한 나머지 나에게 소주병을 기울일 때 너무나 자연스럽게 소주잔을 들어올리는 나를 보면서 습관 혹은 중독이 참 무서운 놈이라는 것을 다시 한번 느꼈다.

금연, 금주를 길게 실행하는게 쉽지는 않을 것 같다.
그래도 이번에는 길게 가 볼 생각이다.