1.4 C
New York
화요일, 12월 23, 2025

Buy now

[광고] 쿠팡 추천 링크

안녕하세요? 올해까지 삼성전자 25년 직장 생황릃 마치고 퇴직하려 합니다. 퇴직 후 아르바이트로 쿠팡 파트너스 활동을 하려고 합니다. 쿠팡 파트너스는 쿠팡 추천 링크를...

카누 캡슐 커피머신 솔직 리뷰: ‘네스프레소 호환’ 가성비 끝판왕 (ft. 쿠팡 최저가 할인)

'공유 커피' 카누가 만든 카누 캡슐 커피머신 : 캡슐 커피머신 바리스타 브리즈/어반! 네스프레소 오리지널 캡슐 호환으로 활용도는 높이고, 카누만의 황금 레시피로 커피 맛은 깊어졌습니다....
Home Blog Page 234

최신 Let’s Encrypt SSL 인증서 발급 방법 4가지 정리

여기에서는 우분투 20.04운영체제에서 웹서로로 NGINX를 사용 시 무료 SSL 인증서로 인기있는 Let’s Encrypt SSL 인증서 발급 방법 전반에 대해서 살펴보도록 하겠습니다.

이전에도 정리한 적이 있지만 시간이 흘러 발급 방법이 달라져 수정 정리할 필요가 생겼습니다.

Let’s Encrypt도 알고 보면 수많은 인증서 발급 기관,  CA(Certificate Authority) 업체 중이 하나입니다. 다만 SSL 인증서 가격이 비싸 보급이 느려지면서 인터넷 보안에 문제가 있다는 문제 의식하에 무료 보급을 통한 인터넷 보안을 강화하겠다는 비영리 단체라고 할 수 있습니다.

  1. 인증서 발급 기관, CA(Certificate Authority) 중 점유율이 가장 높은 곳은 IdenTrust로 2020년 12월 기준으로 42%가 넘습니다.(42.3%)
  2. IdenTrust 다음으로는 DigiCert Group(15.7%) > Sectigo(14.1%) > GoDaddy Group(5.4%) > GlobalSign(2.3%
  3. Let’s Encrypt 점유율은 생각보다 낮아서 0.1%에 불과
  4. 하지만 Let’s Encrypt 사용을 아래 그래프에서 보듯 매우 빠르게 증가
    (개인적인 생각으로는 무료이기 때문에 테스트로 중복 인증도 많다고 생각)
Let’s Encrypt SSL 인증서 사용 증가 추이, Graph by Let’s Encrypt
Let’s Encrypt SSL 인증서 사용 증가 추이, Graph by Let’s Encrypt

Let’s Encrypt SSL 인증서는 아래와 같은 장점들이 있어 사용이 확대되고 있습니다.

  1. 인증 절차가 단순(서버에서 필요한 프로그앰들이 설치되어 있다면) 단 한줄 명령어로 발급
  2. 발급 대기 시간 없이 바로 발급(이메일 입력 등을 포함해 1분 이내)
  3. Nginx나 아파치와 같은 웹서버에 맞추어 자동 옵션 설정되도록 설치 가능
  4. 인증 유효기간은 90일이지만 인증을 자동화 가능
  5. 무엇보다도 무료

근래 새롭게 사이트를 구축하하면서 Let’s Encrypt SSL 인증서 발급 과정에서 기존에 알고 있던 방법들이 대부분 작용하지 않는 것을 확인했습니다. 그것은

  • Let’s Encrypt SSL 인증서에서 여러가지 보안 이슈들이 발견되면서 발급 방법에 대한 보완이 진행되었고,
  • 발급에 필요한 패키지들도 업그레이드 되었고,
  • 예전에 알려졌던 기능들 일부는 지원이 중단(예를들어 자동 갱신 기능으로 많이 사용했던 Cert-Auto기능 지원 중단 등)되기도 했으며
  • 운영체제 업그레이드, DB 업그레이드에 따른 문제 발생 등

위와 같은 요인들로 인해서 기존에 알고 있던 방법들이 이를 제대로 반영하지 못하는 것으로 보입니다.

이제 Let’s Encrypt SSL 인증서 발급 방법에 대해서 알아 보시죠.

인증서 설치를 위한 Certbot tool 설치

Let’s Encrypt SSL 인증서 발급은 Certbot을 이용합니다. Certbot은 우분투 20.04를 설치 후 letsencrypt을 설치했다면 그 안에 포함되어 있기 때문에 별도 Certbot을 설치할 필요가 없습니다.

sudo apt update
sudo apt-get install  letsencrypt -yCode language: PHP (php)

[참고] Nginx 또는 아파치용 인증서 프로그램 설치 이용

Let’s Encrypt SSL 인증서 발급은 매우 다양한 방법으로 이루어지는데요. 이 중에는 Nginx나 아파치와 같은 웨서버가 전적으로 인증서를 제어토록 하는 방법이 있습니다.

이 경우 인증서 관리는 웹서버가 세팅과 관리를 알아서 한다고 하는데요. 저는 몇번 테스트해보고 기존 방식을 사용하기로하고 사용을 그만 두었습니다.

이 방법을 사용하려면 웹서버에 맞는 Certbot을 추가 설치합니다.

우선 우분투에서 Nginf용 Certbot 설치는 아래 명령을 사용합니다. 여기서는 Nginx 웹서버용 파이썬3를 설치합니다.

sudo apt update 
sudo apt upgrade -y 
sudo apt install certbot python3-certbot-nginxCode language: PHP (php)

만약 Apache를 사용한다면 python3-certbot-nginx 명령은 아파치를 지원하도록 python3-certbot-apache 명령으로 대체되겠죠.

sudo apt install certbot python3-certbot-apacheCode language: PHP (php)

그리고 과거 자료들을 보면 python-certbot-nginx 명령을 사용하는데 파이썬3으로 업그레이드되면서 파이썬3를 사용하라는 권고를 받습니다.

Let’s Encrypt SSL 인증서 발급 방법 4가지

Let’s Encrypt SSL 인증서 발급 방법은 webroot와 Standalone, DNS의 3가지 방식이 있습니다. 인증서 발급은 사이트에서 인증기관인 Let’s Encrypt에 접속해 이 사이트의 유효성을 검증하는 과정을 거치며 이 과정을 아래 3가지 방법 중 하나를 선택해 진행할 수 있습니다.

  1. webroot : 사이트 디렉토리 내에 인증서 유효성을 확인할 수 있는 파일을 업로드하여 인증서를 발급하는 방법
    . 실제 작동하고 있는 웹서버의 특정 데렉토리의 특정 파일 쓰기 작업을 통해서 인증
    . 이 방식의 장점은 nginx를 중단시킬 필요가 없음.
    . 이 방법의 단점은 인증 명령에 하나의 도메인 인증서만 발급 가능
  2. 웹서버
    . Nginx나 아파치와 같은 웹서버에서 직접 SSL 인증을 실시하고 웹서버에 맞는 SSL세팅값을 부여
    . 발급이나 갱신을 위해 웹서버를 중단시킬 필요가 없음
    . 인증서 갱신 시 상황에 맞게 세팅을 자동으로 업데이트
    . 사용자가 세팅을 변경할 수 있지만 자동 업데이트 시 반영되지는 않음
  3. Standalone : 사이트 작동을 멈추고 이 사이트의 네크워킹을 이용해 사이트 유효성을 확인해 Let’s Encrypt SSL 인증서를 발급하는 방식
    . 80포트로 가상 staandalone 웹서버를 띄워 인증서를 발급
    . 이 방식은 동시에 여러 도메인을 발급 받을 수 있음
    . 그렇지만 인증서 발급 전에 Nginx를 중단하고 발급 완료 후 다시 Nginx를 시작해야 함
  4. DNS : 도메인을 쿼리해 확인되는 TXT 레코드로 사이트 유효성을 확인하는 방법
    . 와일드 카드 방식으로 인증서를 발급 가능
    . 이 방법은 당연하게도 서버 관리자가 도메인 DNS를 관리/수정할 수 있어야 하며
    . 인증서 갱신 시마다 DNS에서 TXT값을 변경해야 하므로
    외부에서 TXT 레코드를 입력할 수 있도록 DNS가 API를 제공하는 경우만 갱신 과정을 자동으로 처리(클라우두플레어 API가 대표적인 사례)

1. webroot으로 SSL 인증서 발급

이 방법에 대해서는 Let’s Encrypt 설치 및 SSL 인증서 발급, NGINX 설정 방법nginx 서버에 HTTPS사용을 위한 SSL 인증서 발급받기 (Let’s Encrypt)등을 참조했습니다.

솔직히 이 방법은 번거롭기도하고 나중에 설명하겠지만 한계도 있는 방법입니다. 한번 설치해 운영하다가 한 서버에서 여러 도메인을 운영하는 것이 쉽지 않고, 이 방식으로 인증 시 일부 회사 방화벽에서 거부당하는 사례를 발견해서 사용 중단했습니다.

well-known이 있는 곳을 지정

위에서 설명한 것처럼 이 방법은 사이트 디렉토리 내에 인증서 유효성을 확인할 수 있는 파일을 업로드하여 인증서를 발급하는 방법으로 서버 내에 .well-known이 있는 곳을 지정해 줍니다.

이는 엄청 번거롭지만 1) 특정 폴더를 만들고 2) 이 특정 폴더에서 letsencrypt.conf 파일을 만들고 3) 이를 Nginx 설정 파일에서 이 파일을 읽어오도록 합니다.

먼저 특정 폴더를 만들고 mkdir -p 명령 옵션을 사용해 존재하지 않는 폴더를 만들어 줍니다.

mkdir -p /var/www/letsencrypt/.well-known/acme-challengeCode language: PHP (php)

다음으로는 webroot 경로를 알려주는 letsencrypt.conf 파일을 만듭니다. 이 파일 위치는 일반적으로 /etc/nginx/snippets/에 만드네요. 뭐 nano 편집기를 이용해서 아래와 같이 새로 만들 파일을 엽니다.

nano /etc/nginx/snippets/letsencrypt.conf Code language: PHP (php)

이 파일에 아래와 같은 내용을 추가합니다.

location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
root /var/www/letsencrypt;
}Code language: PHP (php)

다음으로는 Nginx 설정 파일 중 server 영역에서 아래 파일을 참조하도록 합니다.

include /etc/nginx/snippets/letsencrypt.conf;Code language: PHP (php)

이렇게 설정이 끝나면 Nginx를 다시 시작해 주어야겠죠.

sudo service nginx restartCode language: PHP (php)

예를 들면 아래와 같습니다.

server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;
    server_name happist.com www.happist.com;

    include /etc/nginx/ssl/letsencrypt.conf;

    location / {
        return 301 https://www.happist.com$request_uri;
        expires epoch;
        # return 301 아래에 expires epoch; 을 붙여주는 것은 301 리다이렉트가 캐싱되지 않도록 하기 위함
    }

}Code language: PHP (php)

SSL 인증서 발급

SSH command line에서 아래 명령을 입력합니다.

certbot certonly --webroot --webroot-path=/var/www/letsencrypt  -d 사이트명.com -d www.사이트명.com  Code language: PHP (php)

여기서 webroot-path는 사이트 루트를 말하는 것이 아니라 .well-known 폴더가 있는 곳을 말합니다.

2. 웹서버를 통한 Let’s Encrypt SSL 인증서 발급

앞에서 설명했듯이 SSL인증서를 일반적인 방식으로 발급할 수도 있도 Apache나 Nginx와 같은 웹서버 옵션을 이용해서 Let’s Encrypt SSL 인증서 발급받을 수도 있습니다.

웹서버를 통한 SSL 인증서 발급 방법의 좋은 점은 standalone 방식과 비슷한 방식이면서도 다르게 발급 받을 시 사이트 서비스를 중단하지 않아도 된다는 점이고, 웹서버가 알아서 적절한 SSL 옵션을 제안해 적용해 준다는 점입니다.

이 과정을 다시 자세하게 설명하면

Certot 설치

서버에서 SSL 인증서를 설치할 웹서버용 인증서 설치 툴인 Certbot을 설치합니다. 위에서 설명했듯이 nginx 웹서버용입니다. Certbot은 파이썬 2.7 또는 3.6버젼 이상을 지원한다고 하네요.

sudo apt install certbot python3-certbot-nginxCode language: PHP (php)

아파치라면 아래 명령어를 사용합니다.

sudo apt install certbot python3-certbot-apacheCode language: PHP (php)

Nginx 설정 확인

Nginx 설정에서 도메인이 제대로 설정되어 있는지 확인합니다. 다른 방식은 nginx 설정에서 도메인에 적용되어 있는지가 중요하지 않지만 웹서버를 이용하는 SSL 인증 방식 선택 시 Nginx 설정에서 도메일이 제대로 설정되어 있어야 합니다.

Nginx 설정 파일은 웹서버 설치 방식에 따라 달라지지만 Nginx 기본 설치 방식으로는 설치 시 /etc/nginx/conf.d/에 있고, 우분투에서 권장하는 방식으로 설치 시 /etc/nginx/sites-available/ 디렉토리에 있습니다.

저는 우분투 20.04를 사용하지만 Nginx 기본 설치 방식으로 설치해 /etc/nginx/conf.d/ 디렉토리 아래에 happist.com.conf라는 파일을 만들어 설정 내용을 넣엇습니다.

nano /etc/nginx/conf.d/happist.com.confCode language: PHP (php)

여기에서 다음과 같은 server_name이 등록되어 있는지만 확인하면 됩니다.

server_name example.com www.example.com;Code language: PHP (php)

도메인 등록이 되어 있는지 확인이 되었으면 편집기를 닫습니다. 없다면 도메인을 등록 , 저장 후 편집기를 빠져 나옵니다.

본격적으로 SSL 인증을 시작하기 전에 nginx가 제대로 작동하는지 확인합니다. 우선 테스트해 봅니다.

sudo nginx -tCode language: PHP (php)

아무 문제가 없다고 나오면 nginx를 다시 가동시킵니다.

sudo systemctl reload nginxCode language: PHP (php)

방화벽에서 HTTPS를 허용

아마 기본적으로 설정되어 있기는 하겠지만 80포트와 443포트를 허용해 주고 있는지 확인합니다.

우분투 20.04라면 기본 방화벽으로 ufw를 사용하고 있겠죠. 여기에서라면 ‘Nginx Full’ 옵션을 사용합니다.

sudo ufw allow ssh
sudo ufw allow 'Nginx Full'Code language: PHP (php)

그냥 iptables를 사용한다면 다음 명령으로 80포트와 443포트를 사용 가능하게 만들 수 있습니다.

sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPTCode language: PHP (php)

SSL 인증서 발급

이제 본격적으로 SSL 인증서를 발급해 보시죠. Nginx 웹서버의 경우 아래 명령어를 사용합니다.

sudo certbot --nginx -d 사이트명.com -d www.사이트명.com  Code language: PHP (php)

만약 아파치라면 다음과 같은 명령을 사용합니다.

sudo certbot --apache d 사이트명.com -d www.사이트명.com  Code language: PHP (php)

그러면 /etc/etsencrypt 폴더에 자동으로 SSL 적용 옵션을 제안해 줍니다. 사용자는 이 옵션을 그대로 사용할 수도 있고, 독자적인 옵션을 적용할 수도 있습니다.

그러나 별도 옵션을 적용하면 nginx가 제안하는 사항들이 제대로 업데이트가 안되기 때문에 매번 수작업으로 업데이트를 해주어야 합니다.

독자적인 옵션을 사용하지 않고 그냥 웹서버가 제안하는 옵션 그대로 사용한다면 나쁘지 않다는 생각입니다.

자동 갱신

자동 갱신은 크론에서 다음 명령어를 적용해 가능토록 만들 수 있습니다.

sudo certbot renew --dry-runCode language: PHP (php)

3. standalone 옵션 적용 SSL 인증서 발급

여기 소개하는 standalone 옵션은 사이트 서비스를 중단하고 사이트의 네트워킹을 이용해 인증서버와 접속하는 방식을 사용합니다. 처음에 가장 많이 소개된 방식이기도 합니다.

이러한 방식은 단점이면서도 장점을 가지는데요. 단점은 이 인증을 진행하는 동안 사이트 서비스를 중단해야 한다는 점이구요. 장점은 간편하고 빠르고 더우기 안정성도 높습니다.

사내 방화벽을 매우 까다롭게 관리하는 국내 일부 회사 중에서 SSL 인증 방식에 따라 접속을 허용하는 않는 경우도 있는데요. 우리나라에서 가장 큰 회사 중의 하나도 이 standalone 방식만 제대로 통과되는 것으로 확인하기도 했습니다.(2020년 5월 기준)

이런 저런 이유로 웹서버를 중단시키고 발급받는 불편함은 있지만 상대적으로 안정적인 방식이라고 생각합니다.

아래와 같은 명령어를 사용합니다. 혼란을 피하기 위해 처음부터 다시 설명해 봅니다.

우선 SSL 인증을 위한 Certbot tool을 설치합니다. 이전 단계에서 설치 했다면 Pass

sudo apt update
sudo apt-get install  letsencrypt -yCode language: PHP (php)

다음으로는 웹서버를 중단시킵니다. 아무 디렉토리에서나 가능한 명령이지만 root로 이동해서 진행해 봅니다.

cd /root/
service nginx stopCode language: PHP (php)

이제 certbot 명령을 이용해 SSL 인증을 시작합니다. standalone 명령을 사용하고 도메인 이름만으로 인증이 진행되는 -d 옵션을 적용합니다.

certbot certonly --standalone -d 사이트명.com -d www.사이트명.comCode language: PHP (php)

인증이 완료되면 웹서버를 다시 가동시킵니다.

service nginx restartCode language: PHP (php)

여러개 도메인을 한번에 인증받기

이 standalone 옵션은 또한 한꺼번에 여러 개의 사이트를 인증 받을 수 있는데요. 아래와 같은 명령을 사용할 수 있습니다. 이는 연속해서 사이트명을 나열해주면 가능합니다.

예를들면 아래와 같이요.

service nginx stop
certbot certonly –standalone -d happist.com -d http://www.happist.com -d sample1.com -d http://www.sample1.com -d sample2.kr -d http://www.sample2.kr -d sample3.co -d http://www.sample3.co -d sample4.net -d http://www.sample4.net
service nginx restart
Code language: PHP (php)

단 이렇게 여러개 사이트를 인증 받을 시 인증서 존재 위치가 맨앞 사이트명으로 통일되게 됩니다. 나중에 사이트를 없앨 때 난감할 수도 있습니다.

즉 위의 경우 맨 앞에 happist.com 이름을 딴 폴더가 만들어지고 이 폴더 아래에 4개의 .pem 파일이 만들어지고, 이 파일들이 5개 사이트에 대한 인증이 구성됩니다.

그럴 경우 나중에 어느 한 사이트를 없애는 경우 – 사이트가 커져서 그 사이트는 다른 서버에서 운영을 한다던지, 아예 사이트를 폐쇄해 버리든지 – 하는 경우 관리가 불편해 질 수 있습니다.

따라서 조금 귀찮드라로도 사이트 하나 하나 명령어를 따로 입력하는 것이 관리엔 더 좋습니다. 아래처럼

certbot certonly --standalone -d happist.com -d www.happist.com

certbot certonly --standalone -d sample1.com -d www.sample1.com

certbot certonly --standalone -d sample2.kr -d www.sample2.kr

certbot certonly --standalone -d sample3.co -d www.sample3.co

certbot certonly --standalone -d sample4.net -d www.sample4.netCode language: PHP (php)

이렇게 각각 명령을 사용해 인증하면 사이트마다 폴더가 생겨서 관리가 좀금 더 쉽워집니다. 아래처럼 각 사이트별 폴더가 형성됩니다. 그 폴더 아래에 그 사이트에 해당하는 각종 .pem 파일이 만들어지기 때문에요.

  • /etc/letsencrypt/live/happist.com
  • /etc/letsencrypt/live/sample1.com
  • /etc/letsencrypt/live/sample2.kr
  • /etc/letsencrypt/live/sample3.co
  • /etc/letsencrypt/live/sample4.net

4. DNS 이용해 발급 받기

도메인이 연결된 DNS의 TXT레코드를 이용해 인증받는 방식으로 많은 장점을 가진 방법이지만 갱신 시 마다 DNS 정보 중 TXT 레코드를 새로 생성해야 하므로 이를 지원하는 DNS API가 없는 경우 자동 갱신이 어렵다는 단점이 있습니다.

  • 와일드 카드 방식으로 인증서를 발급 가능
  • 당연하게도 서버 관리자가 도메인 DNS를 관리/수정할 수 있어야 하며
  • 인증서 갱신 시마다 DNS에서 TXT값을 변경해야 하므로
    외부에서 TXT 레코드를 입력할 수 있도록 DNS가 API를 제공하는 경우만 갱신 과정을 자동으로 처리

이 방법은 위에서 소개한 방법 중에서 가장 까다로운 방법으로 에러 가능성이 높아 여러번 시도하다보면 최대 허용 시도를 초과해 당분간(1주일 정도) 인증이 불가능해지는 불쌍사가 종종 발생하더군요.

그래서 저는 편리함에도 불구하고 사용하지 못하고 있습니다.

클라우드플레어(CloudFlare)의 경우

DNS를 클라우드플레어(CloudFlare)에 도메인 네임서버로 등록해 사용하는 경우 클라우드플레어(CloudFlare)가 제공하는 DNS API를 이용해서 와일드 카드 인증서 등록 및 갱신이 가능합니다.

클라우드플레어(CloudFlare) API 관리 폴더와 파일 생성

클라우드플레어(CloudFlare) API를 관리할 폴더와 파일을 생성합니다.

cd /root
mkdir .secret
nano /root/.secret/cloudflare_api.iniCode language: PHP (php)

cloudflare_api.ini 파일에는 아래 내용을 추가합니다.

여기서 이메일 주소는 클라우드플레어(CloudFlare) 계정에 등록된 이메일이고, Global API Key는 CloudFlare의 계정 관리에서 발급 받을 수 있습니다.

dns_cloudflare_email = "이메일 주소 입력"
dns_cloudflare_api_key = "Global API Key 입력"Code language: PHP (php)

생성한 폴더와 파일에 대한 권한을 변경합니다.

chmod 700 /root/.secret
chmod 400 /root/.secret/cloudflare_api.iniCode language: PHP (php)

Certbot tool과 클라우드플레어 DNS 인증 플러그인 설치

여기에서는 SSL 인증 진행에 필요한 Certbot tool인 letsencrypt과 클아우드플레어 인증 플러그인을 설치합니다.

먼저 인증 플러그인 설치를 위한 파이선 PIP를 설치합니다.

<em>apt install python-pip</em>Code language: PHP (php)
<em>pip install certbot-dns-cloudflare</em>Code language: PHP (php)

혹시SSL 인증을 위한 Certbot tool가 설치되지 않았다면 설치합니다. 이전 단계에서 설치 했다면 Pass

sudo apt update
sudo apt-get install  letsencrypt -yCode language: PHP (php)

SSL 인증서 발급

SSL 인증서 발급 명령어입니다. example.com을 예를 든 것이고 자신의 도메일을 대체하면 됩니다.

/usr/local/bin/certbot certonly --dns-cloudflare --dns-cloudflare-credentials /root/.secret/cloudflare_api.ini -d example.com,*.example.com --preferred-challenges dns-01Code language: PHP (php)

이후 nginx라면 dhparam을 생성해 줍니다.

mkdir /etc/nginx/ssl  
cd /etc/nginx/ssl
openssl dhparam -out dhparams.pem 4096Code language: PHP (php)

이후 아래 명령을 추가합니다.

openssl rand 48 > 
session_ticket.key Code language: PHP (php)

인증서 자동 갱신

이렇게 발행된 인증서를 자동으로 갱신하기 위해서는 코론에 등록합니다.

crontab -eCode language: PHP (php)

Nginx라면 아래와 같은 내용을 추가합니다.

30 4 * * 0 /usr/local/bin/certbot renew --quiet --post-hook "/usr/sbin/service nginx reload" > /dev/null 2>&1Code language: PHP (php)

아파치라면 아래 명령을 사용합니다.

30 4 * * 0 /usr/local/bin/certbot renew --quiet --post-hook "/usr/sbin/service apache2 restart" > /dev/null 2>&1Code language: PHP (php)

Vultr에서 DNS를 이용한 와일드카드 인증 방법

가상서버 호스팅인 Vultr를 이용하는 경우에도 DNS를 이용해 와일드카드 인증이 가능하다고 합니다.

이는 Install Wildcard Certificate from Let’s Encrypt (Ubuntu 20.04 + Nginx + Vultr)를 참조해 간단히 정리했습니다.

필요 사항

  • 우분투 20.04 설치된 서버
  • Vultr DNS에 도메인 네임 등록, 예를들어 example.com
  • A/AAAA 레코드 및 CNAME DNS 레코드 등록
  • Vultr API 사용 가능 상태로 변경
    . 이는 Account – API에서 Enanble API를 눌러서 활성화 함
    . 그러면 Personal Access Token 번호가 나오는데 이를 기록해 놓음
Vultr 가상 서버 API

필요 패키지 설치

이 작업에 필요한 필요 패키지를 설치합니다. 우선 파이썬이 없으면 파이선3를 설치합니다. 그렇지만 우분투 20.04를 설치하면 파이썬 3가 설치되어 있습니다.

<code>sudo apt install -y python3</code>Code language: PHP (php)

다음으로는 Lexicon tool을 설치하는데요. 이는 다양한 DNS 프로바이더로부터 DNS 기록을 관리할 수 있는 파이썬 도구라고 합니다.

<code>sudo apt install -y lexicon</code>Code language: PHP (php)

acme.sh 클라이언트 설치

이 클라이언트는 root 사용자만 설치 가능하므로 root 사용자로 전환합니다.

<code>sudo su - root</code>Code language: PHP (php)

scme.sh를 다운받아 설치합니다. 아래 your_email@example.com는 Vultr 계정에서 사용하는 이메일 주소입니다.

<code>git clone https://github.com/Neilpang/acme.sh.git </code>
<code>cd acme.sh </code>
<code>./acme.sh --install --accountemail "your_email@example.com" </code>
<code>source ~/.bashrc </code>
<code>cd</code>Code language: PHP (php)

와일드카드 SSL 인증

도메인에 대한 RSA와 ECC와일드카드 인증을 받습니다. 아래와 같은 명령을 사용합니다.

  • 아래 your_email@example.com는 Vultr 계정에서 사용하는 이메일 주소
  • XXXXXXXXXXXXXXX은 Personal Access Token 번호
Configure your API key and username
 export PROVIDER=vultr
 export LEXICON_VULTR_USERNAME="your_vultr_email@example.com"
 export LEXICON_VULTR_TOKEN="XXXXXXXXXXXXXXX"
 RSA 2048
 acme.sh --issue --dns dns_lexicon -d example.com -d '*.example.com' --keylength 2048
 ECC 256
 acme.sh --issue --dns dns_lexicon -d example.com -d '*.example.com' --keylength ec-256Code language: PHP (php)

이러한 작업 결과 RSA 및 ECC/ECDSA인증 및 키는 아래 폴더에 위치하게 됩니다.

RSA: <code>~/.acme.sh/example.com</code> directory.
ECC/ECDSA: <code>~/.acme.sh/example.com_ecc</code> directory.Code language: PHP (php)

이들 폴더를 이용할 수 없기 대문에 이들을 /etc/letsencrypt 폴더로 옮김니다. 먼더 폴더를 만들고..

<code>sudo mkdir -p /etc/letsencrypt/example.com </code>
<code>sudo mkdir -p /etc/letsencrypt/example.com_ecc</code>Code language: PHP (php)

아래 명령으로 인증 및 복사합니다.

RSA
 acme.sh --install-cert -d example.com \
         --cert-file /etc/letsencrypt/example.com/cert.pem \
         --key-file /etc/letsencrypt/example.com/private.key \
         --fullchain-file /etc/letsencrypt/example.com/fullchain.pem \
         --reloadcmd "sudo systemctl reload nginx.service"
 ECC/ECDSA
 acme.sh --install-cert -d example.com --ecc \
         --cert-file /etc/letsencrypt/example.com_ecc/cert.pem \
         --key-file /etc/letsencrypt/example.com_ecc/private.key \
         --fullchain-file /etc/letsencrypt/example.com_ecc/fullchain.pem \
         --reloadcmd "sudo systemctl reload nginx.service"Code language: PHP (php)

SSL 인증서 관련 참고

최신 Let’s Encrypt SSL 인증서 발급 방법 4가지 정리

Let’s Encrypt SSL 인증서 발급 및 자동 갱신 방법(업데이트)

최신 보안 트렌드를 반영한 Let’s Encrypt 인증서 세팅 방법

웹, 브라우저, 서버에서 SSL 인증서 정보 확인 방법, SSL 인증서 만료일 확인 등

서버 보안 관련

랜섬웨어 대응, 서버 및 워드프레스 필수 보안 설정 15가지

워드프레스 보안 강화 NGINX 설정 방법 8가지

리눅스 서버 보안을 위한 포트 사용 최적화

리눅스 서버 root 사용 중지로 리눅스 서버 보안 강화하기

우분투 서버 보안 자동 업데이트 및 업데이트 메일 통보 방법

워드프레스 보안 진단 WPScan 사용법 및 이메일로 결과 받아보기

DDoS 취약 기능 XMLRPC 사용 중지로 워드프레스 보안 강화하기

워드프레스 보안 강화를 위한 사용자명 변경 방법

워드프레스 멀웨어 경험에서 배운 워드프레스 보안 가이드

가상서버호스팅 서버 보안 설정 방법 – Nginx +Ubuntu의 경우

리눅스 서버 보안을 위한 포트 사용 최적화

0

사이트 보안을 강화는 방법으로 불필요하게 포트를 열어 놓았는지 확인해 반드시 필요한 포트만 여는 포트 사용 최적화 방법에 대해서 살펴보도록 하죠.

서버에서 사용하는 포트는 아래와 같이 세가지 주요 그룹으로 나눌 수 있습니다.

  1. 시스템 포트(System ports), 0-1023 – 핵심 서비스와 관련된 포트로 운영 체제에 필수적인 포트
  2. 사용자 포트(User ports), 1024-49151 – IANA가 ‘IETF Review’, ‘IESG Approval’, ‘Expert Review’ 프로세스를 위해 할당한 포트
  3. 동적 포트(Dynamic ports), 49152-65535 – 개인적이 용도로 사용하는 프라이빗 포트

어떤 포트를 사용하고 있는지 확인

현재 사이트에서 어떤 포트를 열어놓고 있는지 확인하기 위해서 아래와 같이 netstat -ano 명령을 사용해 봤습니다.

이 명령을 사용하면 아래와 같이 현재 열린 포트 및 대기하고 있는 포트들을 전부 다 보여줍니다. 또한 이 내용외에 다양한 내용을 출력해 줍니다. 너무 많아 기가 질릴 정도..

# netstat -ano
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       Timer
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 0.0.0.0:25              0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 127.0.0.1:6010          0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 0.0.0.0:*****           0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      0 141.164.48.62:443       189.40.73.149:12786     ESTABLISHED off (0.00/0/0)
tcp        0      0 141.164.48.62:443       180.65.25.237:45753     ESTABLISHED off (0.00/0/0)
tcp        0      0 141.164.48.62:443       203.175.39.84:49433     ESTABLISHED off (0.00/0/0)
tcp        0      0 141.164.48.62:443       72.14.199.27:49062      ESTABLISHED off (0.00/0/0)
tcp        0      0 141.164.48.62:443       222.234.131.7:7507      ESTABLISHED off (0.00/0/0)
tcp        0      0 141.164.48.62:443       66.249.79.158:42357     ESTABLISHED off (0.00/0/0)
tcp        0      0 141.164.48.62:443       189.40.73.149:12792     ESTABLISHED off (0.00/0/0)
tcp        0      0 141.164.48.62:443       61.81.11.245:11848      TIME_WAIT   timewait (7.58/0/0)
tcp        0      0 141.164.48.62:443       189.40.73.149:12788     ESTABLISHED off (0.00/0/0)
tcp        0      0 141.164.48.62:443       118.45.130.180:38805    TIME_WAIT   timewait (57.05/0/0)
tcp        0      0 141.164.48.62:443       124.50.187.177:57167    ESTABLISHED off (0.00/0/0)
tcp        0      0 141.164.48.62:443       66.249.79.129:56320     ESTABLISHED off (0.00/0/0)
tcp        0    180 141.164.48.62:*****     124.50.187.177:57295    ESTABLISHED on (0.22/0/0)
tcp        0      0 141.164.48.62:443       66.249.79.120:43419     ESTABLISHED off (0.00/0/0)
tcp        0      0 141.164.48.62:443       211.243.82.156:49304    ESTABLISHED off (0.00/0/0)
tcp        0      0 141.164.48.62:443       66.249.79.159:40840     TIME_WAIT   timewait (34.53/0/0)
tcp        0      0 141.164.48.62:443       211.178.105.144:56345   ESTABLISHED off (0.00/0/0)
tcp        0      0 141.164.48.62:443       66.249.79.118:54414     ESTABLISHED off (0.00/0/0)
tcp        0      0 141.164.48.62:443       66.249.79.158:62256     TIME_WAIT   timewait (2.30/0/0)
tcp        0      0 141.164.48.62:443       222.121.168.2:4079      ESTABLISHED off (0.00/0/0)
tcp        0      0 141.164.48.62:443       121.151.167.84:47722    ESTABLISHED off (0.00/0/0)
tcp6       0      0 :::25                   :::*                    LISTEN      off (0.00/0/0)
tcp6       0      0 ::1:6010                :::*                    LISTEN      off (0.00/0/0)
tcp6       0      0 :::*****                :::*                    LISTEN      off (0.00/0/0)
udp        0      0 127.0.0.53:53           0.0.0.0:*                           off (0.00/0/0)
udp        0      0 141.164.48.62:68        0.0.0.0:*                           off (0.00/0/0)Code language: PHP (php)

또는 netstat 명령대신 요즘 권장된다는 ss 명령을 사용해 봅니다. 조금 더 단순하게 보여줍니다. 간단한 대신 정보가 제한적이네요.

~#ss -ltp
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 4096 127.0.0.53%lo:domain 0.0.0.0:* users:((“systemd-resolve”,pid=556,fd
LISTEN 0 100 0.0.0.0:smtp 0.0.0.0:* users:((“master”,pid=1279035,fd=13))
LISTEN 0 128 127.0.0.1:6010 0.0.0.0:* users:((“sshd”,pid=3070675,fd=10))
LISTEN 0 511 0.0.0.0:https 0.0.0.0:* users:((“nginx”,pid=2951636,fd=7),(“
LISTEN 0 128 0.0.0.0:** 0.0.0.0:* users:((“sshd”,pid=2994821,fd=3)) LISTEN 0 70 127.0.0.1:mysql 0.0.0.0:* users:((“mysqld”,pid=2787110,fd=25)) LISTEN 0 511 0.0.0.0:http 0.0.0.0:* users:((“nginx”,pid=2951636,fd=6),(” LISTEN 0 100 [::]:smtp [::]:* users:((“master”,pid=1279035,fd=14)) LISTEN 0 128 [::1]:6010 [::]:* users:((“sshd”,pid=3070675,fd=9)) LISTEN 0 128 [::]:** [::]:* users:((“sshd”,pid=2994821,fd=4))

이러한 명령을 통해서 확인해보면 제가 열어 놓은 포트는 아래와 같습니다.

  • 도메인 네임 서버 TCP 53
  • 도메인 네임 서버 UDP 53
  • SSH (secure shell) 서버 TCP *(ipv4)
  • SSH (secure shell) 서버 TCP *(ipv6)
  • 웹서버 TCP 443
  • 웹서버 TCP 80
  • SMTP(mail sending) 서버 TCP 25(ipv4)
  • SMTP(mail sending) 서버 TCP 25(ipv6)
  • MySQL 서버 tcp 3306
  • X11 forwarding TCP 6010(ipv4)
  • X11 forwarding TCP 6010(ipv6)
  • BOOTP(부트스트랩 프로토콜) 클라이언트, DHCP로도 사용 UDP 68

이러한 포트중에서 눈에 띄는 것이 ipv4와 ipv6가 모두 사용되고 있다는 것이고, X11 forwarding을 위해 TCP 6010이 열고 있다는 점 정도네요. BOOTP(부트스트랩 프로토콜) 클라이언트는 사용하는지 모르겠어 우선은 그냥 두기로 했습니다.

즉 ipv4만 사용하고 ipv6는 사용 중지하며, X11 forwarding을 위해 TCP 6010도 사용하지 않기로 하죠.

ipv6 비활성화

우분투 서버에서 ipv6 비활성화 방법은 아래와 같이 세가지 방법이 있습니다.

sysctl.conf 설정 수정

먼저 /etc/sysctl.conf 설정을 수정하는 것입니다.

nano  /etc/sysctl.conf Code language: PHP (php)

이 파일 편집 화면에서 아래와 같은 명령을 추가합니다.

net.ipv6.conf.all.disable_ipv6=1
net.ipv6.conf.default.disable_ipv6=1Code language: PHP (php)

grub 설정 수정

위 방법을 사용해도 좋지만 아래에 설명하는 grub를 사용하는 방법이 더 낫다는 평가가 있습니다.

nano /etc/default/grubCode language: PHP (php)

grub 파일 편집 상태에서 아래와 같은 명령을 추가합니다.

GRUB_CMDLINE_LINUX_DEFAULT="ipv6.disable=1"
GRUB_CMDLINE_LINUX="ipv6.disable=1"Code language: PHP (php)

위와 같이 설정을 추가한 후 update-grub 명령을 실행한 후 서버를 부팅하면 적용이 됩니다. ipv6를 사용하지 않을려면 서버 부팅이 필요하군요.

update-grubCode language: PHP (php)

ufw 설정 수정

그런데 우분투에서 보통 그렇듯이 방화벽으로 ufw를 사용한다면 /etc/default/ufw 파일을 수정 설정하면 됩니다.

nano /etc/default/ufwCode language: PHP (php)

이 파일 편집 화면을 보면 IPV6=yes로 되어 있는데요. 이를 no로 변경하면 됩니다. 이 파일 편집 상태를 저장하면 바로 UFW(Uncomplicated Firewall)가 작동하면서부터 이러한 세팅은 적용이 됩니다.

6010 포트 비활성화

이번에는 ssh daemon의 X11 forwarding을 위해 TCP 6010 포트를 사용하지 않는 방법을 살펴보죠.

리눅스 운영체제에서 GUI 방식의 SSH 사용 시 사용한다고 하는데요. 주로 원격으로 떨어져 있는 서버에 접속해 GUI 기반 어플리케이션을 실행시 사용합니다.

우분투가 윈도우즈처럼 GUI 방식으로 발전하기 때문에 SSH 접속 시 이러한 GUI를 지원하기 위한 기능이라고 볼 수 있는데요. 이는 X윈도우 기반 기능이므로 서버와 클라이언트 모두 X윈도우즈 기반이러야 제대로 작동한다고 합니다.

그렇기때문에 웹서버에서는 사용할 일이 거의 없기 때문에 이를 시용할 필요가 없지 않을까요? 사용 포트에 대한 베스트 프랙티스들을 보니 6010 포트는 리스트에 없더군요.

X11 forwarding는 우분투 20.04에서 기본 yes로 설정되어 있기 때문에 /etc/ssh/sshd_config에서 설정을 no로 변경해야 합니다.

nano /etc/ssh/sshd_config Code language: PHP (php)

파일의 맨 아래쪽에 아래와 같은 내용을 볼 수 있는데요. 이중 X11Forwarding yes를 no로 변경하면 됩니다.

#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
X11Forwarding yes --> no로 변경
#X11DisplayOffset 10
#X11UseLocalhost yes
#PermitTTY yes
PrintMotd no
#PrintLastLog yes
#TCPKeepAlive yes
#PermitUserEnvironment no
#Compression delayedCode language: PHP (php)

마찬가지로 이 설정 변경 효과는 서버 재시작해야 작동하는 것 같네요.

설정이 제대로 작동하면 ssh 로그인 시 아래와 같은 경고 표시가 뜹니다.

WARNING! The remote SSH server rejected X11 forwarding request.
Welcome to Ubuntu 20.04 LTS (GNU/Linux 5.4.0-40-generic x86_64)Code language: PHP (php)

리눅스 서버 접속 IP 허용 & 사용자 접속 허용하기

0

오늘은 리눅스 서버 보안을 위해서 서버 접속 ip 허용 또는 특정 사용자 접속 허용하는 방법에 대해서 살펴봅니다. 서버 관리를 위해서 글로벌 각지에서 서버에 접속할 필요가 없다면 접속 ip 범위를 최소화하는 것이 필요합니다.

여러번 설명하지만 우분투를 비롯한 리눅스 서버 보안을 위해서 아래와 같은 사항들이 고려됩니다.

  1. ssh 접속 포트를 22번 포트가 아닌 다른 포트 사용
  2. ssh 접속 ip를 특정 ip대로 제한
    . 한국에서만 접속 가능토록 한국 ip로만 한정
    . 집과 이동중인 태블릿 접속 ip대로만 한정
  3. root 사용 중지 및 특정 사용자_ID만 사용
    보안을 위해 사용자_ID를 굉장히 길고 복잡하게 만들어 해커가 사용자_ID 파악을 어렵게 만듬
    그리고 root 사용 중지
  4. 사용자 비밀번호를 보안이 높도록 만들고, 가능하면 정기적 변경
  5. ssh key를 통한 접속으로 사용자_ID와 비밀번호를 통한 ssh 접속 방법이 한계 극복

어떤 ip를 접속 허용할까

서버 보안을 위해서 특정 ip를 허용한다면 어떤 ip를 허용해야할까요? 이를 확인하는 좋은 방법 중의 하나는 그동안 접속했던 ip를 확인해보는 것입니다.

그동안 접속했던 ip는 아래와 같은 명령어를 사용해 확인할 수 있습니다.

~# cat /var/log/auth* | grep Accepted | awk '{print $9"\t"$11"\t"$14}' | sort | uniqCode language: PHP (php)

저의 경우 지난 2개월동안 접속했던 ip를 확인해보니 아래처럼 5개가 확인됩니다.

root    124.50.187.***  ssh2
root    211.36.134.***  ssh2
root    211.36.135.***  ssh2
root    211.36.142.***  ssh2
root    211.36.151.***  ssh2
root    211.36.158.***  ssh2Code language: PHP (php)

이 ip들을 확인해보니 집과 태블릿에서 사용하던 ip들입니다. 맨 위 ip는 집에서 사용하는 공인 ip이고, 나머지 4개는 태블릿에서 사용하는 유동ip로 보입니다.

그래서 집의 공인 ip와 태블릿의 유동 ip대인 211.36.대를 적용하기로 했습니다.

ip 허용 및 금지 설정

ip 허용 및 금지하는 방법을 살펴보도록 하죠. ip를 허용하는 방법은 /etc/hosts.allow 파일을 수정합니다.

nano /etc/hosts.allowCode language: PHP (php)

위에서 설명한대로 집의 공인 ip와 태블릿의 유통 ip 대역대를 적용하도록 하겠습니다.

ip 대역대 표시는 ip 4 자리 중 해당 부분만 표시할 수 있습니다. 우리가 흔히 아는 것처럼 *같은 것은 사용하지는 못합니다.

  • ip 세자리대까지 표현한다면 ‘124.50.187.’ 로 표시
  • ip 두자리대까지 표시한다면 ‘124.50.’로 표시
  • ip 한자리대까지 표시한다면 ‘124.’으로 표시

특정 ip만 적용하기 윌한 /etc/hosts.allow 파일은 아래와 같이 변경되었습니다.

# /etc/hosts.allow: list of hosts that are allowed to access the system.
#                   See the manual pages hosts_access(5) and hosts_options(5).
#
# Example:    ALL: LOCAL @some_netgroup
#             ALL: .foobar.edu EXCEPT terminalserver.foobar.edu
#
# If you're going to protect the portmapper use the name "rpcbind" for the
# daemon name. See rpcbind(8) and rpc.mountd(8) for further information.
#
sshd: 124.50.187.177
sshd: 211.36.Code language: PHP (php)

그리고 나머지 ip는 모두 사용 중지시킵니다. 이는 /etc/hosts.deny 파일을 수정합니다.

nano /etc/hosts.denyCode language: PHP (php)

아래 내용으로 변경합니다.

# /etc/hosts.deny: list of hosts that are _not_ allowed to access the system.
#                  See the manual pages hosts_access(5) and hosts_options(5).
#
# Example:    ALL: some.host.name, .some.domain
#             ALL EXCEPT in.fingerd: other.host.name, .other.domain
#
# If you're going to protect the portmapper use the name "rpcbind" for the
# daemon name. See rpcbind(8) and rpc.mountd(8) for further information.
#
# The PARANOID wildcard matches any host whose name does not match its
# address.
#
# You may wish to enable this to ensure any programs that don't
# validate looked up hostnames still leave understandable logs. In past
# versions of Debian this has been the default.
# ALL: PARANOID
sshd: ALLCode language: PHP (php)

특정 사용자만 허용하는 방법

특정 사용만 ssh 접속을 허용하는 방법입니다. 이는 sshd_config 파일에서 특정 사용자를 허용하든지 금지시킬 수 있습니다.

nano /etc/ssh/sshd_configCode language: PHP (php)

이 파일에서 아래처럼 AllowUsers 다음에 허용할 사용자를 추가합니다. 예를들면 daisy 사용자만 추가한다면 다음과 같은 명령을 사용합니다.

AllowUsers daisyCode language: PHP (php)

이 파일에는 PermitRootLogin 명령어는 root 사용자 로그인을 허용할지 설정하는 명령인데요. 일부 글들을 보면 root 사용을 중지할 때 no 옵션을 준다고 설명하고 있는데요.

우분투에서 root 사용을 중지시킬 때 아래처럼 이를 no 옵션을 사용한다고 설명하는데 우분투 20.04에서는 작동하지 않더군요.

PermitRootLogin noCode language: PHP (php)

우분투에서 root 사용 중지는 아래 글을 참고하시면 좋을 것 같습니다.

리눅스 서버 root 사용 중지로 리눅스 서버 보안 강화하기

0

강력한 리눅스 서버 보안 방법 중의 하나인 리눅스 서버 root 사용 중지로 서버 root 로그인 시도를 원천적으로 막음으로서 서버 보안 강화 및 서버 최적화 방법에 대해서 살펴보겠습니다.

대부분 서버의 가장 강력한 권한을 갖는 사용자는 Super User라고 할 수 있는 root 입니다. root만 장악하면 서버 전반을 좌지우지할 수 있기 때문에 해커의 중요한 타겟이 됩니다.

여기에 이 Super user 사용자 이름은 root로 만천하에 알려져 있기 때문에 강력한 컴퓨팅에 의한 스크립트 실행으로 다양한 비밀번호를 대입해 보면서 강제적인 roor 로그인을 시도할 수 있습니다.

그렇기 때문에 여기서는 우분투를 비롯한 리눅스 서버에서 roor를 사용하지 않고 서버를 운영하는 방법에 대해서 살펴보도록 하겠습니다. 아래 내용들은 우분투 20.04를 기준으로 설명합니다.

우분투를 비롯한 리눅스 서버 보안을 위해서 아래와 같은 사항들이 고려됩니다.

  1. ssh 접속 포트를 22번 포트가 아닌 다른 포트 사용
  2. ssh 접속 ip를 특정 ip대로 제한
    예를들어 한국에서만 접속 가능토록 한국 ip로만 한정하든지 또는 집과 태블릿 접속 ip대로만 한정
  3. root 사용 중지 및 특정 사용자_ID만 사용
    보안을 위해 사용자_ID를 굉장히 길고 복잡하게 만들어 해커가 사용자_ID 파악을 어렵게 만듬
    그리고 root 사용 중지
  4. 사용자 비밀번호를 보안이 높도록 만들고, 가능하면 정기적 변경
  5. ssh key를 통한 접속으로 사용자_ID와 비밀번호를 통한 ssh 접속 방법이 한계 극복

우분투 서버 설치 시 기본 설정은 root 미사용

기본적으로 우분투를 설치하면 root를 사용할 수 없도록 되어 있습니다. 왜냐하면 root의 비밀번호가 설정되지 않았기 때문이죠.

그래서 root를 사용하려면 root 비밀번호를 설정한 후 사용할 수 있습니다.

그러나 Vultr와 같은 가상 서버 호스팅에서 우분투 서버를 설치하면 ip 주소가 정해지고, 기본 사용자로 root로 설정되고, root의 비밀번호도 정해집니다.

그래서 ssh 이용 시 주어진 ip주소와 root 사용자 그리고 주어진 root 비밀번호를 사용하게 됩니다.

서버 보안에서 강력히 권고하는 한가지 사항은 root를 사용하지말고 별도 사용자를 등록하고 별도 사용자에게 일부 root 권한을 행사하도록 하는 것입니다.

제가 Vultr에 root 사용자를 사용하지 않기위해 없애는 것이 가능한지 질문을 했는데요. Vultr에서는 불가능하다고 답변이 왔습니다.

그런데 구글링을 해보면 우분투에서 root를 사용하지 않을 수 있고, 오히려 root를 사용하지 말라고 권고가 많습니다. 그리고 위해서 한번 설명했지만 우분투는 기본적으로 root를 비활성한 채 설치된다고 합니다.

그래서 조금 더 고민해보고 구글링에 구글링을 거듭하다가 내린 결론은 제 질문이 잘못되었다는 것을 알 수 있었습니다.

  • root 계정 자체를 없애는 것은 불가능
  • 대신 root 비밀번호를 없애서 root가 없는 것처럼 우분투 서버 운영 가능
    root 비밀번호 설정을 없애는 것은 root로 로그인 상태에서 passwd -dl root 명령으로 가능
  • 따라서 root 비밀번호를 없애고, 특정 사용자를 root 수준의 권한을 준다면(sudo) root없이도 모든 작업이 가능

새로운 사용자 등록 및 sudo 권한 등록

사용자 등록 후 이 사용자에게 sudo 권한을 부여하는 방법은 아래와 같습니다.

위에서도 간단히 설명했지만 가능하는 한 사용자_ID를 복잡하고 유추하기 어렵게 만들어 외부 해커가 사용자_ID 파악을 어렵게 만들고, 더 나아가 비밀번호를 강화해 해킹 가능성을 낮추는 것이 목표입니다.

사용자 등록 및 sudo 그룹 등록

먼저 사용자 등록을 합니다.사용자는 가능하면 어렵고 쉽게 유추할 수 없는 이름을 사용합니다.

adduser 신규_사용자_IDCode language: PHP (php)

이 신규_사용자_ID에 sudo 권한 부여를 위해서는 아래와 같이 sudo 그룹에 이 사용자_ID를 추가해 줍니다.

usermod -aG sudo 신규_사용자_IDCode language: PHP (php)

이 명령은 root로 로그인 했을 때나 신규_사용자_ID로 로그인때나 사용 가능했습니다.

여기까지 진행되었다면 신규_사용자_ID로 sudo를 사용할 수 있습니다.

참고로 일부에서는 사용자 추가 시 동시에 sudo 기능을 추가할 수 있도록 아래와 같이 사용자 추가 시 sudo를 추가해주는 방법을 소개하는데요.

이 방법(아래 명령어)은 우분투 20.04에서는 작동하지 않았습니다.

sudo adduser 신규_사용자_ID sudoCode language: PHP (php)

우분투 서버 root 사용 중지하기

이번에는 우분투 서버에서 root 사용 중지하는 방법에 대해서 알아봅니다.

앞서 설명한대로 root 사용자를 아예 없애는 것은 불가능합니다. 다만 root 비밀번호를 없애서 root를 사용하지 않토록 하는 방법이 있죠.

이는 root로 로그인 상태에서 아래와 같은 명령을 사용합니다. 아니면 특정 사용자로 로그인 상태라면 root 권한(sudo -i 옵션을 사용)을 획득한 상태에서 사용할 수 있겠죠.

불필요한 혼란을 방지하기 위해서 root 로그인 상태에서 아래 명령어를 사용합니다.

sudo passwd -dl rootCode language: PHP (php)

여기서 -l은 root 비밀번호를 lock한다는 의미에서 사용하는 옵션으로 보입니다. 이러면 이후부터는 root로 ssh 로그인이 안되고 root 사용이 안됩니다.

그러면 root를 다시 살리려면 어떻게할까요?

이미 root를 사용할 수 없도록 만들었기 때문 root를 사용하려면 아래 명령어를 사용합니다. 그리고 새로운 root 비밀번호를 설정할 수 있습니다.

sudo -i passwd rootCode language: PHP (php)

결국 sudo 권한을 획득한다는 것은 조금 불편하지만 언제든지 root 권한을 획득 할 수 있다는 것을 의미합니다.

그렇게 때문에 개인 사용자나 작은 스타트업에서는 sudo 권한을 가진 사용자를 만든다면 굳이 root 사용자가 필요없다는 결론에 이르고 이것이 더 보안에 유리한 것이 아닐까 싶습니다.

특정 사용자를 root처럼 사용하기

기업의 IT팀이 아니라면 root를 두고 여러 사용자를 등록시켜 일정 권한을 주는 방식이 바람직하기 때문에 root도 필요하고 각기 다른 낮은 사용 권한을 가진 사용자들도 필요합니다.

그러나 개인이 운영하는 서버이거나 작은 스타트업이라면 서버 운영 시 여러 사용자를 둘 필요는 없습니다.

단 한명의 사용자면 충분하죠. 귀찮은 경우 root를 그냥 사용하기도 합니다. 그렇지만 root를 그대로 사용하는 하는 것은 해킹 위험에 더 노출됩니다.

서버 공략 시 사용자로 root를 설정하고 여기에 다양한 비밀번호를 대입해 서버 로그인을 시도하기 때문입니다.

어짜피 서버에서는 root에 준하는 권한을 가진 한 사람은 반드시 필요하기 때문에 root를 사용중지하고 대신 특정 사용자_ID에 root에 준하는 권한을 주는 것이 더 효율적입니다.

해커는 root가 아닌 특정 사용자_ID를 찾아야 하고 거기서 또 비밀번호를 찾아야하기 때문에 그만큼 해킹 확률을 낮출 수 있습니다.

거기에 fail2Ban과 같은 보안 프로그램과 결합한다면 더욱 더 해킹 가능성을 낮출 수 있습니다.

  1. ssh 접속 포트를 22번 포트가 아닌 다른 포트 사용
  2. ssh 접속 ip를 특정 ip대로 제한
    예를들어 한국 ip대로만 한정하든지 또는 집과 태블릿 접속 ip로만 한정
  3. root를 사용하지 않고 특정 사용자_ID만 사용
    보안을 위한 사용자_ID를 굉장히 길고 복잡하게 만드는 경우도 있는 어짜피 ssh나 sftp 사용 시 사용자_ID를 등록해 놓기 때문에 길고 복잡한 사용자_ID가 불편하지는 않음

특정 사용자_ID에게 임시로 root 권한을 부여하는 것은 아래 명령으로 가능합니다.

sudo -iCode language: PHP (php)

이러면 사용자_ID 비밀번호를 묻는데 비밀번호를 입력하면 마치 root처럼 사용할 수 있습니다.

사용자를 root처럼 이용하기

아시다시피 sudo 기능을 사용하려면 사용자_ID 비밀번호를 다시 입력해야 합니다. 보안을 위해서이지만 매넌 비밀번호를 입력하기가 귀찮을 수 있겠죠.

보안을 조금 포기하고 편리함에 더 방점을 둔다면 sudo 사용을 위해서 비밀번호 입력하지 않아도 되도록 만들 수 있습니다.

아래 visudo 명령을 사용하면 sido 사용자 권한을 조정할 수 있습니다.

sudo visudo

또는 

nano /etc/sudoersCode language: PHP (php)

그러면 /etc/sudoers 파일을 편집할 수 있는데요. 여기에서 root에만 허용되어 있는 NOPASSWD 권한을 사용하려는 사용자_ID에도 부과합니다.

즉 User privilege specification 부분에 사용자_ID ALL=(ALL) NOPASSWD: ALL을 추가합니다. 아래와 같은 모습이 됩니다.

root ALL=(ALL) NOPASSWD: ALL
사용자_ID ALL=(ALL) NOPASSWD: ALLCode language: PHP (php)
서버 보안, 일반 사용자를 root 사용자처럼 만들기-사용자 권한 부여

물론 이러한 명령어는 한번 더 비밀번호 체크 기능을 없애면서 보안이 더 낮아지는 효과가 있겠지만 사용자 입장에서는 로그인 후 매번 sudo 사용을 위해 비밀번호를 입력하는 불편함을 줄일 수는 있습니다.

편의성을 높이느냐 아니면 보안을 유지하느냐는 선택의 문제입니다.

uid와 gid를 root처럼 만든다.

다름으호 할 것은 사용자 ID와 그룹 ID를 root처럼 만드는 것입니다.

nano /etc/passwdCode language: PHP (php)

여기 맨 위를 보면 root 설정 내용을 볼 수 있는데요. root는 uid와 gid 값이 0입니다. 일반 사용자는 값이 1000으로 책정되어 있습니다.

여기서 사용자의 uid와 gid를 root처럼 0으로 변경합니다.

서버 보안, 일반 사용자를 root 사용자처럼 만들기-uid와gid를 root처럼 0으로 변경

root 그룹에 일반 사용자 추가

다음으로 할 것은 root 그룹에 일반 사용자 계정을 추가하는 것입니다.

nano /etc/groupCode language: PHP (php)

여기 맨위가 root 그룹을 나타내는데요. 여기서 맨위 root:x:0: 다음에 일반 사용자 계정을 추가하면 됩니다.

서버 보안, 일반 사용자를 root 사용자처럼 만들기- root 그룹에 일반 사용자 계정 추가

이어면 일반 사용자 계정으로 마치 root처럼 사용할 수 있습니다. 그러면 이제는 root를 굳이 사용할 필요가 없기 때문에 root 사용 중지시키면 됩니다.

sudo passwd -dl rootCode language: PHP (php)

참고

우분투 20.04와 PHP 8 기반 워드프레스 설치 방법

가상 서버를 운영하고픈 勇者에게 전하는 가상 서버 운영 입문 노하우 – Vultr 가상서버호스팅(VPS)를 중심으로

워드프레스 최적화를 위한 18개월간의 고민, 그 노하우를 담다.

도쿄 리젼과 비교해 본 Vultr 서울 리젼 사용기

가성비가 뛰어난 Vultr 가상서버호스팅(클라우드호스팅,VPS) 사용기

우분투 서버 보안 자동 업데이트 및 업데이트 메일 통보 방법

0

사이트 운영이든 프로그램이나 앱 사용 시 보안 업데이트는 반드시 적용해야합니다. 우부투 서버 운영 시 우분투 서버 보안 자동 업데이트 및 업그레이드 방법 및 이 결과 메일 통보 방법에 대해 살펴봅니다.

서버 보안 업데이트의 필요성

인터넷이 발전하면서 인터넷 사용자가 증가하고, 인터넷을 이용한 비지니스가 크게 융성해지고 있기 때문에 이에 편승한 해킹 위험이 크게 증가하고 있습니다.

테스트 또는 교육용으로 해킹하는 경우도 있겠지만 대부분은 무엇인가 이득을 노리는경우가 많죠. 그리고 이는 사용자가 많아질수록, 관련된 비지니스가 커질수록 시도는 증가하기 마련입니다.

이렇게 해킹 위험이 증가하고 프로그램등이 빠르게 변하면서 그동안 생각하지 못했던 위약점들이 나타나고 예전에 몰랐던 취약점을 새롭게 발견하기도 합니다.

그렇기 때문에 이러한 취약점들은 보완하는 보안 업데이트는 굉장히 자두 이루어집니다. 서버나 사이트를 안전하게 지키려면 이런 보안 업데이트를 바로바로 실행해 주는 것이 필요합니다.

실제로 해깅등은 이러한 업데이트를 무시하고 방치된 서버나 사이트에서 주로 일어나고 있다는 것도 보안 업데이트 및 업그레이드의 중요성을 웅변해 준다고 할 수 있습니다.

그리고 이런 업데이트 및 업그레이드 시 반드시 사전 백업이 필수적입이죠. 어떤 일이 닐어날지 모르기 때문이죠.

그런데 전업으로 서버 운영을 하는 담당자가 있다면 매일 일정 시간에 안정적을 상황을 파악해 업데이트 및 업그레이드를 진행 후 문제가 없는지 확인할 수 있지만.. 대부분의 경우는 그렇지 않고 서버에 접속할 여유가 적습니다.

그렇기 때문에 최소한 보안 업데이트 및 업그레이드는 자동으로 이루어지고 이를 메일로 통보받는 것이 필요합니다. 그리고 이러한 업데이트는 가능하면 사용하지 않는 새벽 시간에 이루어 지도록 설정하는 것이 필요할 것입니다.

  • 보안 업데이트 전에 사전 백업
  • 보안 업데이트는 자동 실행
  • 보안 업데이트로 시스템 부팅이 필요한 경우, 시스템 부팅은 사용자가 적은 새벽 시간에 진행
  • 보안 업데이트 내용은 메일로 송부

우분투 서버 보안 자동 업데이트 방법

여기서는 운분투 서버 운영 시 보안 자동 업데이트 방법에 대해서 살펴봅니다.

어느 운영체제나 마찬가지겠지만 리눅도도 필요가 있으면 이를 지원하는 다양한 방법들을 제공되고 있습니다.

우분투 리눅스에서는 보안 업데이트가 발생 시 관련 내용만 업데이트하도록 하는 unattended-upgrades라는 프로그램이 있습니다. 오늘은 이를 이용해 우분투 서버 자동 업데이트 방법에 대해서 알아보도록 하겠습니다.

unattended-upgrades 프로그램 설치

먼저 서버 업데이트 및 업그레이드를 통해서 최신 상태로 만듭니다.

sudo apt update && sudo apt upgradeCode language: PHP (php)

다음으로는 위에서 이야기한 unattended-upgrades 프로그램을 설치합니다. 이는 아래 명령을 사용합니다. 별다른 메일 프로그램이 설치되어 있지 않으면 postfix를 설치합니다.

sudo apt install unattended-upgrades apt-listchanges bsd-mailxCode language: PHP (php)

지메일 릴레이 서비를 이용해 우분투 서버에서 메일 발송 시스템 구축에 대해서는 아래 글을 참조하시기 바랍니다.

설치를 시작하다가 중간에 이 프로그램이 서버 용량을 사용할 것인데 설치를 진행할 것인지 질문합니다. 사용하겠다는 용량은 기껏 588K 정도 되기 때문에 부담없이 Y를 누릅니다.

# sudo apt install unattended-upgrades apt-listchanges bsd-mailx
Reading package lists... Done
Building dependency tree       
Reading state information... Done
unattended-upgrades is already the newest version (2.3).
The following packages were automatically installed and are no longer required:
  lockfile-progs sendmail-base sendmail-cf sensible-mda
Use 'sudo apt autoremove' to remove them.
Suggested packages:
  www-browser x-terminal-emulator
The following NEW packages will be installed:
  apt-listchanges bsd-mailx
0 upgraded, 2 newly installed, 0 to remove and 31 not upgraded.
Need to get 150 kB of archives.
After this operation, 588 kB of additional disk space will be used.
Do you want to continue? [Y/n] YCode language: PHP (php)

설정 보안 업체이트 허용

다음으로는 강제 보안 업데이트를 허용합니다. 아래와 같은 명령을 사용하면 중간에 unattended-upgrades를 사용하도록 설정할지 질문하는 팝업이 뜹니다.

sudo dpkg-reconfigure -plow unattended-upgradesCode language: PHP (php)

Applying updates on a frequent basis is an important part of keeping systems secure. By default, updates need to be applied manually using package management tools. Alternatively, you can choose to have this system automatically download and install important updates.Automatically download and install stable updates?  

오늘 목적이 바로 그것이므로 키보드를 왼쪽으로 옮겨 Yes를 선택합니다.

우분투 보안 자동 업데이트 설치 옵션, unattended-upgrades 사용 허용

unattended-upgrades 세부 옵션

이제 unattended-upgrades 세부 옵션을 정합니다. 이는 아래 파일을 편집합니다.

nano /etc/apt/apt.conf.d/50unattended-upgradesCode language: PHP (php)

저는 아래 몇가지를 조정했습니다.

  1. 업데이트 결과를 받을 이메일 주소 설정(73번째 줄)
  2. 보안 업데이는 종종 우분투 서버 리부팅이 필요할 경우가 있습니다. 이 경우 관리자 확인없이 리부팅 허용(93번째 줄)
  3. 서버 리부팅이 필요한 경우 리부팅 시간을 위험이 적은 새벽 시간으로 설정(102번째 줄)

아래는 제가 설정한 내용입니다. 설명 등 군더더기 내용을 그대로 두었습니다.

// Automatically upgrade packages from these (origin:archive) pairs
//
// Note that in Ubuntu security updates may pull in new dependencies
// from non-security sources (e.g. chromium). By allowing the release
// pocket these get automatically pulled in.
Unattended-Upgrade::Allowed-Origins {
        "${distro_id}:${distro_codename}";
        "${distro_id}:${distro_codename}-security";
        // Extended Security Maintenance; doesn't necessarily exist for
        // every release and this system may not have it installed, but if
        // available, the policy for updates is such that unattended-upgrades
        // should also install from here by default.
        "${distro_id}ESMApps:${distro_codename}-apps-security";
        "${distro_id}ESM:${distro_codename}-infra-security";
//      "${distro_id}:${distro_codename}-updates";
//      "${distro_id}:${distro_codename}-proposed";
//      "${distro_id}:${distro_codename}-backports";
};

// Python regular expressions, matching packages to exclude from upgrading
Unattended-Upgrade::Package-Blacklist {
    // The following matches all packages starting with linux-
//  "linux-";

    // Use $ to explicitely define the end of a package name. Without
    // the $, "libc6" would match all of them.
//  "libc6$";
//  "libc6-dev$";
//  "libc6-i686$";

    // Special characters need escaping
//  "libstdc\+\+6$";

    // The following matches packages like xen-system-amd64, xen-utils-4.1,
    // xenstore-utils and libxenstore3.0
//  "(lib)?xen(store)?";

    // For more information about Python regular expressions, see
    // https://docs.python.org/3/howto/regex.html
};

// This option controls whether the development release of Ubuntu will be
// upgraded automatically. Valid values are "true", "false", and "auto".
Unattended-Upgrade::DevRelease "auto";

// This option allows you to control if on a unclean dpkg exit
// unattended-upgrades will automatically run
//   dpkg --force-confold --configure -a
// The default is true, to ensure updates keep getting installed
//Unattended-Upgrade::AutoFixInterruptedDpkg "true";

// Split the upgrade into the smallest possible chunks so that
// they can be interrupted with SIGTERM. This makes the upgrade
// a bit slower but it has the benefit that shutdown while a upgrade
// is running is possible (with a small delay)
//Unattended-Upgrade::MinimalSteps "true";

// Install all updates when the machine is shutting down
// instead of doing it in the background while the machine is running.
// This will (obviously) make shutdown slower.
// Unattended-upgrades increases logind's InhibitDelayMaxSec to 30s.
// This allows more time for unattended-upgrades to shut down gracefully
// or even install a few packages in InstallOnShutdown mode, but is still a
// big step back from the 30 minutes allowed for InstallOnShutdown previously.
// Users enabling InstallOnShutdown mode are advised to increase
// InhibitDelayMaxSec even further, possibly to 30 minutes.
//Unattended-Upgrade::InstallOnShutdown "false";

// Send email to this address for problems or packages upgrades
// If empty or unset then no email is sent, make sure that you
// have a working mail setup on your system. A package that provides
// 'mailx' must be installed. E.g. "user@example.com"
Unattended-Upgrade::Mail "업데이트 상황을 받아 볼 이메일 주소";

// Set this value to one of:
//    "always", "only-on-error" or "on-change"
// If this is not set, then any legacy MailOnlyOnError (boolean) value
// is used to chose between "only-on-error" and "on-change"

// Remove unused automatically installed kernel-related packages
// (kernel images, kernel headers and kernel version locked tools).
//Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";

// Do automatic removal of newly unused dependencies after the upgrade
//Unattended-Upgrade::Remove-New-Unused-Dependencies "true";

// Do automatic removal of unused packages after the upgrade
// (equivalent to apt-get autoremove)
//Unattended-Upgrade::Remove-Unused-Dependencies "false";

// Automatically reboot *WITHOUT CONFIRMATION* if
//  the file /var/run/reboot-required is found after the upgrade
Unattended-Upgrade::Automatic-Reboot "true";

// Automatically reboot even if there are users currently logged in
// when Unattended-Upgrade::Automatic-Reboot is set to true
//Unattended-Upgrade::Automatic-Reboot-WithUsers "true";

// If automatic reboot is enabled and needed, reboot at the specific
// time instead of immediately
//  Default: "now"
Unattended-Upgrade::Automatic-Reboot-Time "03:00";

// Use apt bandwidth limit feature, this example limits the download
// speed to 70kb/sec
//Acquire::http::Dl-Limit "70";

// Enable logging to syslog. Default is False
// Unattended-Upgrade::SyslogEnable "false";

// Specify syslog facility. Default is daemon
// Unattended-Upgrade::SyslogFacility "daemon";

// Download and install upgrades only on AC power
// (i.e. skip or gracefully stop updates on battery)
// Unattended-Upgrade::OnlyOnACPower "true";

// Download and install upgrades only on non-metered connection
// (i.e. skip or gracefully stop updates on a metered connection)
// Unattended-Upgrade::Skip-Updates-On-Metered-Connections "true";

// Verbose logging
// Unattended-Upgrade::Verbose "false";

// Print debugging information both in unattended-upgrades and
// in unattended-upgrade-shutdown
// Unattended-Upgrade::Debug "false";

// Allow package downgrade if Pin-Priority exceeds 1000
// Unattended-Upgrade::Allow-downgrade "false";Code language: PHP (php)

APT 변경 사항 발생 시 받을 메일 주소 변경

다음으로는 listchanges.conf를 편집해 APT 변경 사항 발생 시 받아볼 이메일 주소를 root에서 설정합니다.

 nano /etc/apt/listchanges.confCode language: PHP (php)

여기 설정은 매우 간단한데요. 아래와 같은 항목으로 구성되어 있고 이중 메일 주소를 설정하면 됩니다.

[apt]
frontend=pager
which=news
email_address=업데이트 상황을 받아 볼 이메일 주소
email_format=text
confirm=false
headers=false
reverse=false
save_seen=/var/lib/apt/listchanges.dbCode language: PHP (php)

테스트

아래와 같은 명령을 사용해 제대로 작동하는지 확인해 봅니다.

sudo unattended-upgrades --dry-runCode language: PHP (php)

그러면 아래와 같은 형식으로 변경된 내용을 출력해 줍니다. 물론 근래에 업데이트 및 업그레이드를 통해서 업데이트할 내용이 없다면 아무런 메세지를 보내지 않습니다.

# sudo unattended-upgrades --dry-run
apt-listchanges: Reading changelogs...
apt-listchanges: Reading changelogs...
/usr/bin/dpkg --status-fd 10 --no-triggers --unpack --auto-deconfigure /var/cache/apt/archives/snmp_5.8+dfsg-2ubuntu2.1_amd64.deb /var/cache/apt/archives/libsnmp35_5.8+dfsg-2ubuntu2.1_amd64.deb 
/usr/bin/dpkg --status-fd 10 --configure --pending 
apt-listchanges: Reading changelogs...
apt-listchanges: Reading changelogs...
/usr/bin/dpkg --status-fd 10 --no-triggers --unpack --auto-deconfigure /var/cache/apt/archives/glib-networking-common_2.64.2-1ubuntu0.1_all.deb /var/cache/apt/archives/glib-networking_2.64.2-1ubuntu0.1_amd64.deb /var/cache/apt/archives/glib-networking-services_2.64.2-1ubuntu0.1_amd64.deb 
/usr/bin/dpkg --status-fd 10 --configure --pending 
apt-listchanges: Reading changelogs...
apt-listchanges: Reading changelogs...
/usr/bin/dpkg --status-fd 10 --no-triggers --unpack --auto-deconfigure /var/cache/apt/archives/libsnmp-base_5.8+dfsg-2ubuntu2.1_all.deb 
/usr/bin/dpkg --status-fd 10 --configure --pending 
apt-listchanges: Reading changelogs...
apt-listchanges: Reading changelogs...
/usr/bin/dpkg --status-fd 10 --no-triggers --unpack --auto-deconfigure /var/cache/apt/archives/libseccomp2_2.4.3-1ubuntu3.20.04.2_amd64.deb 
/usr/bin/dpkg --status-fd 10 --no-triggers --configure libseccomp2:amd64 
/usr/bin/dpkg --status-fd 10 --configure --pending 
apt-listchanges: Reading changelogs...
apt-listchanges: Reading changelogs...
/usr/bin/dpkg --status-fd 10 --no-triggers --unpack --auto-deconfigure --recursive /tmp/apt-dpkg-install-m8fgGO 
/usr/bin/dpkg --status-fd 10 --configure --pending 
apt-listchanges: Reading changelogs...
apt-listchanges: Reading changelogs...
/usr/bin/dpkg --status-fd 10 --no-triggers --unpack --auto-deconfigure /var/cache/apt/archives/linux-libc-dev_5.4.0-40.44_amd64.deb 
/usr/bin/dpkg --status-fd 10 --configure --pending Code language: PHP (php)

참고

이는 우분투 서버 보안 자동 업데이트 방법은 아래 글을 참조해 테스트 결과를 기반으로 재정리 했습니다.

아래 참고글은 우분투 18.04를 기준으로 했지만 저는 우분투 20.04에서 테스트해 보았습니다.

How to set up automatic updates for Ubuntu Linux 18.04

그리고 메일을 실행시마다 보내는 것은 아니고 문제가 발생하거나 패키지 업그레이드(problems or packages upgrades)가 발생시에만 보내게 됩니다.

웹서버 에러 – [emerg] bind() to [::]:443 failed (98: Address already in use)

0

요즘 서버가 불안정하면서 평소에 접해보지 못하던 희귀한 사례들을 만나게 되었습니다. 이중 NGINX의 443 포트 메모리가 이미 사용중이라서 NGINX 구동 불가하는 웹서버 에러를 만나 대처한 이야기를 풀어보고자 합니다.

이 현상은 멀웨어에 감염된 사이트를 지우고 다시 설치하는 가운데 만났습니다. 아마 해커가 교묘하게 사이트에서 얼웨어를 제거하면 웹서버가 작동되지 않토록 장난을 친것으로 추정하고 있는데요.

아무튼 멀웨어를 치료 후 서버를 다시 시작하면 시스템이 죽어버립니다.

그럴 겨우 보통 NGINX 웹서버를 체크 시 nginx -t 옵션을 사용해 점검합니다. 그러면 NGINX 세팅 중 문제 없는지를 체크해 이상이 없으면 OK 메세지를 보내는데요.

# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Code language: PHP (php)

그리고나서 NGINX 웹서버를 다시 구동시키면 아무런 문제가 없이 작동합니다.

문제 상황

그런데 이 경우는 nginx -t에서는 아무런 문제가 없다가 service nginx restart 명령을 받아 NGINX 웹서버를 다시 가동하려면 에러 메세지를 내면서 NGINX 웹서버를 가동시키지 못합니다.

아래 메세지처럼 ‘systemctl status nginx.service’로 점검하라고 메세지 나오며, systemctl status nginx.service를 이용해 점검해보면

  • NGINX 활성화할 수 없으며
  • 80포트를 이미 사용하고 있다고 합니다.
# service nginx restart 
Job for nginx.service failed because the control process exited with error code.
See "systemctl status nginx.service" and "journalctl -xe" for details.

# systemctl status nginx.service
● nginx.service - nginx - high performance web server
     Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
     Active: failed (Result: exit-code) since Thu 2020-07-02 16:37:00 KST; 28s ago
       Docs: http://nginx.org/en/docs/
    Process: 1109 ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf (code=exited, status=1/FAILURE)


Jul 02 16:36:57 etrend systemd[1]: Starting nginx - high performance web server...
Jul 02 16:36:57 etrend nginx[1109]: nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in us>
Jul 02 16:36:58 etrend nginx[1109]: nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in us>
Jul 02 16:36:58 etrend nginx[1109]: nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in us>
Jul 02 16:36:59 etrend nginx[1109]: nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in us>
Jul 02 16:36:59 etrend nginx[1109]: nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in us>
Jul 02 16:37:00 etrend nginx[1109]: nginx: [emerg] still could not bind()
Jul 02 16:37:00 etrend systemd[1]: nginx.service: Control process exited, code=exited, status=1/FAILURE
Jul 02 16:37:00 etrend systemd[1]: nginx.service: Failed with result 'exit-code'.
Jul 02 16:37:00 etrend systemd[1]: Failed to start nginx - high performance web server
Code language: PHP (php)

net-tools로 원인 파악

그러면 누가 이미 address를 사용하고 있는지 점검하기 위해 netstat를 점검해 봅니다.

먼저 net-tools을 설치하구요.

apt install net-toolsCode language: PHP (php)

다음으로 아래 명령어로 네트워크 상황을 점검해 봅니다.

netstat -tulpNCode language: PHP (php)

그랬더니 아래와 같이 http로 apache2가 이미 사용하고 있다고 합니다. 여기는 NGINX 웹서버이므로 hhtps는 NGINX가 사용해야 정상이겠죠.

# netstat -tulpN
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 localhost:6010          0.0.0.0:*               LISTEN      1185/sshd: root@pts 
tcp        0      0 localhost:mysql         0.0.0.0:*               LISTEN      958/mysqld          
tcp        0      0 localhost:submission    0.0.0.0:*               LISTEN      1315/sendmail: MTA: 
tcp        0      0 0.0.0.0:*****           0.0.0.0:*               LISTEN      687/sshd: /usr/sbin 
tcp        0      0 localhost:domain        0.0.0.0:*               LISTEN      585/systemd-resolve 
tcp        0      0 localhost:smtp          0.0.0.0:*               LISTEN      1315/sendmail: MTA: 
tcp6       0      0 localhost:6010          [::]:*                  LISTEN      1185/sshd: root@pts 
tcp6       0      0 [::]:http               [::]:*                  LISTEN      702/apache2         
tcp6       0      0 [::]:*****              [::]:*                  LISTEN      687/sshd: /usr/sbin 
udp        0      0 localhost:domain        0.0.0.0:*                           585/systemd-resolve 
udp        0      0 45.77.96.212.vul:bootpc 0.0.0.0:*    Code language: PHP (php)

어떤 상황에서 나타나는가

어떤 상황에서 이러한 문제가 발생하는지 점검해 보았는데요.

확실한 것 중의 하나는 certbot 명령을 dry run 옵션과 같이 사용 시 반드시 이 문제가 나타납니다.

Let’s encrypt SSL 인증 갱신 명령 옵션에 –dry-run이 있습니다. 이는 SSL 인증 완료 시기가 아니라도 종료 상황을 만들어 적절하게 갱신이 되는지를 시뮬레이션할해 볼 수 있는데요.

/usr/bin/certbot renew --dry-run >> /var/log/letsencrypt/renew.logCode language: PHP (php)

이 옵션을 사용해 certbot new 명령을 실행 결과입니다.

~# /usr/bin/certbot renew --dry-run >> /var/log/letsencrypt/renew.log
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Cert not due for renewal, but simulating renewal for dry run
Plugins selected: Authenticator nginx, Installer nginx
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for happist.com
http-01 challenge for www.happist.com
nginx: [error] invalid PID number "" in "/var/run/nginx.pid"
Waiting for verification..
Cleaning up challengesCode language: PHP (php)

그리고 다시 nginx를 구동시키면 구동되지 않습니다. 그래서 systemctl status nginx.service 명령으로 상황을 파악해보면 위에서 소개한 것처럼 이미 address가 사용 중이라고 나옵니다.

~# systemctl status nginx.service
● nginx.service - nginx - high performance web server
     Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
     Active: failed (Result: exit-code) since Sat 2020-08-08 12:49:38 KST; 3min 9s ago
       Docs: http://nginx.org/en/docs/
    Process: 2257 ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf (code=exited, status=1/FAILURE)

Aug 08 12:49:37 etrend nginx[2257]: nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
Aug 08 12:49:37 etrend nginx[2257]: nginx: [emerg] bind() to 0.0.0.0:443 failed (98: Address already in use)
Aug 08 12:49:37 etrend nginx[2257]: nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
Aug 08 12:49:37 etrend nginx[2257]: nginx: [emerg] bind() to 0.0.0.0:443 failed (98: Address already in use)
Aug 08 12:49:38 etrend nginx[2257]: nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
Aug 08 12:49:38 etrend nginx[2257]: nginx: [emerg] bind() to 0.0.0.0:443 failed (98: Address already in use)
Aug 08 12:49:38 etrend nginx[2257]: nginx: [emerg] still could not bind()
Aug 08 12:49:38 etrend systemd[1]: nginx.service: Control process exited, code=exited, status=1/FAILURE
Aug 08 12:49:38 etrend systemd[1]: nginx.service: Failed with result 'exit-code'.
Aug 08 12:49:38 etrend systemd[1]: Failed to start nginx - high performance web server.
Code language: PHP (php)

해결 방안

이 문제의 근본적인 해결 방안, 즉 이런 문제가 나타나지 않토록 만드는 방법은 아직 확인하지 못했습니다.

다만 임시로 nginx 웹서버에서 다른 프로그램이 address를 먼저 사용한다는 문제를 해결을 위해서는 대략 두가지 방법이 있습니다.

apache2 stop 명령

우분투 설치 시 기본으로 apache2가 설치되어 있기 때문에 이 apache2 stop 명령을 사용하면 이 문제가 일시적으로 해소됩니다.

sudo /etc/init.d/apache2 stop 

sudo service nginx restartCode language: PHP (php)

fuser -k 80/tcp 사용

저는 apache2를 없애버리면 이 문제가 해소될 것으로 보고 apache2를 삭데햌ㅆ는데요. 그럼에도 불구하고 이문제는 계속 발생했습니다. apache2가 이 문제 원인은 아니라는 것이죠.

아마 위에서 지적한 대로 SSL 인증 과정에서 80주소를 일부 어플리케이션이 사용하고 되돌려주지 않는 버그가 있는 것 같습니다.

apsche2가 없는 경우는 아래 명령을 사용합니다.

sudo fuser -k 80/tcpCode language: PHP (php)

그러면 아래와 같이 80/tcp address를 kil합니다.

~#  sudo fuser -k 80/tcp
80/tcp:               2240  2249Code language: PHP (php)

그리고 nginx를 구동하면 제대로 작동합니다.

SSL 갱신 스크립트 개선

이런 문제를 반영하여 SSL 갱신 스크립트를 아래와 같이 변경합니다. nginx를 구동하기 전에 fuser -k 80/tcp 명령을 추가하는 것입니다.

/etc/init.d/nginx stop
/usr/bin/certbot renew --dry-run >> /var/log/letsencrypt/renew.log
fuser -k 80/tcp
/etc/init.d/nginx start Code language: PHP (php)

PHP 에러 대응 – PHP Warning: call_user_func_array() expects parameter 1 to be a valid callback

워드프레스 운영을 위해 다양한 커스텀 코드를 적용하다보면 PHP 에러를 만나게 됩니다.

이러한 PHP 에러중에는 치명적인 것도 있지만 대부분은 워드프레스 사이트가 다운될 정도로 심각한 경우가 아니므로 무시하게 마련입니다.

그러나 PHP 에러 대응이 적절하지 않으면, 서버에서는 끊임없이 서버 에러 메세지를 발송하면서 궁극적으로 시스템 자원을 약화시키는 경우가 있습니다.

여기에서는 대수롭지 않게 넘기기 쉽운 PHP 에러 중 PHP Warning: call_user_func_array() expects parameter 1 to be a valid callback에 대해서 알아봅니다.

이 글은 PHP 에러 대응 사례-PHP Warning: call_user_func_array() expects parameter 1 to be a valid callback를 기반으로 조금 내용을 수정한 것입니다.

PHP 에러 메세지 사례

오늘 소개하는 PHP 에러 대응 -PHP Warning: call_user_func_array() expects parameter 1 to be a valid callback도 이러한 예의 하나인데요.

보통 이런 에러가 발생하면 아래와 같은 에러 메세지를 보냅니다. 이는 서버의 error.log에서 발견할 수 있습니다.

웹서버로 NGINX를 사용한다면 /var/log/nginx 폴더에 있는 error.log에서 확인할 수 있습니다. 하나의 실예를 들기 위해 에러 메세지를 그대로 가져와 봤습니다.

2020/07/04 13:33:50 [error] 2739157#2739157: *149426 FastCGI sent in stderr: "PHP message: PHP Warning:  call_user_func_array() expects parameter 1 to be a valid callback, function 'child_enqueue_styles' not found or invalid function name in /home/사이트 이름/wp-includes/class-wp-hook.php on line 287", client: 220.64.101.2, server: 사이트 이름.com, request: "GET /571441/ HTTP/1.1", host: "사이트 이름.com"Code language: PHP (php)

에러 메세지의 원인

이러한 메세지가 나오는 것은 대부분 워드프레스 차이드 테마의 hunctions.php에 다음과 같은 형식의 커스텀 코드가 있는 경우가 발생한다고 합니다.

add_action( 'wp_enqueue_scripts', 'custom_scripts', 9999 );Code language: PHP (php)

저의 경우에는 다음과 코드가 있었습니다.

add_action( 'wp_enqueue_scripts', 'child_enqueue_styles', 15 );Code language: PHP (php)

문제 해결

오랜만에 서버가 제대로 작동하는지 확인하면서 NGINX 웹서버가 끊임없이 이런 메세지를 내고 있다는 것을 발견하고 토요일 오전 내내 구글링을 통해서 문제 해결 방법을 찾았습니다.

그러나 좀처럼 이 문제 해결 방안을 찾을 수 없었는데 근 5시간이상의 구글링끝에 이에 대한 해결책을 제시하는 글을 찾았습니다.

Warning: call_user_func_array() expects parameter 1 to be a valid callback, function ‘custom_scripts’ not found or invalid function name in /home/.sites/149/site5056863/web/web/wp-includes/class-wp-hook.php on line 286

위 글에 따르면 문제 원인이 커스텀 코드에서 발생하고 있기 때문에 문제 해결은 이 커스텀 코드를 삭제함으로 가능합니다.

저의 경우 차일드 테마를 별도로 만들지 않고 MU-PLUGINS에서 별도 php 파일을 만들면서 상기 커스텀 코드를 적용했는데요. 굳이 필요한 컷텀 코드는 아니었나 봅니다.

이 커스텀 코드 삭제 후 별다른 이슈가 없었고, 오히혀 에러 메세지는 사라졌습니다.

WWDC 20이 보여준 애플 미래 전략의 핵심, AR/VR 비즈니스

0

코노라 팬데믹으로 애플 비지니스 환경이 그리 우호적이지 않음에도 불구하고 애플 주가는 사상 최고를 기록하며 승승 장두하고 있습니다. 애플 주가를 그렇게 끌어 올리는 애플 미래 전략이 궁금한 일이 아닐 수 없습니다.

그래서 애플 미래 전략에 대한 관심을 가질 필요가 있는 지점이기도합니다. 그러는 가운데 최근 애플의 연례 행사인 WWDC에서는 iOs 업그레이드를 비롯한 다양한 내용이 발표디었습니다.

애플 미래 전략에 대한 많은 분석 중 애플이 이 모든 준비들은 애플 미래전략으로 AR/VR 비즈니스를 겨냥하고 있다는 것에 주목해 애플 미래 전략을 분석한 박시용님의 페북글이 있어 허락을 받아 여기에 소개합니다.

박시용님은 <WWDC에서 일관되게 가르키는 단 한가지. 바로 AR/VR 비즈니스>라는 글을 통해서 이번 WWDC의 주제는 1.방해하지 않는 UX 2.플랫폼 대통합 3.측위기술의 3가지로 보고 각 내용을 분석하면서 이러한 모든 것의 종착역은 미래 준비로서 AR/VR 비즈니스에 대해 주목하고 있습니다.

https://www.facebook.com/lemon119/posts/3233833476674950

WWDC에서 일관되게 가르키는 단 한가지. 바로 AR/VR 비즈니스

이번 애플 WWDC 2020을 곱씹어 보면서 계속 들었던 생각은 ‘얘네들, 노골적으로 AR/VR 시장을 준비하는구나.’ 였는데, 외신을 비롯하여 아무도 AR/VR과 연결지어 분석한 내용이 없는것 같아 한판 정리해봅니다.

올해 WWDC에서는 기존과는 다르게 하드웨어 발표는 하지 않고 지나갔습니다. 각 디바이스들의 OS의 발표를 마치고 ARM기반의 새로운 프로세서 자랑을 한 뒤 마무리 지었죠. 하지만 한번 더 살펴보면 이 모든것의 끝에는 AR/VR 비즈니스가 있었습니다.

얼마전 프로 유출러 Jon Prosser 내용에 따르면 애플은 Apple Glass라는 이름으로 AR디바이스를 준비중이며, 사생활 침해를 막기 위해 카메라는 부착하지 않고 이번 아이패드 프로에 부착된 라이다센서를 달았다고 합니다. 발표는 내년 상반기, 출시는 2년후라고 예측했습니다.

애플 글래스 특허 도면, apple glass things-you-should-know-2

그럼 WWDC로 돌아가서 다시 살펴볼까요. 이번 발표를 관통하는 주제는 크게 3가지입니다. 1.방해하지 않는 UX 2.플랫폼 대통합 3.측위기술

방해하지 않는 애플 UX

iOS, iPadOS, MacOS의 UX가 매우 많이 바뀌었습니다. 특히나 iOS의 경우에는 앱서랍이나 위젯등을 도입함으로써 원하는정보에 빠르게 다가갈 수 있게되었습니다.

또한 사용중에 전화가 오는 경우 기존에는 화면 전체가 전화 화면으로 전환되었지만 이제는 위에서 콜바 하나만 작게 내려와서 기존 작업을 방해받지 않게 되었죠.

그룹메시지에서도 누가 말을 하는지 작게 말풍선으로 표시되게 되었고 시리 화면도 전체를 가리지 않게 되었습니다.

이거 안드로이드에서는 십년전부터 있던 기능들입니다. 그 기능들은 애플은 왜 이제서야 적용을 한다고 하는 걸까요? 전세계 시총 1위인 회사가 설마 기술이 없어서 구현 못했을리는 없고요.

수년간 욕을 먹으면서도 바꾸지 않았던 UX를 이렇게 ‘방해하지 않는 UX’로 전환을 꾀하는건 이유가 있어서일겁니다.

항상 애플의 문법은 동일했습니다. First Mover보다는 기술이나 유저들의 경험치가 어느정도 무르익은 다음 극한의 ux완성도를 들고 제품을 출시하였습니다.

몇년전 애플워치가 출시하기도 이전에 제가 웨어러블 업체 발굴을 위해서 심천에 간 적이 있었는데, 그 당시 판매가(공급가 말고) 3만원 미만의 제품들이 수백종류가 넘었습니다. 그러나 애플워치가 햅틱엔진을 달고 나오자 시장의 판도는 다 바뀌었죠. 제가 만났던 그 업체들, 아직까지 제품을 만들고 있지는 않을것 같습니다.

몇년째 욕을 먹으면서도 수신전화 화면을 전체화면으로 유지하는대신 아이폰을 사용하지 않을때는 밀어서 받기, 사용중에는 버튼으로 받기를 나눠놓을정도로 디테일한 ux팀이, 이번에 방해받지 않는ux로 대대적인 개편을 한 이유는 앞으로 AR의 시대가 도래했을때의 유저들이 경험할 사용성에 대한 준비라고 생각됩니다.

이번 iOS에서 pip가 적용되었는데 기존의 안드로이드와는 다르게 팝업으로 떠있는 동영상 창을 바깥으로 밀어놓았다가 사용할때는 화살표를 살짝 당겨오는 방식을 도입했습니다. 이것도 ar글라스를 사용할때 꼭 필요한 ux이며, 유저들에게는 ar글라스 출시 이전부터 익숙하게 경험할 수 있게 하는 장치라고 보여집니다.

플랫폼 대통합

이번 발표의 원모어띵은 ARM기반의 Apple Silicon 칩셋이었습니다.

2005년 파워PC에서 인텔로 전환할때의 wwdc에서는 인텔이라는 회사를 특히 강조했지만 이번에는 어디에서도 ARM이라는 이야기는 들리지 않았습니다. 오로지 ‘우리는 칩셋까지 자체 설계하고 모든 프로그램이 원활히 돌아갈 수 있도록 하겠다.’에 초점을 두었죠.

외부의 칩셋을 쓰지 않고 자체적으로 칩셋을 설계하는경우, 디바이스 업데이트 주기를 칩셋의 스케줄에 맞출 필요도 없고 제품 원가도 유의미하게 낮아질 수 있습니다.

그러나 큰 허들이 있는데 이 경우에는 기존에 사용하던 레거시 프로그램들을 전부 ARM 커스텀 칩셋에 맞추어 컴파일하거나 가상화 머신을 사용해야 하는 단점이 발생합니다.

그러나 이런 과도기가 지나가게 되면 기존의 ARM칩셋 위에서 돌아가던 iOS, iPadOS의 어플들을 자유롭게 맥에서도 교차 사용 가능하게 됩니다.
이는 디바이스의 제한 없이 기존의 레거시 프로그램, 수많은 개발자들이 앱스토어에 등록한 어플들을 사용할 수 있다는 뜻입니다.

또한 애플의 A프로세서는 고성능, 저전력의 특징을 갖고 있습니다.

위의 애플글라스의 경우 1세대 기기에서는 독자적인 프로세싱보다는 아이폰과 연결되어 아이폰에서 연산작업이 주로 이루어지겠지만 시간이 지나면 결국 AR/VR 디바이스 자체에서 프로세싱하게 될겁니다.

애플은 스마트스피커인 홈팟에도 아이폰6에 들어가는 A8프로세서를 탑재했고 심지어는 조만간 출시될 무선충전기인 Airpower에는 아이폰X에 들어가는 A11칩셋을 사용한다는 루머가 있습니다.

이는 애플글라스에서도 A칩셋을 사용할것이며 이 위에서 돌아가는 서비스들은 아이폰, 아이패드, 맥 상관없이 모든 플랫폼에서 seamless하게 경험할 수 있다는 장점이 있습니다.

위의 애플글라스 유출내용에 따르면 2년후에 출시 예정이라고 합니다. 그리고 이번 wwdc의 발표에 따르면 2년후에는 모든 맥은 Apple Silicon 기반으로 출시된다고 합니다. 무섭도록 맞아떨어지는 스케줄이죠.

측위 기술

이번 wwdc의 발표 중 별것 아닌것처럼 스리슬쩍 빠르게 넘어간 것들 중 아주아주 중요한것들이 있습니다.

우선 Apple Car Key 시연 중 소개되었던 u1칩셋의 모습, 손 씻을때 애플워치가 자동으로 손씻는 모션을 알아채고 가이드 해주는 기능, 마지막으로 에어팟 프로의 펌웨어 업데이트로 공간음향을 구현하는 기능입니다.

위의 기능들은 모두 사용자의 모션과 위치를 측정하는 측위기술들이 뒷받침 되어야 합니다.

작년 아이폰11 발표때 애플은 아이폰11의 가장 큰 기술적 혁신인, UWB(초광대역)칩인 u1칩을 내장하고도 별다른 언급을 하지 않았습니다.

그러나 u1칩은 센티미터 단위의 위치탐색 능력 및 벽과 인체등의 장애물에 방해받지 않는 특성을 이용하여 애플 카 키, 홈킷 시스템과 더불어 앞으로 출시될 애플글라스에서 가장 중요한 역할을 하게 될 겁니다.

앞으로 애플워치, 애플글라스를 비롯하여 모든 디바이스에 u1칩셋이 확실시 됩니다.

이렇게 아이폰, AR글라스, 애플워치등이 전부 U1칩을 탑재하고 있다면 서로의 위치를 파악해 미묘한 손이나 얼굴의 움직임 만으로 가상물체를 조종하게 될 수 있을것이고요.

그렇다면 엔드유저가 꼭 일반적인 소비자가 아닐수 있고, 이는 가상물체의 세밀한 원격조정이 필요한 B2B로의 비즈니스 확장을 기대해 볼 수도 있습니다.

또한 에어팟 프로의 공간음향 기능 추가로 소리에도 방향성을 표현할 수 있게 되었으니, 인간의 오감 중 미각이랑 후각과 관련된 기능만 붙여서 출시하면 완벽한 VR세상이 도래하겠네요.

마치며

정리해보자면, 애플은 이번 WWDC에서 ‘앞으로 2,3년동안 사용자들에게 새로운 UX를 습득시키고 그 후에 본격적인 AR/VR 디바이스를 출시하면서 시장을 지배하겠다.’ 라는 내용을 발표한것과 다름이 없습니다.

가을에 새롭게 출시될 아이폰 및 다른 디바이스들이 이런 방향과 얼마나 부합하는지 찾아보는것도 재미있는 일이 될겁니다.

결론: 애플 주식은 오늘이 가장 저렴합니다.

참고

애플과 페이스북의 고객 데이타 확보 경쟁, 반목속에 실질적 동맹 가능성

최근 애플이 WWDC에서 발표 내용 그리고 페이스북에 대한 광고 보이콧등이 경영 환경이 빠르게 변하고 있습니다. 이런한 변화 가운데 고객 데이타 확보를 위한 애플과 페이스북 경쟁속에 숨어있는 애플과 페이스북 전략에 대해 제품 혁신 이론으로 유명한 톰 벤슨의 글이 있어 소개합니다.

소비자 대상 하드웨어와 소프트웨어 상품을 대표하는 애플과 페이스북이 서로 치열하게 반목하고 있지만, 실질적으로는 각각의 경제적 해자를 강화하는 선에서 동반자 측면도 있다는 분석입니다.

  • 글쓴이는 애플 혁신 가능성 논란이 있을 때부터 애플의 경제적 해자는 사용자를 중심에 두고 관련 사용성을 극대화하면서 다른 업체들과 차별화한 것에서 애플의 지속적인 성장 가능성을 가져왔다고 보고 있습니다.
    .
  • 그러면서 이번 애플이 WWDC에서 발표한 내용 중에는 쿠키 사용과 같은 개인 정보 추적을 거의 무력화시킨 것이 있는데 이는 페이스북을 비롯한 상당수 인터넷 비지니스 업체들를 흔들 수 있는 요소라고 보고 있습니다.
    .
  • 그러나 애플의 이러한 정책은 애플의 서비스 수익 강화 방침에 따라 앱스토어 강화 방침의 하나라고도 해석할 수 있지만, 실상 앱스토어를 확대하고 수익 확대에는 페이스북이 지대한 역활을 했으며, 앞으로도 페이스북의 역활을 무시할 수 없을 것으로 예상합니다.

    애플이 고객 데이타 확보를 막는 것은 대다수 소비자 데이타 기술에 의존하는 업체들에게 큰 위협이 되지만 페이스북처럼 독보적인 기술로 극복하면 오히려 더 큰 기회를 가질 수 있다고…
    .
  • 또한 페이스북은 애플이 쿠키 활용을 극히 제한하면서 쇼피파이와 같은 후발 주자들이 새로게 부상하는 것을 막고 이미 기술을 확보한 페이스북이 새로운 기회를 잡는데 큰 기여를 하고 있다고 분석합니다. 이러한 분명한 예로 페이스북 샵을 들고 있습니다.
    .
  • 페이스북으로서는 현재 진행되고 있는 코로나 팬데믹, 기존 업체들의 광고 보이코트등이 장기적인 성장에 큰 상처를 주지 않으며, 오히려 데이타 확보 및 이용등에서 타의 추종을 불허하는 기술력을 가지고 있기 때문에 오리혀 기회가 될 것으로 보고 있습니다.

    페이스북 광고 보이코트를 주도하고 있는 유니레버와 같은 기존 대기업들은 페이스북에서 차지하는 비중은 20%로 생각보다 높지않고, 페이스북은 롱테일에 의지하기 때문에 다른 광고주로 대체될 것이며, 더우기 기존 대기업들은 가장 낮은 광고비를 책정받아 왔는데 이게 없어지면서 평균적인 광고 단가는 높아질 것으로 봅니다.
    .
  • 결론적으로 애플과 페이스북은 치열하게 경쟁하면서도 알게 모르게 서로의 비지니스 모델을 강화해주는 역활을 하는 실질적인 동맹이라고도 해석할 수 있습니다.

이 글에서는 제품 혁신이론으로 유명한 톰 벤슨이 최근 애플과 페이스북 움직임과 발표들을 기반으로 그들의 전략에 대해 정리한 Apple and Facebook를 번역 소개하고 있습니다.

어려운 내용이라 의역도 많고 부족한 부분이 있을 것이지만 이해해 주시고영어 공부 겸해서 번역을 해봤는데요.

어려운 내용이라 의역에 의존하기도 했고 구글의 힘을 빌리기는 했지만 부족한 부분이 있을 것이지만 이해해 주시고, 수정 사항을 알려주시면 좋겠습니다.


4대 소비자 대상 기술 회사 중 구글과 아마존은 누구나 이해하기 쉬운 경제적 해자를 가지고 있었습니다. 최근 마이크로소프트가 소매점 폐쇄를 결정한 것은 소비자 대상 비지니스에서 5년 만에 이루어진 후퇴입니다.

구글은 고객 접점을 제어함으로써 데이터 및 인프라 분야에서 큰 이점을 확보하고 있습니다(안드로이드를 완전히 소유하고 다른 플랫폼에 디폴트 배치(프리로드)토록 강제합니다).

아마존은 쇼핑 소비자들이 1순위로 접속하는 아마존닷컴에서 상품 검색부문을 제어함으로써 인프라와 데이터에서 큰 이점을 가지고 있습니다. 경쟁자들이 아마존과 싸우는 것은 매우 힘들고 심지어는 불가능하기까지 합니다.

애플의 경제적 해자

하지만 애플은 아이폰의 급격한 성공 이후에도 수년동안 사업의 지속가능성에 대한 의문에 직면했습니다.

Stratechery(이 글을 쓴 톰 벤슨이 운영하는 블로그)가 인기를 얻을 수 있었던 주제 중 하나가 아이폰의 지속 가능성이었습니다. 당시 Clayton Christensen 교수를 포함한 많은 사람들의 아이폰이 제대로 된 혁신을 이어가지 않기 때문에 몰락할 것이라는 주장햇습니다.

그러나 저는 2014년 글에서 당시 애플 접근 방식이 지속 가능한 이유를 설명했습니다.

게다가 통합 솔루션(intergrated solution)은 사용자 환경에 있어 항상 우수합니다. 모든 것을 같이 만들면, 모든 것이 함께 잘 작동하도록 보장할 수 있기 때문에, 표준과 상호 연결 시 나올 수 있는 불가피한 어려움과 최적화의 부족을 피할 수 있습니다.

그러나 핵심은 사용자들이 이러한 통합과 경험을 중요시한다는 것입니다. 그것이 바로 제가 크리스텐슨의 파괴적인 혁신 이론에 대한 비판의 핵심입니다. 사용자 경험 관점에서 제품 구매자가 사용자일 때에 중요합니다.

사용자들은 사용자 경험에 대해 관심을 가지지만(놀라움운 일이지요!) 실제 사용자가 아닌 구매자(대부분의 비즈니스 대 비즈니스 제품 및 모든 Christensen의 예처럼)들은 그렇지 않습니다.

저는 이것이 크리스텐슨이 애플에 대해 맹점을 갖게 된 뿌리라고 믿습니다. 한 달 전 헨리 블로젯과의 인터뷰에서 다음과 같이 말했습니다.

만약 애플이 그러한 특별한 사용자 경험을 가지고 있다면, 여기에 모듈로 참여하는 사람들은 (이를 구현하려고) 노력할 것이라는 것을 충분히 예측할 수 있습니다.
또 그들은 이것을 어떻게 구현해야하는지 이해하려는 강력한 동기를 가질 것이라는 것을 예상할 수 있습니다.

그리고 궁극적으로 한계를 가지고 있는 한, 애플은 어느 순간 한계에 부딪힙니다. 따라서 다른 제품 카테고리나 독점적인 제품을 개발하려고 합니다.
왜냐하면 그들은 실제로 독점적인 제품을 개발하는 데 능숙하기 때문입니다.
대부분의기업은 제한된 운영 체제에 대한 통찰력을 가지고 있지만, 한 번 최고점에 도달한 후 쇠락하게 됩니다.

하지만 이 사용자 경험 품질에는 한계가 없다는 것입니다. 다른 거의 모든 산업의 소비자들이 보여주듯이, 최고 제품과 그밖의 제품 사이에 명확히 차이를 설명할 수 있는 것이 있다면, 사용자 기반 일부는 최고 수준의 프리미엄을 지불할 것입니다.

그것이 애플 미래의 열쇠입니다. 애플은 2년마다 완전히 새로운 제품을 필요로 하지 않습니다. 그들은 단지 그들의 카테고리에서 가장 좋은 제품을 계속 만들기만 하면 됩니다. 쉬워요, 그렇죠?

물론 쉽지는 않지만, 특히 하드웨어에 관한 한, 애플의 리더쉽은 그 어느 때보다도 큽니다. 이는 탁월한 시스템 온 칩 덕분입니다. 2020년 WWDC를 보도하는 헤드라인 뉴스에는 애플이 이러한 특별한 이점을 Mac으로 확장하고 있다고 알려주고 있습니다.

물론 최고 기기를 제공하는 것만으로는 역시 충분하지 않습니다. 많은 사람들에 따르면 이것이 애플이 영원히 불운했던 또 다른 이유라고 합니다. 다시 2013년 Business Insider에 소개된 Blodget을 소개하겠습니다.

스마트폰과 태블릿이 플랫폼이 아니었다면(제품의 가치와 고객의 구매 결정 시 중요한 것이 제품 그 자체였다면) 애플의 시장 점유율 하락은 별 차이가 없을 것입니다. 애플 옹호자들이 중요한 것은 애플 “시장 점유율”이 아니라 “이익 점유율”이라고 우쭐대며 주장할 때 그것은 정확한 지적이엇습니다.

하지만 스마트폰과 태블릿은 하나의 플랫폼입니다. 써드 파티 기업들이스마트폰 및 태블릿 플랫폼에서 실행할 앱과 서비스를 구축하고 있습니다.

이와 같은 애플리케이션과 서비스는 플랫폼을 더욱 가치 있게 만들고 있습니다. 소비자들은 스마트폰과 태블릿 플랫폼에서 실행되는 앱과 서비스를 중심으로 자신의 삶을 표준화하고 있습니다.

이러한 “네트워크 효과” 때문에 플랫폼 시장에서 시장 점유율이 우세한 것은 큰 경쟁 우위입니다.

플랫폼 시장에서는 종종 생각하기조차 싫지만 항상 미친 듯이 강력한 마이크로소프트가 PC 시장에서 수십 년 동안 보여주었듯이, 대부분의 힘과 이익은 결국 시장 점유율 선두 업체에 귀속됩니다.

사실, 애플이 사용자 경험을 우선시하는 것은 어떤 일종의 해자가 아니라 애플이 필요로 하는 것보다 훨씬 더 애플을 필요로 하는 개발자들의 지렛대이기도 했습니다.

따라서 지난 2주 동안 두 번째로 큰 이슈는 애플의 앱 스토어 정책입니다.

애플이 서비스 매출 증대를 위해 노력하면서 애플은 지난 몇년동안 (앱 스토어관련) 불문율 규정을 대폭 강화해 왔습니다.

소규모 업체의 개발자이든지, 대형 업체의 개발자이든지 , 모든 개발자들은 아이폰 제조업체, 애플의 요구에 응할 수 밖에 없습니다.

그것은 애플이 사용자가 사용할 아이폰 앱 제공에 있어서 누구도 피해갈 수 없는 게이트 키퍼로 작용하는 가장 가치있는 로열티와 앱 리뷰를 결합했기 때문입니다.

빌 게이츠 라인

한편, 페이스북은 종종 애플과 반대로 생각되는데, 애플은 제품을 팔고, 페이스북은 광고를 판매합니다. 애플은 데이터 수집을 최소화하고 페이스북은 이를 최대화합니다. 애플은 플랫폼이고, 페이스북은 앱일 뿐입니다.

하지만, 두 기업이 공유하는 것은 실리콘 밸리의 영원한 회의론입니다. 페이스북은 설립에서부터 야후의 인수 제의를 거절한 결정, IPO 이후의 주가 폭락까지 지속적으로 (성공을) 의심 받아왔습니다.

트위터, 스냅챗, 틱톡에 이르기까지 모든 새로운 소셜 미디어 앱들은 페이스북을 끌어내려 마침내 제2의 마이스페이스로 만들어 버릴 수 있을 것이라는 기대를 받았었습니다.

하지만 사실은 많은 면에서 페이스북은 애플보다 플랫폼에 가깝습니다. 2018년에 저는 페이스북에 대한 비판으로 가득찬 빌 게이츠 라인(The Bill Gates Line)이라는 글을 썼습니다.

지난 몇 주 동안 저는 플랫폼과 애그리게이터(aggregators) 사이에 어떤 차이가 있는지 탐구해왔고, 세밀 샤와의 인터뷰에서 샤맛 팔리하피티야(Chamath Palihapitiya)의 대답이 떠올랐습니다.

Semil Shah: 페이스북에 보낸 시간과 페이스북 플랫폼과 연결간 어떤 유사점이 있을까요? 그리고 우버가 플랫폼에서 많은 돈을 벌 수 있었을까요?

샤맛 팔리하피티야 : 둘 다 플랫폼이 아닙니다. 둘 다 우선순위를 N번째에 두는 우스꽝스러운 노력과도 비슷합니다.
저는 페이스북 플랫폼을 담당했습니다. 우린 그게 무슨 대단한 일인것처럼 의기양양했습니다.
그리고 빌 게이츠로부터 투자를 유치했을때를 기억합니다. 당시 우리는 투자 유치를 500만 달러, 83만 달러, 5억 달러, 그리고 150억 달러로 늘릴 수 있었습니다.

빌게이트로부터 150억 달러 투자 유치한 후 빌 게이츠가 하는 소리를 들었습니다.

“그건 쓰레기 같은 소리예요. 이건 플랫폼이 아닙니다. 플랫폼은 그것을 사용하는 모든 사람들의 경제적 가치가 그것을 창조하는 회사의 가치를 초과할 때입니다.그래야 플래폼이라고 부를 수 있어요.”

이러한 정의대로 윈도우즈(Windows)는 실제로 궁극적인 플랫폼이었습니다. 마이크로소프트는 윈도우즈 에코시스템 전체 가치 중 극히 일부만을 차지했다고 자랑하던 회사입니다.

그리고 이 운영 체제의 확실한 후계자는 Amazon Web Services와 Microsoft의 Azure Cloud Services입니다. 세 가지 사례 모두 견고하고 지속 가능성이 뛰어난 비즈니스를 가지고 있습니다.

플랫폼 비지니스 도면 - 써드파티가 고객을 유치
플랫폼 비지니스 도면 – 써드파티가 고객을 유치합니다.

그러나 일단 플랫폼이 빌게이츠 라인(Bill Gates Line) 아래로 빠지면, “플랫폼”을 기반으로하는 비즈니스의 장기적인 잠재력이 떨어지기 시작합니다.

예를 들어, 애플 앱스토어는 플랫폼의 모든 기능을 가지고 있지만 애플은 아이폰 수익성과 앱스토어 경제성 장악을 위해 에코시스템 전체를 확실하게 틀어쥐고 있습니다.

그로인해 앱스토어에서 강력하고 내구성있는 비즈니스가 부족한 것은 자연스런 결과입니다.

애플이 앱스토어 에코시스템을 통제하는 플랫폼 비지니스 도면
애플이 앱스토어 에코시스템을 통제하는 플랫폼 비지니스 도면

애플의 개발자 경제 통제 능력은 개발자와 고객 사이의 관계를 중개하는 데서 비롯됩니다.

이 이야기에서 빠진 것은 바로 그 모든 개발자들이 어떻게 앱스토어에서 돈을 벌었는가 하는 것입니다.

네, 의심할 여지 없이, 그것의 큰 부분은 아이폰의 폭발적인 성장과 어떻게 앱스토어가 쉽고 안전하게 앱을 설치할 수 있게 만들었는지에 있었습니다. 하지만 이것에 큰 역활은 페이스북이 했습니다.

페이스북 플랫폼

페이스북의 모바일 관련 초기 실패는 잘 알려져 있습니다. 페이스북은 초기에 웹 기반 앱에 베팅한 회사입니다. 페이스북 iOS 앱은 공개된 후에도 완전히 다시 개발되었습니다.

즉, 모바일이 폭발적으로 증가하는 시점에 모바일 앱은 제대로 작동하지 않았기 때문에 데스크톱 광고 제품과 플랫폼을 기본으로 할 수 밖에 없었습니다.

페이스북 모바일 앱 재 설계는 단순히 회사를 살리는 것 뿐만이 아니라 실제로 업계를 크게 변화시켰습니다. 이 페이스북 모바일 앱의 혁신적 기능 중 하나는 앱 설치 광고였습니다.

2012년 TechCrunch에서 다음과 같이 보도하고 있습니다.

페이스북은 앱 경제에 엄청난 베팅을 하고 있으며, 앱스토어 외부의 최고 검색 소스가 되고 싶어합니다.

페이스북 모바일 앱의 모바일 앱 설치 광고를 통해 개발자는 자신의 앱을 홍보하는 타일을 페이스북 모바일 뉴스 피드에서 구입할 수 있습니다. 이를 탭하면 사용자가 앱을 다운로드할 수 있도록 애플 앱스토어 또는 구글 플래이로 즉각 이동합니다.

페이스북 광고가 이미 잘 작동하고 있었습니다. 광고 클라이언트인 TinyCo는 다른 설치 채널에 비해 클릭율과 전환률이 50% 더 높았습니다.

페이스북 광고는 또한 더 많은 사용자들을 불러들였습니다. 광고 기술 스타트업체 Nanigans 고객은 페이스북 모바일 앱 설치 광고를 구입해 기존 기존 모바일 광고보다 8배~10배 더 많은 도달(reach)을 달성했습니다. AdParlor는 1-2%의 클릭율(click through rate)을 일관되게 유지했습니다.

페이스북의 App Install 제품은 사용자 획득에 가장 중요한 채널이 되었습니다.

특히 애플 인앱 구매 API로 수익을 창출한 게임의 경우, 페이스북 데이터가 앱 설치당 예상 가치에 대한 개발자의 정교한 이해와 결합되어 앱 스토어 매출의 폭발적 증가를 초래했습니다.

그럼에도 불구하고, 이마저도 페이스북을 의심하는 이유로 여겨졌습니다. 2015년에 저는 저명한 벤처 투자자들의 페이스북 회의론에 대해 썼습니다:

앱 설치 광고에 대한 비판의 상당 부분은 회사와 소비자 사이의 지배적인 상호 작용대신 앱을 재미있는 값싼 도구로 보는 구식 가정에 있습니다.

사용자와의 연결 시 웹 페이지나 다른 형태의 상호 작용보다 앱이 더 중요하다는 전제에서 시작한다면, 앱 설치를 위한 주요 채널이 되는 것이 훨씬 안전합니다.

물론, 페이스북 매출 중 적어도 일부는 게임용 앱 설치 광고에서 나올 것입니다. 그렇지 않나요? 물론이죠! 하지만 그마저도 세 가지 이유로 인해 비평가들이 생각하는 것보다 덜 위험합니다.

  • 벤처기업들이 돈을 헤프게 쓰는 경향이 있다고 해서 앱 설치 광고비 지출이 ‘스프레이 앤 프레이(spray-and-pray), 스프레이 뿌리듯 아무렇게나 광고를 집행하고 어느 하나 걸리기를 기도하는 것’에 불과하다고 보는 것은 실수입니다.

    사실, 앱 설치 광고는 직접 마케팅일 뿐만이 아니라 추적하기가 훨씬 쉽습니다. 특히 페이스북 앱 설치 광고는 가장 데이터 집약적인 광고 형식 중 하나입니다.
    .
  • 그렇기는 하지만, 제가 굴리(Gurley) 같은 벤처 투자가라면, 저는 모바일 게임에 대해서는 다소 조심스럽게 접근할 것입니다.

    거기에는 투자 유치 심지어는 기업 공개(IPO)를 위해서 이런 1회성 깜짝 성과를 내는 놀라운 사례들이 많이 있습니다.
    이후 그들은 초기 성공을 재현하기 위해 발버둥칠 뿐입니다. 정말 투자하기 어려운 분야라고 생각합니다.

    그러나 페이스북은 특정 게임 회사가 성공하든 실패하든 신경 쓸 필요가 없습니다. 왜냐하면 그들은 어떤 게임 회사에도 노출되지 않기 때문입니다. 그들은 산업 전반에 노출되어 있습니다.
    그리고 그 점에 대해서 다음과 같이 말씀드리겠습니다.
    .
  • 모바일 게임 분약 매출은 일시적인 성공이 아닙니다.(flash-in-the-pan은 프라이팬 속의 불꽃이라고 직역할 수 있는데, 이는 일시적인 성공이나 용두사미적인 계획이라는 의미로 사용됨)

    비디오 게임 조사 회사인 뉴저지에 따르면, 올해 전 세계 모바일 게임 매출이 콘솔 게임 매출을 초과할 것으로 예상된다고 합니다.
    흥미롭게도, 콘솔 게임 매출은 아마도 여전히 북미에서 우세할 것이므로, 미국 기반 관찰자들은 여기에서 맹점을 들어낼 것입니다.
    모바일 게임 비중은 아시아 지역에서 절대적으로 높아질 것입니다.

…결국, 거품이 생기면 페이스북을 포함한 모든 사람이 피해를 입을 것입니다. 하지만 큰 그림으로 볼 때 저는 그 회사가 실리콘밸리에서 가장 저평가된 회사라고 생각합니다.

  • 페이스북은 그들의 수익화 능력을 거의 드러내지 않았고,
  • 브랜드 광고는 아직 TV에서 이동하지 않았으며,
  • 인스타그램은 여전히 수익화되지 않았으며,
  • 페이스북 사용자는 여전히 증가하고 있습니다.

이 발췌문은 모바일 게임에 관한 것이지만, 이 분석은 페이스북에서 성장한 소비자 직접 연결하는 이커머스회사와 같은 수많은 업계에 적용됩니다.

  • 페이스북 타겟팅은 온라인으로 전환되는 회사들에게 특히 강력한 조합입니다.

    실제로 회사를 평가하면서 제가 저지른 가장 큰 실수는 브랜드 광고 잠재력을 과대평가하고 소비자 직접 대응 기회(direct response opportunity)가 얼마나 큰지를 과소평가한 것입니다.
    .
  • 이와 관련, 페이스북이 새로운 직접 대응 기반 기업( direct response-based companies)의 탄생 여건을 조성했기 때문에 직접대응 기회( direct response opportunity)가 매우 커졌습니다.

    앱의 경우 애플 및 구글(안드로이드)과 함께 이 기회를 만들었고, 이커머스의 경우 Shopify와 함께 이 기회를 만들었습니다.

    두 사례의 공통점은 페이스북 광고가 인터넷에 국한된 새로운 사업을 창출하는 데 결정적인 요소였다는 점입니다.
    .
  • 모바일 게임만이 아닙니다. 인터넷의 변혁적 영향이 이제 막 감지되기 시작했습니다.

    다시말하면 장기적으로 볼 때 전통적인 기업들은 이제라고 디지털을 채택하는 것이 기존 비지니스가 모두 쓸모없어 지는 것보다는 나을 것입니다.
    이러한 예로 제가 가장 좋아하는 회사가 바로 CPG 회사들입니다.

페이스북의 강점, Facebook’s Anti-Fragility

2016년에 쓴 ‘TV광고의 놀라운 강점과 필연적인 몰락, TV Advertising’s Surprising Strength — And Inevitable Fall‘을 인용해 보죠.

텔레비전 광고 기관은 광고주, 그들이 판매하는 상품, 그리고 그들이 사고 파는 방식과 얽혀 있습니다.

그리고 텔레비전 광고사 경영진들에게 끔찍한 사실은 텔레비전 광고들이 TV 시청 자체와 똑같이 인터넷으로 부터 위협 받고 있다는 것입니다.

CPG는 완벽한 예입니다. “house of brands”을 구축하면 P&G와 같은 회사가 규모를 활용하여 R&D에 투자하고, 제품 비용을 낮추며, 가장 중요한 유통 채널(즉, 소매 유통 진열 공간)을 장악해 인구 통계학적 그룹을 타깃으로 삼을 수 있습니다.

한편 소매업체들은 자체적으로 규모가 크기 때문에 협상 테이블에서 대규모 공급업체와 맞짱뜰 수 있을 뿐만 아니라 물류, 재고 관리, 매장 개발 등으로 확장할 수 있습니다.

반면 자동차 회사들은 CPG 회사들과 다릅니다. 그들은 생산 및 유통 규모의 혜택을 누리면서 다양한 인구 통계에 맞추기 위해 “house of brands”를 운영합니다.

가장 큰 차이점은 시간이 지남에 따라 여러 번의 작은 구매 대신 한 번의 큰 구매로 돈을 버는 것입니다.

이와 유사한 원칙이 이 목록에 있는 다른 기업에도 적용됩니다. 즉, 모든 기업은 기껏해야 무딘 타겟팅으로 가능한 한 많은 소비자에게 다가가고 있으며, 규모에 따라 혜택을 받고 있으며, 모든 기업은 소비자로부터 상당한 평생 가치를 창출할 것으로 기대하고 있습니다.

그리고, 그러한 기대에 따라 엄청난 TV 광고 비용을 부담할 수 있습니다. 실제로 미국 200대 광고주들은 전체 광고의 51%(그리고 디지털 광고의 41%)에 불과함에도 불구하고 TV 광고의 80%를 차지할 정도로 TV 광고를 매우 좋아합니다.

이는2019년 1분기 기준 페이스북 100대 광고주들이 페이스북 광고 매출의 20% 미만을 차지했던 것과 매우 다른 양상입니다. 작년에 페이스북이 번 697억 달러의 대부분은 800만 광고주의 롱테일에서 나온 것입니다.

페이스북의 완전 자동화된 광고 구매 시스템 때문에 이러한 롱테일(long-tail) 집중이 가능하므로 이는 코로나 팬데믹 동안의 경제 침체 시 엄청난 자산이 되었습니다.

페이스북은 2020년 1분기 실적 발표에서 다음과 같이 설명했습니다.

이 첫 번째 부분은 월스트리트저널 기사의 잘못된 점을 지적합니다. 단순히 브랜드 광고가 감소하는 동안 (페이스북) 직접 광고가 강력하게 유지된 것이 아니라 브랜드 광고가 감소했기 때문에 직접 반응 광고를 많이 받았다는 것입니다.

하지만, 한정된 광고를 위해 경쟁하던 광고주들 일부가 광고 구매를 중단하는 코로나 팬데믹에서 발생하는 상황을 주목해 보십시오.

모바일 게임 회사들은 광고 예산을 줄이지 않습니다. 광고 예산을 줄이면 회사를 죽이는 것이 될 것입니다! – 하지만 실제로는 더 효율적인 광고 집행을 하게 됩니다.

갑자기 앱 설치 광고 단가가 앱 설치당 0.75달러로 떨어졌습니다. 그래서 이 모바일 게임 회사는 2만달러로 26,667개의 앱 설치를 기대할 수 있습니다. 이것으로 6,667달러 예상 수익을 올렸습니다.

이는 분명히 페이스북에게는 부정적입니다. 즉, 추가적으로 6,000달러의 이윤이 페이스북의 주머니에서 빠져나간다는 것입니다. 하지만 동시에 모바일 회사들이 광고비 지출을 줄이지 않았기 때문에 손실이 상쇄됩니다.

물론, 이러한 기회가 점점 더 많은 기업들에게 돌아가면서, 결국 페이스북 이익은 재고량에 따라 결정됩니다. 이는 페이스북 플랫폼 사용량이 증가하고 있다는 점을 감안하면 정상으로 회복되고 더 나아가 더 많은 광고 매출이 발생할 수 있습니다.

이는 대형 CPG 기업들이 페이스북을 보이콧한다는 소식이 재정적인 관점에서 큰 문제가 아닌 이유입니다.

예를들어 유니레너 미국 광고 지출액 1,180만 달러는 절대적으로 없어지지 않을 페이스북 타임라인 컨텐츠에서 자동화된 효율성으로 다른 광고로 대체됩니다.

게다가, 페이스북은 광고 매출 최상위 기업들을 잃겠지만, 이들은 페이스북 광고 경매 시스템에서 가장 낮은 가격으로 수주해 왔기 때문에 전반적으로 평균 광고 단가가 올라갈 수 있습니다.

이러한 방식으로 페이스북은 구글조차 가지고 있지 못한 강점을 가지고 있습니다.

페이스북의 많은 사업들은 페이스북을 중심으로 만들어진 인터넷 네이티브 회사들의 롱테일에서 비롯됩니다. 코로나 팬데믹 사태나 현재와 같은 불매운동은 실제로는 페이스북 에코시스템을 강화시키는 역활을 합니다.

페이스북 취약점, 애플

그러나 페이스북도 취약성을 가지고 있습니다. 바로 애플입니다. AdAge 기사를 보시죠.

애플은 곧 출시될 iOS 14 소프트웨어에 대한 새로운 개인 정보 보호 변경 사항을 발표했는데, 이는 미디어 구매자와 브랜드가 소비자를 타켓팅하고 측정하고 찾는 방법을 크게 방해할 것입니다.

  • 이러한 변경으로 앱이 서로 다른 앱과 웹 사이트에서 iOS 사용자를 추적하기가 더 어려워질 것입니다.
  • 또한 어떤 마케팅 전술이 판매 또는 전환에 기여했는지 판단하기가 더 어려워질 것입니다.

월요일 애플의 WWDC(Worldwide Developers Conference)에서 발표된 변경 사항은 사용자의 모바일 장치에 고유 번호를 할당하는 애플의 IDFA(Indentifier for Advertisers)에 적용됩니다. 광고주들은 이 기능에 접근하여 광고 타겟팅, 유사 잠재 고객 구축, 고객 특성 파악 및 앱 다운로드 촉진 등에서 이 기능을 사용할 수 있습니다.

IDFA는 기본적으로 앱 업체 및 광고주와 공유되지만, iOS 14가 올 가을에 출시되면 변경될 것입니다. 변경되면 앱 게시자는 다른 앱 및 웹 사이트에서 해당 앱 정보를 추적하거나 타사와 공유할 수 있도록 팝업을 띄워서 사용자로부터 명시적 권한을 이임받아야 합니다.

페이스북은 IDFA(및 안드로이드에서 이와 같은 개념인 구글 Advertising ID)의 왕이었습니다. 이는 페이스북의 앱 설치 비즈니스의 기반이 되었습니다.

페이스북은 사용자가 게임에서 일정 금액을 소비했을 시점을 파악하여 유사한 사용자를 찾아 해당 게임에 대한 앱 설치 광고를 표시하고 그 효과를 측정할 수 있었습니다.

사실, 지난 몇 년 동안, 페이스북은 광고주들에게 단지 그들의 페이스북 광고 달성 목표를 명시해 달라고 요청해 왔습니다. 그리고 페이스북은 사용자들에게 얼마나 많은 광고를 표시할 것인지 등등 정보를 파악하는 모든 작업을 합니다. 전체 과정은 자동화되어 있습니다.

이 부분은 많이 달라질 것 같습니다. 애플은 매우 영리하게 접근하고 있습니다. 반경쟁으로 해석될 수 있는 IDFA를 죽이는 대신, 애플은 단순히 사용자들에게 추적당하고 싶은지 물어보도록 만들어, IDFA를 쓸모없게 만들고 있습니다.

지금도 미국 아이폰 사용자들 중 30%가 자신의 IDFA를 꺼버리고 사용하고 있으며, 페이스북은 이들에게는 앱 설치 광고조차 보여주지 않고 있습니다. 이제 이러한 IDFA 적용 여부는 예전의 옵트아웃(Opt-out) 대신 옵트인(Opt-in)으로 제공될 것입니다.

추가로 설명하면 이전에는 IDFA 적용이 기본이었고 사용자가 IDFA 사용하지 않겠다고 추가 옵션 설정하면 중지되는 옵트아웃 방식이었다면, 이제는 사용자가 사용하겠다고 동의하기 전에는 적용되지 않는 옵트인 방식으로 변경되는 것입니다.

그래도 저는 페이스북을 무시할 수 없습니다.

데이타 수집과 디지탈 광고 표시 측면에서 페이스북보다 우월하지 못하는 대부분 다른 디지탈 기술 광고 회사들은 훨씬 더 힘든 환경에 처할 것으로 보이며, 페이스북이 상처를 입을 정도로 디지탈 에코 시스템과 관련된 광고가 사라질 것으로 보이지 않습니다.

사실, GDPR과 마찬가지로, 안전한 방법은 역경속에서도 성과를 낼 수 있는 능력을 가진 회사입니다. 특히, 앱 설치 광고 캠페인에 대한 애플의 대안인 SKAdNetwork는 너무 제한적이어서 페이스북같이 자동화된 캠페인을 만들 수 있는 회사는 엄청난 가치가 있을 것입니다.

또한 제가 지난 달에 설명한 것처럼, 애플의 웹 쿠키 단속이 페이스북에도 도움이 되었다는 점도 주목할 필요가 있습니다.

애플의 이러한 정책은 써드파티 결제 제공업체가 원활한 서비스를 제공하는 것을 더욱 어렵게 함으로써, 페이스북이 D2C 기업에 대한 페이먼트 서비스를 제공할 수 있는 기회의 열어주고 있습니다.

페이스북 샵은 이에 대한 완벽한 예입니다.

페이스북 샵은 쇼피파이를 이용하는 판매자들에게도 좋기 때문에 성공할 것이지만, 쇼피파이가 결제 문제를 스스로 해결할 수 없도록 애플과 페이스북이 효과적으로 협력했기 때문에 페이스북이 결제 부분을 차지할 수 있었습니다.

이것이 애플-페이스북의 역동성을 매우 매력적으로 만들어 줍니다. 페이스북의 가장 큰 기회는 애플이 매번 페이스북을 반대하는 것처럼 보이는데도 불구하고 애플의 플랫폼 제안의 허점을 메우는 데서 옵니다.

애플과 페이스북의 위험 공유

특히 주목할 점은 두 회사 사이의 갈등이 그들의 가장 큰 자산을 어떻게 위협하느냐 하는 것입니다.

애플

쿠키와의 싸움과 IDFA의 효과적인 폐지는 한 가지 관점에서 사용자에게 초점을 맞추고 있지만, 서비스 수익 확대를 위한 애플의 전략 집중을 무시할 수는 없습니다.

웹을 덜 유용하게 만드는 것은 애플이 그 몫을 차지할 수 있는 앱들을 더 유용하게 만듭니다. 마찬가지로, 애플이 업계의 제품들을 무력화시키면서까지 자체적인 앱 설치 제품을 확장하고 있다는 것은 주목할 만합니다.

문제는 이러한 서비스 수익 극대화를 위한 시도가 사용자 경험 또는 애플의 수익에 부합하는지 여부입니다.

애플은 사용자 경험 확대가 수익으로 이어진다는 것을 기억해야 합니다.

페이스북

한편 페이스북은 이미 페이스북 샵 발표에서 볼 수 있듯이 최고의 파트너로부터 비즈니스를 이끌어 낼 수 있는 가능성을 보고 있습니다.

공급 업체가 자체 앱에서 장치 ID를 가져올 수 있도록하는 IDFV (공급 업체 식별자)를 여전히 사용할 수 있다는 점에서 IDFA와 비슷한 유혹을 받을 수 있을 것입니다.

페이스북은 자사의 비즈니스 모델을 다른 앱 광고 플랫폼에서 가장 인기 있는 게임과 서비스를 위한 WeChat과 같은 퍼블리싱 모델로 전환하는 것을 고려할 수 있을까요?

페이스북은 또한 주의해야 합니다. 롱테일 서비스는 애플보다 빌게이츠 타입의 플랫폼으로 만들었을 뿐만 아니라 위기를 극복할 회사의 힘의 근간이기도 합니다.

그럼에도 불구하고, 그 어느 때보다 분명해 보이는 것은 이 두 회사, 즉 애플과 페이스북이 이 산업을 주도하고 있다는 것입니다.

그들의 접근 방식이 매우 다르다는 것은 실제로는 그들이 가장 중요한 전략적 동반자가 될 수 있는지를 설명해 줍니다.

리눅스 백신 ClamAV 스캔 결과 메일로 받아보기

0

일전에 서버 및 워드프레스 보안을 위한 무료 리눅스 백신 ClamAV 이용 및 문제 해결법에 대해 포스팅 했습니다. 그 후 리눅스 서버에서 정기적으로 멀웨어가 있는지 ClamAV 스캔 후 그 결과를 관리자 메일로 보내는 방법을 고민해 봤습니다.

여기서는 리눅스 서버에서 ClamAV 스캔 후 멀웨어가 있는 경우와 없는 경우로 나우어 서버 관리자에게 메일로 알려주는 방법에 대해서 살펴보도록 하겠습니다.

우선 무료 리눅스 백신 ClamAV 사용법에 대해서는 아래 글을 참조하시기 바랍니다. ClamAV 설치 및 기본 이용 방법에 대해서는 이 글을 참조하시라고 별도로 설명하지는 않겠습니다.

ClamAV 멀웨어 스캔 결과를 메일로 보내는 방법

다행히 우분투 서버에서 ClamAV 스캔 후 메일로 보내는 방법들이 소개되어 있어 이를 기반으로 오류를 수정해 우분투 서버에 적용할 수 있었습니다.

비교적 자세히 설명된 자료는 아래를 참고하시기 바랍니다.

Configure Clamav for daily system scans and email notification on Debian

저도 이 사용법대로 사용해 봤는데 잘 안되어서 몇가지를 수정했습니다.

메일 발송 시스템

우선 저는 서버 메일 발송 시스템으로 지메일 릴레이 기능을 이용했다는 점을 밝히고 싶습니다. 메일 발송 시스템에 따라서 설정이 달라질 수 있다는 생각입니다.

이전 포스팅에서도 밝혔지만 제가 선택한 지메일 이용은 지메일에서 제공하는 릴레이 기능을 활용하므로 안전하고 스팸 메일로 분류될 가능성이 아주 적습니다. 다만 하루 500통 정도로 메일 발송횟수가 제한된다는 한계는 있습니다.

그렇기때문에 ClamAV로 스캔 후 메일 보낼 시 SMTP 메일 발송 옵션을 명기해 지메일 SMTP로 메일이 갈 수 있도록 했습니다.

아래와 같은 내용을 추가합니다.

# ClamAV 검사 및 메일 보내기
smtp_server=smtp.gmail.com:587
smtp_auth=Yes
smtp_pass=지메일 웹 비밀번호
smtp_ssl=YesCode language: PHP (php)

바이러스 데이타베이스 업데이트

스캔전에 ClamAV가 가지고 있는 바이러스 데이타베이스를 업데이트해야 하는데요.

저의 경우는 일부 에러가 나타나서 아래와 같이 강제적으로 바이러스 데이타베이스 업데이트하도록 만들었습니다.

# 바이러스 데이타베이스 업데이트
lsof /var/log/clamav/freshclam.log 
pkill -15 -x freshclam 
/etc/init.d/clamav-freshclam stop  
freshclam 
/etc/init.d/clamav-freshclam startCode language: PHP (php)

ClamAV로 바이러스 스캔 및 결과 이메일로 보내기

여기서는 ClamAV로 바이러스 감염여부를 스캔한 후 감염 파일이 있는지 아닌지에 따라 다른 내용의 메일을 보내는 방법을 설명합니다.

먼저 앞부분에서 로그파일 위치, 이메일 주소, 스캔할 폴더 등을 지정해 줍니다.

LOGFILE="/var/log/clamav/clamav-$(date +'%Y-%m-%d').log";
EMAIL_FROM="발송 이메일 주소";
EMAIL_TO="수신 이메일 주소";
DIRTOSCAN="ClamAV가 스캔할 폴더";Code language: PHP (php)

다음으로 ClamAV로 스캔 및 그 결과를 메일로 보내는 쉘 스크립터를 작성합니다. 이는 쉡 스크립터에서 사용하는 if – then – else – fi 명령을 사용합니다.

이 스크립트에서 제가 아는 범위내에서 설명을 추가했으니 참고하시기 바랍니다.

for S in ${DIRTOSCAN}; do
 DIRSIZE=$(du -sh "$S" 2>/dev/null | cut -f1);
 
 echo "Starting scan of "$S" directory.
 Directory size: "$DIRSIZE".";
 # 스캔한 폴더 용량 표시, 다른 표현 명령 Amount of data to be scanned is "$DIRSIZE".";
 
 clamscan -ri "$S" >> "$LOGFILE";
 # 감염 파일을 옮기는 경우 다음 명령 사용, clamscan -ri --remove "$S" >> "$LOGFILE";
 
 # 멀웨어 등에 감염된 라인이 있는 지 확인, get the value of "Infected lines"
 # find /var/log/clamav/ -type f -mtime +30 -exec rm {} \;
 MALWARE=$(tail "$LOGFILE"|grep Infected|cut -d" " -f3);
 
 # 멀웨어 감염 파일이 0이 아니라면, 즉 감염 파일이 있다면 멀웨어가 발견되었다는 메세지와 함께 로그 파일 첨부해 메일 발송, 
 # if the value is not equal to zero, send an email with the log file attached
 if [ "$MALWARE" -ne "0" ];
 	then
        # using heirloom-mailx below	
        echo "오늘 ClamAV로 서버를 스캐닝했습니다. 그 결과 오늘 스캔한 $DIRTOSCAN에서 멀웨어가 발견되었습니다. 자세한 내용은 첨부 로그 파일을 참조하시기 바랍니다."|mail -A "$LOGFILE" -s "멀웨어가 발견되었습니다!!" -r "$EMAIL_FROM" "$EMAIL_TO";
    else
        echo -e "오늘 ClamAV로 서버를 스캐닝했습니다. 그 결과 다행히 아무런 멀웨어가 발견되지 않았습니다. 따라서 오늘 스캔한 $DIRTOSCAN 부분은 안전하다고 할 수 있습니다. 자세한 내용은 첨부 로그 파일을 참조하시기 바랍니다."|mail -A "$LOGFILE" -s "스캔 결과 다행히 감염 파일은 없었습니다!!" -r "$EMAIL_FROM" "$EMAIL_TO";

 fi
done
 
exit 0Code language: PHP (php)

최종 자동 실행 시키기

위에서 정리한 내용을 토대로 리눅스 서버 크론탭에서 자동으로 실행되도록 만들겠습니다.

우선 실행 파일을 만듭니다. 실행 파일은 clamav.sh로 정하죠. 편집기를 열어 파일 편집 준비를 합니다.

nano clamav.shCode language: PHP (php)

이 파일에 위에서 정리한 내용을 추가합니다. 그리고 저장해야죠.

#!/bin/sh

# 바이러스 데이타베이스 업데이트
lsof /var/log/clamav/freshclam.log 
pkill -15 -x freshclam 
/etc/init.d/clamav-freshclam stop  
freshclam 
/etc/init.d/clamav-freshclam start

# ClamAV 검사 및 메일 보내기
smtp_server=smtp.gmail.com:587
smtp_auth=Yes
smtp_pass=지메일 웹 비밀번호
smtp_ssl=Yes

LOGFILE="/var/log/clamav/clamav-$(date +'%Y-%m-%d').log";
EMAIL_FROM="발송 이메일 주소";
EMAIL_TO="수신 이메일 주소";
DIRTOSCAN="ClamAV가 스캔할 폴더";
 
for S in ${DIRTOSCAN}; do
 DIRSIZE=$(du -sh "$S" 2>/dev/null | cut -f1);
 
 echo "Starting scan of "$S" directory.
 Directory size: "$DIRSIZE".";
 # 스캔한 폴더 용량 표시, 다른 표현 명령 Amount of data to be scanned is "$DIRSIZE".";
 
 clamscan -ri "$S" >> "$LOGFILE";
 # 감염 파일을 옮기는 경우 다음 명령 사용, clamscan -ri --remove "$S" >> "$LOGFILE";
 
 # 멀웨어 등에 감염된 라인이 있는 지 확인, get the value of "Infected lines"
 # find /var/log/clamav/ -type f -mtime +30 -exec rm {} \;
 MALWARE=$(tail "$LOGFILE"|grep Infected|cut -d" " -f3);
 
 # 멀웨어 감염 파일이 0이 아니라면, 즉 감염 파일이 있다면 멀웨어가 발견되었다는 메세지와 함께 로그 파일 첨부해 메일 발송, 
 # if the value is not equal to zero, send an email with the log file attached
 if [ "$MALWARE" -ne "0" ];
 	then
        # using heirloom-mailx below	
        echo "오늘 ClamAV로 서버를 스캐닝했습니다. 그 결과 오늘 스캔한 $DIRTOSCAN에서 멀웨어가 발견되었습니다. 자세한 내용은 첨부 로그 파일을 참조하시기 바랍니다."|mail -A "$LOGFILE" -s "멀웨어가 발견되었습니다!!" -r "$EMAIL_FROM" "$EMAIL_TO";
    else
        echo "오늘 ClamAV로 서버를 스캐닝했습니다. 그 결과 다행히 아무런 멀웨어가 발견되지 않았습니다. 따라서 오늘 스캔한 $DIRTOSCAN 부분은 안전하다고 할 수 있습니다. 자세한 내용은 첨부 로그 파일을 참조하시기 바랍니다."|mail -A "$LOGFILE" -s "스캔 결과 다행히 감염 파일은 없었습니다!!" -r "$EMAIL_FROM" "$EMAIL_TO";

 fi
done
 
exit 0Code language: PHP (php)

다음으로 크론탭에 이 실핼 파일을 정기적으로 작동하라고 명령합니다.

다 아시겠지만 크론탭 명령을 등록 편집하는 것은 crontab -e 옵션을 사용합니다.

crontab -eCode language: PHP (php)

크론탬 명령을 추가합니다. 저는 매일 새벽 3시 15분에 실행하도록 했습니다. 다른 명령과 겹치다보니 이 시간이 나왔네요.

15 03 * * * clamav.shCode language: PHP (php)

크론탭 명령을 추가했으면 크론을 재 실행시킵니다.

service cron startCode language: PHP (php)

실행 후 이런 메일이 날라오는군요. 다행히 멀웨어에 걸린 워드프레스 파일들은 없다고요.

무료 리눅스 백신 Clamav 실핼 시킨 후 결과 메일