1. Update / upgrade existing packages
apt-get update && apt-get dist-upgrade
Code language: JavaScript (javascript)
2. Install nginx(libressl)+PageSpeed
apt-get install libxml2-dev libxslt1-dev libgd-dev libatomic-ops-dev libperl-dev
cd /usr/local/src
wget https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.3.1.tar.gz && tar xzvf libressl-3.3.1.tar.gz
bash <(curl -f -L -sS https://ngxpagespeed.com/install) --nginx-version latest
Code language: PHP (php)
중간에 요구하는 nginx configure 옵션은 아래와 같이 준다. 모듈 포함여부 등은 필요에 따라 수정하면 된다.
--prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --with-threads --with-file-aio --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_xslt_module=dynamic --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_v2_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_auth_request_module --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module --with-http_slice_module --with-http_stub_status_module --with-http_perl_module=dynamic --with-perl=/usr/bin/perl --with-mail=dynamic --with-mail_ssl_module --with-stream=dynamic --with-stream_ssl_module --with-stream_realip_module --with-stream_ssl_preread_module --with-pcre --with-pcre-jit --with-libatomic --with-cc-opt='-O2 -Wall -D_FORTIFY_SOURCE=2 -fstack-protector-strong -funwind-tables -fasynchronous-unwind-tables -fstack-clash-protection -Werror=return-type -flto=auto -g -fPIC -D_GNU_SOURCE' --with-ld-opt='-Wl,-z,relro,-z,now -pie' --with-compat --with-openssl=/usr/local/src/libressl-3.3.1/
Code language: JavaScript (javascript)
nginx module 디렉토리를 /etc/nginx/modules로 symlink해 준다.
sudo ln -s /usr/lib/nginx/modules /etc/nginx/modules
/lib/systemd/system/nginx.service
에 init script를 작성한다. 참조
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/usr/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
Code language: JavaScript (javascript)
가상호스트 설정파일을 넣을 디렉토리들을 생성해준다.
mkdir /etc/nginx/sites-enabled /etc/nginx/sites-available
/etc/nginx/nginx.conf를 nginx.conf.old로 이름 변경하고, nginx.conf를 아래와 같이 재작성한다.
user www-data;
worker_processes auto;
worker_rlimit_nofile 102400;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 10240;
use epoll;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
server_tokens off;
sendfile on;
keepalive_timeout 65;
client_max_body_size 100M;
client_body_buffer_size 1M;
include /etc/nginx/sites-enabled/*.conf;
}
Code language: PHP (php)
/etc/nginx/sites-available/{}.conf 아래에는 대략적으로 이러한 내용의 설정이 작성될 수 있다. 아예 http는 배제하고 https로 전부 리다이렉트 설정한 모습이다. 주석 처리한 것은 필요시 해제하여 적절하게 사용할 수 있다.
server {
include listen.conf;
server_name your.domain;
rewrite ^(.*)$ https://your.domain$request_uri;
}
server {
include listen_ssl.conf;
index index.php;
root /home/test/www;
server_name test.ghkim.net;
#access_log /var/log/nginx/your.domain.access.log main buffer=512k flush=20s;
#error_log /var/log/nginx/your.domain.error.log;
ssl_certificate /somewhere/to/fullchain.pem;
ssl_certificate_key /somewhere/to/privkey.pem;
ssl_dhparam /etc/nginx/dh.param;
include ssl.conf;
include location_default.conf;
include pagespeed.conf;
include security.conf;
include expires.conf;
#include php.conf;
}
Code language: PHP (php)
/etc/nginx/listen.conf는 아래와 같은 내용으로 저장한다.
listen 80;
listen [::]:80;
Code language: CSS (css)
/etc/nginx/listen_ssl.conf는 아래와 같은 내용으로 저장한다. 현재 http/3(QUIC)이 논의되고 있지만 아직 초안 단계로, 현재로서는 http/2만 적용하도록 한다.
listen 443 ssl http2;
listen [::]:443 ssl http2;
Code language: CSS (css)
ssl 보안 강화를 위하여 dhparam을 만들어 준다.
openssl dhparam -out /etc/nginx/dh.param 4096
/etc/nginx/ssl.conf에는 아래와 같은 내용으로 저장한다. 현재 nginx의 TLSv1.3은 openssl 1.1.1 이상을 사용한 경우에만 지원된다(Libressl은 지원하지만 nginx에서 반영해야 함, 참조).
resolver 8.8.8.8 8.8.4.4 valid=300s;
ssl_protocols TLSv1.2;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_prefer_server_ciphers on;
ssl_stapling on;
ssl_stapling_verify on;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_ecdh_curve secp384r1;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
Code language: JavaScript (javascript)
/etc/nginx/expires.conf는 아래와 같이 저장한다.
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 1M;
add_header Pragma public;
add_header Cache-Control "public, max-age=2592000";
}
Code language: PHP (php)
/etc/nginx/location_default.conf는 아래와 같이 저장한다.
location / {
try_files $uri $uri/ =404;
}
Code language: PHP (php)
/etc/nginx/pagespeed.conf에는 아래와 같은 내용으로 저장한다. 참조
pagespeed on;
# Needs to exist and be writable by nginx. Use tmpfs for best performance.
pagespeed FileCachePath /var/ngx_pagespeed_cache;
# Ensure requests for pagespeed optimized resources go to the pagespeed handler
# and no extraneous headers get set.
location ~ "\.pagespeed\.([a-z]\.)?[a-z]{2}\.[^.]{10}\.[^.]+" {
add_header "" "";
}
location ~ "^/pagespeed_static/" { }
location ~ "^/ngx_pagespeed_beacon$" { }
Code language: PHP (php)
/etc/nginx/security.conf에는 아래와 같은 내용으로 저장한다. 원본은 어디서 주워온 것인데 출처가 기억나지 않는다. modsecurity는 몇몇 이유로 이번에는 설정하지 않는다.
## Block SQL injections
set $block_sql_injections 0;
if ($query_string ~ "union.*select.*\(") {
set $block_sql_injections 1;
}
if ($query_string ~ "union.*all.*select.*") {
set $block_sql_injections 1;
}
if ($query_string ~ "concat.*\(") {
set $block_sql_injections 1;
}
if ($block_sql_injections = 1) {
return 403;
}
## Block file injections
set $block_file_injections 0;
if ($query_string ~ "[a-zA-Z0-9_]=(\.\.//?)+") {
set $block_file_injections 1;
}
if ($query_string ~ "[a-zA-Z0-9_]=/([a-z0-9_.]//?)+") {
set $block_file_injections 1;
}
if ($block_file_injections = 1) {
return 403;
}
## Block common exploits
set $block_common_exploits 0;
if ($query_string ~ "(<|%3C).*script.*(>|%3E)") {
set $block_common_exploits 1;
}
if ($query_string ~ "GLOBALS(=|\[|\%[0-9A-Z]{0,2})") {
set $block_common_exploits 1;
}
if ($query_string ~ "_REQUEST(=|\[|\%[0-9A-Z]{0,2})") {
set $block_common_exploits 1;
}
if ($query_string ~ "proc/self/environ") {
set $block_common_exploits 1;
}
if ($query_string ~ "mosConfig_[a-zA-Z_]{1,21}(=|\%3D)") {
set $block_common_exploits 1;
}
if ($query_string ~ "base64_(en|de)code\(.*\)") {
set $block_common_exploits 1;
}
if ($block_common_exploits = 1) {
return 403;
}
## Block spam
set $block_spam 0;
if ($query_string ~ "\b(ultram|unicauca|valium|viagra|vicodin|xanax|ypxaieo)\b") {
set $block_spam 1;
}
if ($query_string ~ "\b(erections|hoodia|huronriveracres|impotence|levitra|libido)\b") {
set $block_spam 1;
}
if ($query_string ~ "\b(ambien|blue\spill|cialis|cocaine|ejaculation|erectile)\b") {
set $block_spam 1;
}
if ($query_string ~ "\b(lipitor|phentermin|pro[sz]ac|sandyauer|tramadol|troyhamby)\b") {
set $block_spam 1;
}
if ($block_spam = 1) {
return 403;
}
## Block user agents
set $block_user_agents 0;
# Don't disable wget if you need it to run cron jobs!
if ($http_user_agent ~ "Wget") {
set $block_user_agents 1;
}
# Disable Akeeba Remote Control 2.5 and earlier
if ($http_user_agent ~ "Indy Library") {
set $block_user_agents 1;
}
# Common bandwidth hoggers and hacking tools.
if ($http_user_agent ~ "libwww-perl") {
set $block_user_agents 1;
}
if ($http_user_agent ~ "GetRight") {
set $block_user_agents 1;
}
if ($http_user_agent ~ "GetWeb!") {
set $block_user_agents 1;
}
if ($http_user_agent ~ "Go!Zilla") {
set $block_user_agents 1;
}
if ($http_user_agent ~ "Download Demon") {
set $block_user_agents 1;
}
if ($http_user_agent ~ "Go-Ahead-Got-It") {
set $block_user_agents 1;
}
if ($http_user_agent ~ "TurnitinBot") {
set $block_user_agents 1;
}
if ($http_user_agent ~ "GrabNet") {
set $block_user_agents 1;
}
if ($http_user_agent ~ "zgrab") {
set $block_user_agents 1;
}
if ($block_user_agents = 1) {
return 403;
}
Code language: PHP (php)
/etc/nginx/php.conf는 아래와 같이 저장한다.
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
try_files $fastcgi_script_name =404;
set $path_info $fastcgi_path_info;
fastcgi_param PATH_INFO $path_info;
fastcgi_index index.php;
include fastcgi.conf;
fastcgi_pass unix:/var/run/php/php8.0-fpm.sock;
fastcgi_buffer_size 128k;
fastcgi_buffers 256 16k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
fastcgi_send_timeout 240;
fastcgi_read_timeout 240;
fastcgi_intercept_errors on;
}
Code language: PHP (php)
nginx service를 부팅시 자동 시작하도록 등록하고, 필요시 실행한다(다만, 4번의 Let’s encrypt까지 작업을 모두 완료해야 실행될 것임)
systemctl enable nginx.service
systemctl start nginx.service
Code language: CSS (css)
3. Install PHP8-FPM
추가 설치한 각종 라이브러리는 필요에 따라 조정하여 사용한다.
sudo add-apt-repository ppa:ondrej/php
sudo apt-get install php8.0-fpm php8.0-gd php8.0-curl php8.0-mbstring php8.0-apcu php8.0-intl php8.0-zip php8.0-mysql php8.0-xml php8.0-imagick
Code language: JavaScript (javascript)
아래의 php.ini 설정을 변경한다.
upload_max_filesize = 100M
allow_url_fopen = Off
post_max_size = 100M
/etc/php/8.0/fpm/conf.d/10-opcache.ini에서 필요에 따라 아래 구문을 추가한다. 1235, 1254, 1255 중 가능한 것을 사용한다. 메모리 문제로 대형 어플리케이션의 경우 설정을 낮춰야 한다. 자세한 설명은 참조. 기본은 tracing(1254)이다.
opcache.jit=1255
opcache.jit_buffer_size=100M
이후 php8.0-fpm을 실행하고 부팅시 자동 시작하도록 등록한다.
sudo systemctl start php8.0-fpm
sudo systemctl enable php8.0-fpm
Code language: CSS (css)
4. Install Let’s Encrypt
sudo snap install core; sudo snap refresh core
sudo apt-get remove certbot
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo certbot certonly --nginx
Code language: JavaScript (javascript)
이후 적절한 정보를 입력하고 인증서를 받는다. 이후 nginx 설정을 변경하여 ssl 인증서 위치를 정확히 기입해 준다. 그다음 automatic renewal이 잘 되는지 테스트해 보자.
sudo certbot renew --dry-run
5. Install MariaDB 10.5
현재 Ubuntu 20.04 LTS의 기본 제공 패키지는 10.3버전으로, 10.5 버전을 이용하려면 아래와 같이 하면 된다.
sudo apt-key adv --fetch-keys 'https://mariadb.org/mariadb_release_signing_key.asc'
sudo add-apt-repository 'deb [arch=amd64,arm64,ppc64el] https://ftp.harukasan.org/mariadb/repo/10.5/ubuntu focal main'
sudo apt update
sudo apt install mariadb-server mariadb-client
sudo mysql_secure_installation
Code language: JavaScript (javascript)
Leave a Reply