본문으로 건너뛰기

"linux" 태그로 연결된 33개 게시물개의 게시물이 있습니다.

모든 태그 보기

Docker로 LEMP Stack 구축하기

· 약 2분

이 포스트 전에 웹서버 세팅을 하나씩 설치해서 띄워보는 걸 권장하고 Docker, SSH Login, LetsEncrypt, sed 명령어의 사용법을 알고 있어야 한다. 구성할 서버 스택은 다음과 같다.

  • Docker
  • Docker-compose
  • Host 에 사용될 Linux (Centos7)
  • Alpain Linux
  • Nginx ^1.13
  • MariaDB ^10.2
  • PHP ^7.1
  • Laravel =5.4
  • LetsEncrypt
  • HTTP2
  • Redis

이전 포스트를 참조하자.

Container 쇼핑

Docker Hub에서 마음에 드는 Container 를 사용해도 되지만, 생각처럼 돌아가는 Container 는 다음과 같았다.

Laradock을 안 썼죠?

  1. Laradock 에서 caddy 를 사용하지 않고 nginx 와 certbot 만을 이용해 http2 환경을 구성하는 예제가 없었다.
  2. 그래도 시도해봤으나 certbot 인증시에 DocumentRoot 를 잡지 못하는 현상을 삽질로 매꿀 시간이 없었다.
  3. Git repo 를 Clone 받아서 Docker-compose 로 Container 를 구동하기 때문에 추후 ECS 에 적용할 수가 없는 구조였다.
  4. 직접 구축해보고 싶었다.

세팅

nginx-php-fpm

Laravel 용 및 튜닝을 위해 Docker hub 의 이미지 대신 Git repo 의 이미지를 Clone 해서 세팅을 해보자.

내용 추가 중..

Centos7 Timezone 변경하기

· 약 1분
# 기존 설정 백업
$ mv /etc/localtime /etc/localtime.bak

# 타임존 연결
$ ln -s /usr/share/zoneinfo/Asia/Seoul /etc/localtime

# 백업을 안하고 바로 연결시
$ ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime

timedatectl

timedatectl 명령어를 사용해 쉽게 바꿀 수 있다.

# 한줄로 깔끔하게
$ timedatectl set-timezone Asia/Seoul

여담

시간날 때 세팅용 쉘을 만들어야겠다.

쉘 스크립트 if 조건변수

· 약 2분

쉘 스크립트의 비교 변수 몇 가지를 알아보자.

연산자기능예시
-afile_exists[ -a /etc/passwd ]
-dfile_exists && is_dir[ -d /etc ]
-ffile_exists && is_file[ -f /etc/passwd ]
-sfile_exists && not empty[ -s /etc/passwd ]
-w해당 유저로 쓰기 가능[ -w test.txt ]
-x해당 유저로 실행 가능[ -x test.sh ]
-N마지막 파일 읽은 시점부터 변경점이 있는지[ -N test.txt ]
-O해당 유저의 파일인지[ -O test.txt ]
-G해당 그룹의 파일인지[ -G test.txt ]
-ntB파일보다 A파일이 새로운지[ A_file -nt B_file ]
-otB파일보다 A파일이 오래됬는지[ A_file -ot B_file ]

숫자 비교

연산자기능예시
-ltLess than[ 0 -lt 1 ]
-leLess than or Equal[ 1 -le 1 ]
-eqEqual[ 1 -eq 1 ]
-gtGreater than[ 1 -gt 0 ]
-geGreater than or Equal[ 1 -ge 1 ]
-neNot Equal to[ 1 -ne 0 ]

Docker Error response from daemon: reference does not exist

· 약 1분

Docker rmi명령어로 이미지를 삭제하는데 Error response from daemon: reference does not exist 오류가 나면서 이미지 삭제가 안 되는 경우 다음과 같이 하면된다.

구글링하면 다시 설치하거나 cache를 비우거나 하라는데 해결되진 않았고 쉽게 접근하면 된다. 그냥 이미지 폴더를 날리자

$ sudo systemctl stop docker
$ sudo rm -rf /var/lib/docker
$ sudo systemctl start docker

Linux 폴더 구조

· 약 2분

윈도우도 Program Files 가 무슨 폴더인지 보자마자 알듯 리눅스도 폴더명이 친숙해지면 더 쉬워지지 않을까 했다. (보통 /home, /etc, /var, /tmp 정도만 왔다 갔다 하니까) 이 정도만 정리해 놓으면 CPU 정보를 볼때 왜 /proc/cpuinfo를 까야되는지 한 번에 감이 올 것 같다.

경로설명
/Root
/bin기본 명령어 프로그램 (ex. ls, cp)
/dev장치 파일
/etc시스템 설정 및 사용자 정보, 네트워킹 설정 파일
/home유저 폴더
/lib실행파일이 사용할 수 있는 공유 라이브러리 코드 파일
/proc시스템 통계
/sys장치와 시스템 인터페이스 제공
/sbin시스템 실행 파일
/tmp임시 파일
/usr리눅스 시스템 파일 (사용자 파일이 아님)
/var변수 서브디렉토리로 프로그램 런타임 정보 기록
/boot커널 부트 로더 파일
/media제거 가능한 미디어를 위한 마운트 포인트
/opt제3자 소프트웨어 파일
/usr/includeC컴파일러 헤더파일
/usr/infoGNU 정보 매뉴얼
/usr/local관리자 소프트웨어 설치 파일
/usr/man매뉴얼 페이지
/usr/share다른 유닉스 머신과 작업해야 할 파일
/vmlinuz 또는 /boot/vmlinuz리눅스 커널

여담

Linux Kernel을 이해하는 그 날까지

CentOS7 LEMP Stack 설치하기 (HTTP2, PHP7.1, Maria, Letsencrypt)

· 약 9분

Linux, Nginx, MariaDB, PHP

Why LEMP instead of LNMP? We go with LEMP due to the pronunciation for Nginx: Engine-X (en-juhn-ecks). Think of how in English, the article an is used instead of a for hour even though it begins with a consonant. The importance is the sound of the first letter rather than its written representation. Besides, LEMP is actually pronounceable and doesn’t sound like reciting the alphabet.

PHP

repo 를 등록하고 설치하는 방법이 있지만 php71 등의 이름으로 설정해야되서 번거롭다. yum 명령어의 --enablerepo 옵션을 사용해 php71 repository 를 가져오자.

# php repo를 가져오기
$ yum -y install http://rpms.famillecollet.com/enterprise/remi-release-7.rpm

$ vi /etc/yum.repos.d/remi-php71.repo

[remi-php71]
name=Remi\'s PHP 7.1 RPM repository for Enterprise Linux 7 - $basearch
#baseurl=http://rpms.remirepo.net/enterprise/7/php71/$basearch/
mirrorlist=http://rpms.remirepo.net/enterprise/7/php71/mirror
# 이 값을 1로 바꿔준다.
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-remi

$ yum -y install php php-fpm php-devel php-curl php-mcrypt php-mysql php-xmlrpc php-mbstring php-zip 등등

$ systemctl start php-fpm
$ systemctl enable php-fpm

Maria

예전 포스팅으로 대체한다. 설치방법은 똑같고 버전만 다르게 해주면 된다. 설치 후 서비스 실행만 systemctl 명령어로 해주자.

Xtrabackup

이제 mysqldump 를 좀 놓아주고 Incremental Backup 을 해주자. 이게 왜 좋은지는 공홈이나 이나 다른 블로그에 자세히 설명되어있다.

# xtrabackup 설치
$ yum -y install xtrabackup

# 증분백업을 위해 전체 백업이 한 번 필요하다.
# root가 아닌 유저일 경우 해당 DB를 백업하기 위해 PROCESS 등 여러 권한을 추가해야한다.
# (로그 메세지로 추가하라고 나온다.)
$ innobackupex --user='root' --password='암호' --databases='DB' --no-timestamp /백업위치

# 증분백업
$ innobackupex --user='root' --password='암호' --incremental --incremental-basedir='/백업위치/xtrabackup_checkpoints' --no-timestamp /증분백업위치

# 증분백업을 전체백업 위에 얹기
$ innobackupex --apply-log --redo-only --incremental-dir='/증분백업위치' /백업위치

# 증분백업 삭제
$ rm -rf /증분백업위치


# 복원
$ systemctl stop mariadb

# 데이터 폴더를 날려야한다. (만약을 대비해 백업)
$ rm -rf /var/lib/mysql/*
$ innobackupex --copy-back /백업위치

# 권한부여
$ chown -R mysql:mysql /var/lib/mysql
$ systemctl start mariadb

Nginx

HTTP2 를 적용하기 위해서는 Nginx 1.9 버전과 Openssl 1.0.2 버전 이상이 필요한데, 기본 repository 에는 이 버전이 적용되어있지 않다. 따라서 검색해보면 컴파일 설치를 해야 된다는 글이 다수다. 모든 패키지는 패키지 매니져로 관리하는게 좋다고 생각하는 나로썬 그냥 넘어갈 수 없다. Nginx 최신 repository 를 관리해주는 나이스한 곳을 찾았다.

$ yum -y install yum-utils
$ yum-config-manager --add-repo https://brouken.com/brouken.repo

# 기존 nginx repo를 사용하지 않는다는 옵션
$ yum-config-manager --save --setopt=epel.exclude=nginx*;
$ yum -y install nginx

$ systemctl start nginx
$ systemctl enable nginx

# nginx 버전 확인
$ Nginx -V
nginx version: nginx/1.13.1
built with OpenSSL 1.0.2k 26 Jan 2017

setopt 가 오류가 날 경우

ngixn.repo 를 만들어주고 연결하자.

$ vi /etc/yum.repos.d/nginx.repo

# vim /etc/yum.repos.d/nginx.repo

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/mainline/centos/7/$basearch/
gpgcheck=0
enabled=1

# 저장하고 설치 시작

$ yum update
$ yum -y install nginx
$ systemctl start nginx
$ systemctl enable nginx

LetsEncrypt

공짜 SSL 인 LetsEncrypt 의 이름이 certbot 으로 바뀌었다. 공홈을 참조해도 좋다. 인증을 받기위해 먼저 도메인을 따야한다.

$ yum -y install certbot

# 인증
$ certbot certonly --standalone -d example.com -d www.example.com

# 갱신 확인
$ certbot renew --dry-run

# 갱신하면서 nginx 재부팅
# 이 명령어를 적절히 cron에 넣어주자.
$ certbot renew --pre-hook="systemctl stop nginx" --post-hook="systemctl start nginx"

인증이 성공하면 /etc/letsencrypt/live/example.com/ 경로 아래에 키가 떨어질 것이다. 자세한 명령어 옵션은 Docs 참조.

nginx 연동

ssl 을 적용하면서 HTTP2 도 붙혀보자. HTTP2 에서는 bundling 보다 파일을 쪼개서 보내는게 더 효율적이라고 한다. (non-blocking 이니까)

# HTTP
server {
listen 80;
server_name example.com www.example.com;

# certbot --webroot 인증을 받기위한 설정
#location ^~ /.well-known/acme-challenge/ {
# default_type "text/plain";
# root /var/www/letsencrypt;
#}

# 80 접속시 443으로 redirect
location / {
return 301 https://$server_name$request_uri;
}
}

# HTTPS
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
root /var/nginx/www/public;
index index.php index.html;

# 지저분한 보안 옵션은 추천옵션이니 넣어주자.
ssl on;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;

#ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_protocols TLSv1.2;
ssl_ciphers EECDH+AESGCM:EECDH+AES;
ssl_ecdh_curve secp384r1;
ssl_prefer_server_ciphers on;

ssl_stapling on;
ssl_stapling_verify on;

location / {
try_files $uri $uri/ /index.php?$query_string;
}

location ~ \.php {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_index index.php;
fastcgi_pass 127.0.0.1:9000;
}

location ~ /\.ht {
deny all;
}

# 캐싱할 데이터가 있다면 추가
location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc|woff)$ {
expires 1M;
add_header Cache-Control "public";
}

location ~* \.(?:css|js)$ {
expires 7d;
add_header Cache-Control "public";
}
}

해당 세팅은 Laravel5.4 용이다.

nginx.conf 에는 해당 옵션들도 추가해주자.

nginx.conf
  # CPU 물리 코어에 따라 설정한다.
# 1코어에선 1로 나머지는 auto로 설정하면 된다.
# grep ^processor /proc/cpuinfo | wc -l 로 확인 가능
worker_processes 1;

events {
# 각 worker process에서 한 번에 처리할 수 있는 최대 연결 수
# ulimit -n의 값과 같게 설정하자.
worker_connections 1024;
# I/O event 노티 방식을 epoll로 사용. (poll보다 발전한 방식)
use epoll;
# worker가 한 번에 모든 연결을 수용할 수 있도록 설정
multi_accept on;
}

http {
# access_log 제거
access_log off;
server_tokens off;

# iframe 보안 이슈 DENY
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";

# PHP 서버라는 header 제거
fastcgi_hide_header X-Powered-By;
# static file 제공 최적화
sendfile on;
# TCP multiple buffer를 individual packet으로 전송하게 변경
tcp_nopush on;
# TCP에서 TCP_CORK 옵션을 활성화
# MTU에서 IP 헤더의 40-60 Byte를 뺀값과 같다는데 뭐라는건지 모르겠다.
tcp_nodelay on;
# keep alive 설정
keepalive_timeout 65;
# keepalive_requests 100000;

# gzip 압축설정
gzip on;
gzip_min_length 1000;
gzip_types application/x-javascript text/css application/javascript text/javascript text/plain text/xml application/json application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype application/x-font-ttf application/xml font/eot font/opentype font/otf image/svg+xml image/vnd.microsoft.icon;
gzip_disable "MSIE [1-6]\.";
}

적용 후에 HTTP2 확인 확장프로그램 설치 후 이 프로그램에 파란불이 들어오면 성공이다.

파일 백업

소스는 git 으로 관리가 되는데 static 파일은 주기적으로 백업이 필요하다.

file_backup.sh
NOW_DATE=`date`
BACKUP_DATE=`date +"%Y%m%d"`
FILE_DIR=백업할 폴더 경로
BACKUP_DIR=백업된 파일 경로

# gz 압축
tar zcvf ${BACKUP_DIR}/${BACKUP_DATE}.tar.gz ${FILE_DIR}

# 3일 이상된 백업파일은 제거
find ${BACKUP_DIR}/ -mtime +3 -exec rm -f {} \;
# find ${BACKUP_DIR}/ -mtime 3 -delete

여담

다음부터 Ubuntu 쓸까 생각했는데, Nginx 최신 Repo 를 찾은게 컸다. 하지만 빨리 Docker 책 읽자. Nginx, Reverse Proxy, Redis, PHP, Jenkins 를 한 번에 해결해주겠지. 이제 DockerFile 이 잘 읽히긴 하는데, 언제쯤 갈아탈 수 있으려나

Ubuntu에서 timezone 변경

· 약 2분

Ubuntu 설치시 다른 국가로 되어있는 시간대를 바꿔야한다.

$ tzselect

명령어를 실행하면 아래처럼 번호를 선택할 수 있다.

Please identify a location so that time zone rules can be set correctly.
Please select a continent, ocean, "coord", or "TZ".
1) Africa
2) Americas
3) Antarctica
4) Asia
5) Atlantic Ocean
6) Australia
7) Europe
8) Indian Ocean
9) Pacific Ocean
10) coord - I want to use geographical coordinates.
11) TZ - I want to specify the time zone using the Posix TZ format.
#? 4

4번 아시아를 선택하면 국가 선택지가 나온다.

Please select a country whose clocks agree with yours.
1) Afghanistan 18) Israel 35) Palestine
2) Armenia 19) Japan 36) Philippines
3) Azerbaijan 20) Jordan 37) Qatar
4) Bahrain 21) Kazakhstan 38) Russia
5) Bangladesh 22) Korea (North) 39) Saudi Arabia
6) Bhutan 23) Korea (South) 40) Singapore
7) Brunei 24) Kuwait 41) Sri Lanka
8) Cambodia 25) Kyrgyzstan 42) Syria
9) China 26) Laos 43) Taiwan
10) Cyprus 27) Lebanon 44) Tajikistan
11) East Timor 28) Macau 45) Thailand
12) Georgia 29) Malaysia 46) Turkmenistan
13) Hong Kong 30) Mongolia 47) United Arab Emirates
14) India 31) Myanmar (Burma) 48) Uzbekistan
15) Indonesia 32) Nepal 49) Vietnam
16) Iran 33) Oman 50) Yemen
17) Iraq 34) Pakistan
#? 23

국가를 선택 후 마지막으로 확인을 해주면

The following information has been given:

Korea (South)

Therefore TZ=\'Asia/Seoul\' will be used.
Local time is now: Tue Feb 14 23:04:10 KST 2017.
Universal Time is now: Tue Feb 14 14:04:10 UTC 2017.
Is the above information OK?
1) Yes
2) No
#? 1

...
Here is that TZ value again, this time on standard output so that you
can use the /usr/bin/tzselect command in shell scripts:
Asia/Seoul

성공적으로 반영되었다.

확인

$ date
Tue Feb 14 23:04:21 KST 2017

550 : smtp auth address is not same to envfrom address (#5.5.0)

· 약 1분

stmp 로 메일 발송시 아래와 같은 오류가 발생하는 경우가 있다.

550 : smtp auth address is not same to envfrom address (#5.5.0)
The following From address failed: [email protected] : MAIL FROM command failed, smtp auth address is not same to envfrom address (#5.5.0)

해결

smtp 인증 username 과 보내는 메일주소가 같지 않아서 발생한다. username 과 from email 을 일치시켜주면 해결된다.

Redmine Bitnami 플러그인 설치

· 약 1분

빛나미로 설치된 레드마인에 플러그인을 추가해보자

root 권한으로 접근해야한다.

$ cd /opt/redmine/apps/redmine/htdocs/plugins

플러그인 설치

$ git clone 플러그인

레드마인 쉘 접속

$ cd /opt/redmine
$ ./use_redmine

레드마인 번들 업데이트

번들은 플러그인이라고 생각하면 된다.

$ cd apps/redmine/htdocs
$ rake redmine:plugins:migrate RAILS_ENV=production

rake 명령어가 실행이 안될시

$ bundle install --without development test
$ rake redmine:plugins:migrate RAILS_ENV=production

레드마인 재시작

$ exit
$ cd /opt/redmine
$ ./ctlscript.sh restart

이제 레드마인 관리자에서 플러그인을 관리할 수 있다.

chkconfig run level 설명

· 약 2분

chkconfig 로 부팅시 자동실행 서비스를 등록할 수 있다.

$ chkconfig service on

이 명령어를 사용하면 2345 레벨이 활성화 된다. 그렇다면 레벨은 뭘까?

Run Level 은 서비스의 실행을 단계별로 구분하여 적용하는 것을 말한다.

  • 0 - halt (Do NOT set init default to this)

  • 1 - Single user mode

  • 2 - Multiuser, without NFS (The same as 3, if you do not have networking)

  • 3 - Full multiuser mode

  • 4 - unused

  • 5 - X11

  • 6 - reboot (Do NOT set init default to this)

  • 0 : 시스템 종료시

  • 1 : 싱글 유저 모드 (시스템 복원모드, 기본적으로 관리자 권한의 쉘을 얻게 된다)

  • 2 : NFS가 지원되지 않는 다중 사용자 모드 (네트워크를 사용하지 않는 텍스트 유저 모드)

  • 3 : 완전 다중 사용자 모드 (일반적인 로그인 시, CLI 환경)

  • 4 : 미지정 (사용안함, 임의로 정할 수 있음)

  • 5 : 3번과 같으나 GUI (X11) 환경

  • 6 : 재부팅

모듈 설치시에는 on 또는 345 설정이 큰 차이가 없다.