ArchLinux:Nginx: Difference between revisions
m (→NGINX) |
(→NGINX) |
||
(28 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
{{DISPLAYTITLE:{{TitleIcon|arch=true}} NGINX + PHP}}<metadesc> | {{DISPLAYTITLE:{{TitleIcon|arch=true}} NGINX + PHP}}<metadesc>Setting up a full web stack on Arch Linux.</metadesc> | ||
<div id="tocalign">__TOC__</div> | <div id="tocalign">__TOC__</div> | ||
{{Back|Arch Linux}} | {{Back|Arch Linux}} | ||
= {{Icon24|sitemap}} Introduction = | = {{Icon24|sitemap}} Introduction = | ||
= {{Icon24|sitemap}} | = {{Icon24|sitemap}} Install = | ||
Beforehand be sure to determine weather the web server will be using MySQL (ie. MariaDB) or PostgreSQL. | Beforehand be sure to determine weather the web server will be using MySQL (ie. MariaDB) or PostgreSQL. | ||
Line 10: | Line 10: | ||
{{Console|1=pikaur -S apache-tools composer curl minify nginx php-fpm sassc wget}} | {{Console|1=pikaur -S apache-tools composer curl minify nginx php-fpm sassc wget}} | ||
Install all of the required PHP extensions. | Install all of the required PHP extensions. | ||
{{Console|1=pikaur -S php-gd php-geoip php- | {{Console|1=pikaur -S php-gd php-geoip php-imagick php-intl php-memcache php-odbc php-sqlite php-sodium xdebug}} | ||
Next create the environment for the web server. | Next create the environment for the web server. | ||
{{Console|1=sudo mkdir -p /nginx/conf.d /nginx/https /nginx/logs /nginx/sql /nginx/ssl /nginx/vhosts.d}} | {{Console|1=sudo mkdir -p /nginx/conf.d /nginx/https /nginx/logs /nginx/sql /nginx/ssl /nginx/vhosts.d}} | ||
{{margin}} | |||
{{Console|1=sudo chown -R http:http /nginx}} | |||
{{margin}} | {{margin}} | ||
{{Console|1=sudo chmod -R 770 /nginx}} | {{Console|1=sudo chmod -R 770 /nginx}} | ||
Line 19: | Line 21: | ||
{{margin}} | {{margin}} | ||
{{Console|1=sudo gpasswd -a {{cyanBold|username}} http}} | {{Console|1=sudo gpasswd -a {{cyanBold|username}} http}} | ||
Set the default shell for {{mono|http}} to Bash. | |||
{{Console|1=sudo chsh -s /bin/bash http}} | |||
== {{Icon|notebook}} PostgreSQL == | == {{Icon|notebook}} PostgreSQL == | ||
Using {{mono|postgresql}} as a back-end will require the following setup and configuration. | Using {{mono|postgresql}} as a back-end will require the following setup and configuration. | ||
{{Console|1=pikaur -S postgresql}} | {{Console|1=pikaur -S postgresql php-pgsql}} | ||
{{margin}} | {{margin}} | ||
{{Console|1=sudo chown postgres:postgres /nginx/sql}} | {{Console|1=sudo chown postgres:postgres /nginx/sql}} | ||
Line 42: | Line 46: | ||
Create a new postgres user account. | Create a new postgres user account. | ||
{{Console|1=createuser -P --interactive<br/>Enter name of role to add: {{cyanBold|username}}<br/>Enter password for new role: {{cyanBold|********}}<br/>Enter it again: {{cyanBold|********}}<br/>Shall the new role be a superuser? (y/n) {{cyanBold|n}}<br/>Shall the new role be allowed to create databases? (y/n) {{cyanBold|y}}<br/>Shall the new role be allowed to create more new roles? (y/n) {{cyanBold|n}}}} | {{Console|1=createuser -P --interactive<br/>Enter name of role to add: {{cyanBold|username}}<br/>Enter password for new role: {{cyanBold|********}}<br/>Enter it again: {{cyanBold|********}}<br/>Shall the new role be a superuser? (y/n) {{cyanBold|n}}<br/>Shall the new role be allowed to create databases? (y/n) {{cyanBold|y}}<br/>Shall the new role be allowed to create more new roles? (y/n) {{cyanBold|n}}}} | ||
== {{Icon|notebook}} MariaDB == | == {{Icon|notebook}} MariaDB == | ||
Using {{mono|mariadb}} as a back-end will require the following setup and configuration. | Using {{mono|mariadb}} as a back-end will require the following setup and configuration. | ||
Line 61: | Line 64: | ||
{{Console|1=sudo mysql_secure_installation}} | {{Console|1=sudo mysql_secure_installation}} | ||
{{Note|1=The default mysql root password is none}} | {{Note|1=The default mysql root password is none}} | ||
Connect to mysql using the root account and the password you previously set. | |||
{{Console|1=sudo mysql -u root -p | {{Console|1=sudo mysql -u root -p}} | ||
Add a new mysql user account. | |||
{{Console|1=MariaDB [(none)]> GRANT ALL PRIVILEGES ON *.* TO '{{cyanBold|kyau}}'@'localhost' {{greenBold|\}}<br/>  IDENTIFIED BY '{{cyanBold|user_password}}' WITH GRANT OPTION;}} | |||
= {{Icon24|sitemap}} Configuration = | |||
== {{Icon|notebook}} PHP == | |||
First remove the default pool. | |||
{{Console|1=sudo rm /etc/php/php-fpm.d/www.conf}} | |||
Create the defaults for all pools. | |||
{{Console|1=sudoedit /etc/php/php-fpm.d/defaults.inc}} | |||
{{margin}} | |||
{{Console|title=/etc/php/php-fpm.d/defaults.inc|prompt=false|1=user {{=}} http<br/>group {{=}} http<br/>listen {{=}} /run/php-fpm/php-fpm-$pool.sock<br/>listen.owner {{=}} http<br/>listen.group {{=}} http<br/>{{blackBold|; process configuration}}<br/>pm {{=}} dynamic<br/>pm.max_children {{=}} 5<br/>pm.start_servers {{=}} 2<br/>pm.min_spare_servers {{=}} 1<br/>pm.max_spare_servers {{=}} 3<br/>{{blackBold|; php.ini changes}}<br/>php_admin_flag[expose_php] {{=}} off<br/>php_admin_flag[log_errors] {{=}} on<br/>php_admin_flag[short_open_tag] {{=}} on<br/>php_admin_value[date.timezone] {{=}} America/Los_Angeles<br/>php_admin_value[error_log] {{=}} /nginx/logs/$pool/php.log<br/>php_admin_value[memory_limit] {{=}} 256M<br/>php_admin_value[post_max_size] {{=}} 2048M<br/>php_admin_value[session.save_path] {{=}} /tmp<br/>php_admin_value[upload_max_filesize] {{=}} 2048M}} | |||
Enable all third party PHP extensions that were installed. | |||
{{Console|1=sudo find . -type f -name '*.ini' -exec sed -i -e 's/^;extension/extension/g' {{greenBold|\}}<br/>  -e 's/^;zend_extension/zend_extension/g' -e 's/^;xdebug/xdebug/g' {} +}} | |||
Enable global PHP extensions. | |||
{{Console|1=sudoedit /etc/php/conf.d/defaults.ini}} | |||
{{margin}} | |||
{{Console|title=/etc/php/conf.d/defaults.ini|prompt=false|1=extension{{=}}bz2<br/>extension{{=}}exif<br/>extension{{=}}gd<br/>extension{{=}}gettext<br/>extension{{=}}gmp<br/>extension{{=}}iconv<br/>extension{{=}}intl<br/>extension{{=}}sodium<br/>extension{{=}}mysqli<br/>extension{{=}}odbc<br/>extension{{=}}pdo_mysql<br/>extension{{=}}pdo_odbc<br/>extension{{=}}pdo_sqlite<br/>extension{{=}}sockets<br/>extension{{=}}sqlite3<br/>{{blackBold|; opcache}}<br/>zend_extension{{=}}opcache<br/>opcache.enable {{=}} 1<br/>opcache.interned_strings_buffer {{=}} 8<br/>opcache.max_accelerated_files {{=}} 10000<br/>opcache.memory_consumption {{=}} 128<br/>opcache.save_comments {{=}} 1<br/>opcache.revalidate_freq {{=}} 1}} | |||
Create a php-fpm pool for the domain being setup (use a different pool for each site/domain). | |||
{{Console|1=sudoedit /etc/php/php-fpm.d/domain_com.conf}} | |||
{{margin}} | |||
{{Console|title=/etc/php/php-fpm.d/domain_com.conf|prompt=false|1={{blackBold|; $KYAULabs: domain_com.conf,v 1.0.0 2021/05/01 12:36:14 kyau Exp $}}<br/><br/>[domain_com]<br/>include {{=}} /etc/php/php-fpm.d/defaults.inc<br/>env[HOSTNAME] {{=}} domain.com<br/>env[PATH] {{=}} /usr/local/bin:/usr/bin:/bin<br/>env[TMP] {{=}} /tmp<br/>env[TMPDIR] {{=}} /tmp<br/>env[TEMP] {{=}} /tmp<br/><br/>{{blackBold|; vim: ft{{=}}dosini sts{{=}}4 sw{{=}}4 ts{{=}}4 noet :}}}} | |||
{{margin}} | |||
{{Note|1=One can temporarily disable sites/domains by renaming the config to {{mono|.conf.disable}} and reloading the php-fpm service}} | |||
Be sure to set the file permissions properly. | |||
{{Console|1=sudo chmod 644 /etc/php/conf.d/defaults.ini /etc/php/php-fpm.d/*}} | |||
Start and enable the {{mono|php-fpm}} service. | |||
{{Console|1=sudo systemctl enable --now php-fpm.service}} | |||
== {{Icon|notebook}} NGINX == | |||
Create a blank configuration file. | |||
{{Console|1=sudo install -g http -m 660 -o http /dev/null /nginx/conf.d/nginx.conf}} | |||
Copy the MIME types file. | |||
{{Console|1=sudo install -g http -m 660 -o http /etc/nginx/mime.types /nginx/conf.d/mime.types}} | |||
Remove the default config in {{mono|nginx.conf}} and replace it with an include (to the new config location). | |||
{{Console|1=sudoedit /etc/nginx/nginx.conf}} | |||
{{margin}} | |||
{{Console|title=/etc/nginx/nginx.conf|prompt=false|1=include /nginx/conf.d/nginx.conf;}} | |||
Create the nginx config file. | |||
{{Console|1=sudoedit /nginx/conf.d/nginx.conf}} | |||
{{margin}} | |||
{{Console|title=/nginx/conf.d/nginx.conf|prompt=false|1={{blackBold|# $KYAULabs: nginx.conf,v 1.1.7 2021/05/03 18:14:27 kyau Exp $}}<br/><br/>{{blackBold|# Help / Additional Info {{{}}<br/>{{blackBold|# always test configuration before reload!}}<br/>{{blackBold|# $ sudo nginx -t}}<br/>{{blackBold|# reload the configuration by using reload not restart!}}<br/>{{blackBold|# $ sudo systemctl reload nginx}}<br/>{{blackBold|# <nowiki>https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/</nowiki>}}<br/>{{blackBold|# }}}}}<br/><br/>{{blackBold|# enables the use of “just-in-time compilation” for the regular expressions}}<br/>{{blackBold|# known by the time of configuration parsing}}<br/>pcre_jit on;<br/>{{blackBold|# user and group credentials used by worker processes}}<br/>user http http;<br/>{{blackBold|# number of worker processes (auto will autodetect number of CPU cores)}}<br/>worker_processes auto;<br/>{{blackBold|# binds worker processes automatically to available CPUs}}<br/>worker_cpu_affinity auto;<br/>{{blackBold|# number of file descriptors used for nginx}}<br/>worker_rlimit_nofile 65535;<br/><br/>events {<br/> {{blackBold|# worker process will accept one/all (off/on) connection(s) at a time}}<br/> multi_accept on;<br/> {{blackBold|# maximum number of simultaneous connections that can be opened by a worker}}<br/> worker_connections 4096;<br/>}<br/><br/>http {<br/> {{blackBold|# mime types}}<br/> include /nginx/conf.d/mime.types;<br/> {{blackBold|# to boost I/O on HDD we can disable access logs}}<br/> access_log off;<br/> {{blackBold|# read and send using multi-threading, without blocking a worker process}}<br/> aio threads;<br/> {{blackBold|# hide index pages}}<br/> autoindex off;<br/> {{blackBold|# add to 'Content-Type' response header}}<br/> charset utf-8;<br/> {{blackBold|# request timed out -- default 60}}<br/> client_body_timeout 10;<br/> {{blackBold|# sets the maximum allowed size of the client request body -- default 1}}<br/> client_max_body_size 16m;<br/> {{blackBold|# default mime type}}<br/> default_type text/plain;<br/> {{blackBold|# enable gzipping of responses}}<br/> gzip on;<br/> {{blackBold|# disables gzipping of responses for msie6 and below}}<br/> gzip_disable "msie6";<br/> {{blackBold|# minimum length of a response that will be gzipped -- default 20}}<br/> gzip_min_length 1024;<br/> {{blackBold|# gzip compression level -- default 1}}<br/> gzip_comp_level 6;<br/> gzip_vary on;<br/> gzip_proxied expired no-cache no-store private auth;<br/> {{blackBold|# text/html is always compressed}}<br/> gzip_types<br/> text/css<br/> text/javascript<br/> text/xml<br/> text/x-component<br/> application/javascript<br/> application/x-javascript<br/> application/json<br/> application/xml<br/> application/rss+xml<br/> application/atom+xml<br/> font/truetype<br/> font/opentype<br/> application/vnd.ms-fontobject<br/> image/svg+xml;<br/> {{blackBold|# files that will be used as an index, checked in the specified order}}<br/> index index.php index.html index.htm index.txt;<br/> {{blackBold|# enables keep-alive connections with all browsers}}<br/> keepalive_disable none;<br/> {{blackBold|# keep-alive client connections stay active for -- default 75}}<br/> keepalive_timeout 30s;<br/> {{blackBold|# specifies log format}}<br/> log_format main<br/> '$remote_addr - $remote_user [$time_local] '<br/> '"$request" $status $body_bytes_sent '<br/> '"$http_referer" "$http_user_agent"';<br/> {{blackBold|# disables logging of errors about not found files into error_log}}<br/> log_not_found off;<br/> {{blackBold|# cache open file descriptors, directories and file lookup errors}}<br/> open_file_cache max=10240 inactive=20s;<br/> open_file_cache_valid 30s;<br/> open_file_cache_min_uses 2;<br/> open_file_cache_errors on;<br/> {{blackBold|# allow the server to close connection on non responding client, this will}}<br/> {{blackBold|# free up memory}}<br/> reset_timedout_connection on;<br/> {{blackBold|# if client stops responding, free up memory -- default 60}}<br/> send_timeout 8;<br/> {{blackBold|# copies data between one FD and other from within the kernel faster than}}<br/> {{blackBold|# read() + write()}}<br/> sendfile on;<br/> {{blackBold|# bucket size for the server names hash tables}}<br/> server_names_hash_bucket_size 128;<br/> {{blackBold|# disables emitting nginx version on error pages and in the "server"}}<br/> {{blackBold|# response header field}}<br/> server_tokens off;<br/> {{blackBold|# send headers in one piece, it is better than sending them one by one}}<br/> tcp_nopush on;<br/> {{blackBold|# don't buffer data sent, good for small data bursts in real time}}<br/> tcp_nodelay on;<br/> {{blackBold|# hash table maximum size -- default 1024}}<br/> types_hash_max_size 4096;<br/><br/> {{blackBold|# include domain configuration files}}<br/> include /nginx/vhosts.d/*.conf;<br/><br/> {{blackBold|# redirect all non-encrypted (http) traffic to encrypted (https)}}<br/> server {<br/> server_name _;<br/> listen *:80 default_server;<br/> listen [::]:80 default_server;<br/> return 301 <nowiki>https://$host$request_uri;</nowiki><br/> }<br/>}<br/><br/>{{blackBold|# vim: ft{{=}}nginx sts{{=}}4 sw{{=}}4 ts{{=}}4 noet :}}}} | |||
Create a vhost defaults config. | |||
{{Console|1=sudoedit /nginx/conf.d/vhost_defaults}} | |||
{{margin}} | |||
{{Console|title=/nginx/conf.d/vhost_defaults|prompt=false|1={{blackBold|# $KYAULabs: vhost.defaults,v 1.0.7 2021/05/16 12:48:55 kyau Exp $}}<br/><br/>{{blackBold|## SSL/TLS (<nowiki>https://cipherlist.dev/</nowiki>)}}<br/>ssl_dhparam /nginx/ssl/dhparam4096.pem; {{blackBold|# openssl dhparam -out dhparam4096.pem 4096}}<br/>ssl_protocols TLSv1.3; {{blackBold|# Requires nginx >{{=}} 1.13.0}}<br/>ssl_ciphers EECDH+CHACHA20:EECDH+AES;<br/>ssl_ecdh_curve X25519; {{blackBold|# Requires nginx >{{=}} 1.1.0}}<br/>ssl_session_cache shared:SSL:10m;<br/>ssl_session_tickets off; {{blackBold|# Requires nginx >{{=}} 1.5.9}}<br/>ssl_session_timeout 10m;<br/>ssl_stapling on; {{blackBold|# Requires nginx >{{=}} 1.3.7}}<br/>ssl_stapling_verify on; {{blackBold|# Requires nginx >{{=}} 1.3.7}}<br/>ssl_prefer_server_ciphers on;<br/>resolver 1.1.1.1 1.0.0.1 [2606:4700:4700::1111] [2606:4700:4700::1001] valid=60s; {{blackBold|# Change if you run your own DNS servers}}<br/>resolver_timeout 2s;<br/><br/>{{blackBold|# security settings}}<br/>add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;<br/>add_header X-Frame-Options DENY;<br/>add_header X-Content-Type-Options nosniff;<br/>add_header X-XSS-Protection "1; mode=block";<br/><br/>{{blackBold|# vim: ft{{=}}nginx sts{{=}}4 sw{{=}}4 ts{{=}}4 noet :}}}} | |||
Create a URI defaults config. | |||
{{Console|1=sudoedit /nginx/conf.d/uri_defaults}} | |||
{{Console|title=/nginx/conf.d/uri_defaults|prompt=false|1={{blackBold|# $KYAULabs: uri_defaults,v 1.0.2 2021/05/05 17:55:10 kyau Exp $}}<br/><br/>{{blackBold|# remove `robots.txt` and all favicons from the logs}}<br/>location ~* "^/(favicon\.\S{3,5}{{!}}robots\.txt)$" {<br/> access_log off;<br/> allow all;<br/> log_not_found off;<br/>}<br/><br/>{{blackBold|# disable dot (hidden) files while allowing `.well-known`}}<br/>location ~* /\.(?!well-known).* {<br/> access_log off;<br/> deny all;<br/> log_not_found off;<br/>}<br/><br/>{{blackBold|# deny access to any sensitive material}}<br/>location ~* (?:#.*#{{!}}\.(?:bak{{!}}conf{{!}}dist{{!}}fla{{!}}in[ci]{{!}}log{{!}}orig{{!}}phps{{!}}psd{{!}}sass{{!}}scss{{!}}sh{{!}}sql{{!}}sw[op]){{!}}~)$ {<br/> access_log on;<br/> deny all;<br/> log_not_found on;<br/>}<br/><br/>{{blackBold|# asset/media cache}}<br/>location ~* \.(?:css(\.map)?{{!}}js(\.map)?{{!}}jpe?g{{!}}png{{!}}gif{{!}}ico{{!}}cur{{!}}heic{{!}}webp{{!}}tiff?{{!}}mp3{{!}}m4a{{!}}aac{{!}}ogg{{!}}midi?{{!}}wav{{!}}mp4{{!}}mov{{!}}webm{{!}}mpe?g{{!}}avi{{!}}ogv{{!}}flv{{!}}wmv)$ {<br/> access_log off;<br/> expires 7d;<br/>}<br/><br/>{{blackBold|# fonts/svg cache and access}}<br/>location ~* \.(?:svgz?{{!}}ttf{{!}}ttc{{!}}otf{{!}}eot{{!}}woff2?)$ {<br/> access_log off;<br/> add_header Access-Control-Allow-Origin "*";<br/> expires 7d;<br/>}<br/><br/>{{blackBold|# html processing}}<br/>location ~* \.html$ {<br/> try_files $uri $uri/ /index.html {{=}}404;<br/>}<br/><br/>{{blackBold|# http error pages}}<br/>error_page 404 /404;<br/>error_page 500 502 503 504 /50x;<br/>location = /404 {<br/> root /nginx/https/error;<br/> index 404.php;<br/>}<br/>location = /50x {<br/> root /nginx/https/error;<br/> index 50x.php;<br/>}<br/><br/>{{blackBold|# vim: ft{{=}}nginx sts{{=}}4 sw{{=}}4 ts{{=}}4 noet :}}}} | |||
=== FastCGI === | |||
Create a {{mono|fastcgi_params}} config file (PHP environmental variable defaults). | |||
{{Console|1=sudoedit /nginx/conf.d/fastcgi_params}} | |||
{{margin}} | |||
{{Console|title=/nginx/conf.d/fastcgi_params|prompt=false|1={{blackBold|# $KYAULabs: fastcgi_params,v 1.0.5 2021/05/03 17:31:37 kyau Exp $}}<br/><br/>fastcgi_param QUERY_STRING $query_string;<br/>fastcgi_param REQUEST_METHOD $request_method;<br/>fastcgi_param CONTENT_TYPE $content_type;<br/>fastcgi_param CONTENT_LENGTH $content_length;<br/><br/>fastcgi_param SCRIPT_FILENAME $request_filename;<br/>fastcgi_param SCRIPT_NAME $fastcgi_script_name;<br/>fastcgi_param REQUEST_URI $request_uri;<br/>fastcgi_param DOCUMENT_URI $document_uri;<br/>fastcgi_param DOCUMENT_ROOT $document_root;<br/>fastcgi_param SERVER_PROTOCOL $server_protocol;<br/>fastcgi_param REQUEST_SCHEME $scheme;<br/>fastcgi_param HTTPS $https if_not_empty;<br/><br/>fastcgi_param GATEWAY_INTERFACE CGI/1.1;<br/>{{blackBold|#fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;}}<br/>fastcgi_param SERVER_SOFTWARE nginx;<br/><br/>fastcgi_param REMOTE_ADDR $remote_addr;<br/>fastcgi_param REMOTE_PORT $remote_port;<br/>fastcgi_param SERVER_ADDR $server_addr;<br/>fastcgi_param SERVER_PORT $server_port;<br/>fastcgi_param SERVER_NAME $server_name;<br/><br/>{{blackBold|# PHP only, required if PHP was built with --enable-force-cgi-redirect}}<br/>fastcgi_param REDIRECT_STATUS 200;<br/><br/>{{blackBold|# Mitigate <nowiki>https://httpoxy.org/</nowiki> vulnerabilities}}<br/>fastcgi_param HTTP_PROXY "";<br/><br/>{{blackBold|# vim: ft{{=}}nginx sts{{=}}4 sw{{=}}4 ts{{=}}4 noet :}}}} | |||
=== SSL/TLS === | |||
Create the {{mono|dhparam}} as indicated above. | |||
{{Console|1=sudo -u http openssl dhparam -out /nginx/ssl/dhparam4096.pem 4096}} | |||
Set permissions properly. | |||
{{Console|1=sudo chmod 660 /nginx/ssl/dhparam4096.pem}} | |||
=== Virtual Hosts === | |||
Virtual Hosts are created in domain config files keeping all subdomains in a single file. The following template can be used, simply replace {{mono|domain_com}} and {{mono|domain.com}} with the actual domain name. | |||
{{Console|1=sudoedit /nginx/vhosts.d/{{cyanBold|domain_com}}.conf}} | |||
{{margin}} | |||
{{Console|title=/nginx/vhosts.d/domain_com.conf|prompt=false|1={{blackBold|# $KYAULabs: domain_com.conf,v 1.1.5 2021/05/05 18:06:34 kyau Exp $}}<br/><br/>{{blackBold|## Redirect all WWW to Non-WWW (SSL)}}<br/>server {<br/> listen *:443 ssl http2;<br/> listen [::]:443 ssl http2;<br/> server_name www.{{cyanBold|domain.com}};<br/><br/> #access_log /nginx/logs/{{cyanBold|domain_com}}/www-access.log;<br/> error_log /nginx/logs/{{cyanBold|domain_com}}/www-error.log;<br/><br/> ssl_certificate /etc/letsencrypt/live/{{cyanBold|domain.com}}/fullchain.pem;<br/> ssl_certificate_key /etc/letsencrypt/live/{{cyanBold|domain.com}}/privkey.pem;<br/> ssl_trusted_certificate /etc/letsencrypt/live/{{cyanBold|domain.com}}/chain.pem;<br/><br/> include /nginx/conf.d/vhost_defaults;<br/><br/> return 301 <nowiki>https://domain.com$request_uri</nowiki>;<br/>}<br/><br/>{{blackBold|## domain.com}}<br/>server {<br/> listen *:443 ssl http2;<br/> listen [::]:443 ssl http2;<br/> server_name {{cyanBold|domain.com}};<br/><br/> #access_log /nginx/logs/{{cyanBold|domain_com}}/domain_com-access.log;<br/> error_log /nginx/logs/{{cyanBold|domain_com}}/domain_com-error.log;<br/><br/> ssl_certificate /etc/letsencrypt/live/{{cyanBold|domain.com}}/fullchain.pem;<br/> ssl_certificate_key /etc/letsencrypt/live/{{cyanBold|domain.com}}/privkey.pem;<br/> ssl_trusted_certificate /etc/letsencrypt/live/{{cyanBold|domain.com}}/chain.pem;<br/><br/> include /nginx/conf.d/vhost_defaults;<br/><br/> root /nginx/https/{{cyanBold|domain_com}}/www;<br/><br/> location / {<br/> try_files $uri $uri/ @rewrite;<br/> }<br/><br/> location @rewrite {<br/> {{blackBold|#rewrite ^/directory/$ /script.php?x{{=}}directory last;}}<br/> }<br/><br/> {{blackBold|#location ^~ /app/ {<br/> #proxy_pass <nowiki>http://127.0.0.1:8080/</nowiki>;<br/> #proxy_http_version 1.1;<br/> #proxy_set_header Connection "upgrade";<br/> #proxy_set_header Upgrade $http_upgrade;<br/> #proxy_set_header X-Forwarded-For $remote_addr;<br/> #proxy_set_header X-Forwarded-Proto $scheme;<br/> # by defaults nginx times out connections in one minute<br/> #proxy_read_timeout 1d;<br/> #}}}<br/><br/> include /nginx/conf.d/uri_defaults;<br/><br/> {{blackBold|# php scripts}}<br/> location ~* [^/]\.php(/{{!}}$) {<br/> try_files $fastcgi_script_name =404;<br/> include /nginx/conf.d/fastcgi_params;<br/> fastcgi_buffers 8 16k;<br/> fastcgi_buffer_size 32k;<br/> fastcgi_index index.php;<br/> fastcgi_split_path_info ^(.+?\.php)(/.*)$;<br/> fastcgi_pass unix:/run/php-fpm/php-fpm-domain_com.sock;<br/> }<br/>}<br/><br/>{{blackBold|## api.domain.com}}<br/>server {<br/> listen *:443 ssl http2;<br/> listen [::]:443 ssl http2;<br/> server_name api.{{cyanBold|domain.com}};<br/><br/> #access_log /nginx/logs/{{cyanBold|domain_com}}/api-access.log;<br/> error_log /nginx/logs/{{cyanBold|domain_com}}/api-error.log;<br/><br/> ssl_certificate /etc/letsencrypt/live/{{cyanBold|domain.com}}/fullchain.pem;<br/> ssl_certificate_key /etc/letsencrypt/live/{{cyanBold|domain.com}}/privkey.pem;<br/> ssl_trusted_certificate /etc/letsencrypt/live/{{cyanBold|domain.com}}/chain.pem;<br/><br/> include /nginx/conf.d/vhost_defaults;<br/><br/> root /nginx/https/{{cyanBold|domain_com}}/api;<br/><br/> location / {<br/> try_files $uri $uri/ @rewrite;<br/> }<br/><br/> location @rewrite {<br/> {{blackBold|#rewrite ^/directory/$ /script.php?x{{=}}directory last;}}<br/> }<br/><br/> include /nginx/conf.d/uri_defaults;<br/><br/> {{blackBold|# php scripts}}<br/> location ~* [^/]\.php(/{{!}}$) {<br/> try_files $fastcgi_script_name =404;<br/> include /nginx/conf.d/fastcgi_params;<br/> fastcgi_buffers 8 16k;<br/> fastcgi_buffer_size 32k;<br/> fastcgi_index index.php;<br/> fastcgi_split_path_info ^(.+?\.php)(/.*)$;<br/> fastcgi_pass unix:/run/php-fpm/php-fpm-domain_com.sock;<br/> }<br/>}<br/><br/>{{blackBold|# vim: ft{{=}}nginx sts{{=}}4 sw{{=}}4 ts{{=}}4 noet :}}}} | |||
[[Category:Arch Linux]] | [[Category:Arch Linux]] |
Latest revision as of 00:46, 17 May 2021
Introduction
Install
Beforehand be sure to determine weather the web server will be using MySQL (ie. MariaDB) or PostgreSQL.
Begin by installing NGINX, PHP and other required utilities.
# pikaur -S apache-tools composer curl minify nginx php-fpm sassc wget |
Install all of the required PHP extensions.
# pikaur -S php-gd php-geoip php-imagick php-intl php-memcache php-odbc php-sqlite php-sodium xdebug |
Next create the environment for the web server.
# sudo mkdir -p /nginx/conf.d /nginx/https /nginx/logs /nginx/sql /nginx/ssl /nginx/vhosts.d |
# sudo chown -R http:http /nginx |
# sudo chmod -R 770 /nginx |
# sudo chmod 750 /nginx/sql |
# sudo gpasswd -a username http |
Set the default shell for http to Bash.
# sudo chsh -s /bin/bash http |
PostgreSQL
Using postgresql as a back-end will require the following setup and configuration.
# pikaur -S postgresql php-pgsql |
# sudo chown postgres:postgres /nginx/sql |
# sudo gpasswd -a username postgres |
Swap over to the postgresql user account.
# sudo -iu postgres |
Run the database initialization.
# initdb --locale en_US.UTF-8 -E UTF8 -D '/nginx/sql/data' |
Return to the normal user account.
# exit |
Modify the systemd service file to reflect the new data directory.
# sudo systemctl edit postgresql.service |
Environment=PGROOT=/nginx/sql PIDFile=/nginx/sql/postmaster.pid |
Start and enable the systemd service.
# sudo systemctl enable --now postgresql.service |
Swap back over to the postgresql user account.
# sudo -iu postgres |
Create a new postgres user account.
# createuser -P --interactive Enter name of role to add: username Enter password for new role: ******** Enter it again: ******** Shall the new role be a superuser? (y/n) n Shall the new role be allowed to create databases? (y/n) y Shall the new role be allowed to create more new roles? (y/n) n |
MariaDB
Using mariadb as a back-end will require the following setup and configuration.
# pikaur -S mariadb |
# sudo chown mysql:mysql /nginx/sql |
Give the current logged in user access.
# sudo gpasswd -a username mysql |
Create and initialize the data directory.
# mariadb-install-db --user=mysql --basedir=/usr --datadir=/nginx/sql |
# sudoedit /etc/my.cnf.d/server.cnf |
[mysqld] datadir=/nginx/sql |
Start and enable the MySQL service.
# sudo systemctl enable --now mariadb.service |
Secure the installation and set the root password.
# sudo mysql_secure_installation |
The default mysql root password is none |
Connect to mysql using the root account and the password you previously set.
# sudo mysql -u root -p |
Add a new mysql user account.
# MariaDB [(none)]> GRANT ALL PRIVILEGES ON *.* TO 'kyau'@'localhost' \ IDENTIFIED BY 'user_password' WITH GRANT OPTION; |
Configuration
PHP
First remove the default pool.
# sudo rm /etc/php/php-fpm.d/www.conf |
Create the defaults for all pools.
# sudoedit /etc/php/php-fpm.d/defaults.inc |
user = http group = http listen = /run/php-fpm/php-fpm-$pool.sock listen.owner = http listen.group = http ; process configuration pm = dynamic pm.max_children = 5 pm.start_servers = 2 pm.min_spare_servers = 1 pm.max_spare_servers = 3 ; php.ini changes php_admin_flag[expose_php] = off php_admin_flag[log_errors] = on php_admin_flag[short_open_tag] = on php_admin_value[date.timezone] = America/Los_Angeles php_admin_value[error_log] = /nginx/logs/$pool/php.log php_admin_value[memory_limit] = 256M php_admin_value[post_max_size] = 2048M php_admin_value[session.save_path] = /tmp php_admin_value[upload_max_filesize] = 2048M |
Enable all third party PHP extensions that were installed.
# sudo find . -type f -name '*.ini' -exec sed -i -e 's/^;extension/extension/g' \ -e 's/^;zend_extension/zend_extension/g' -e 's/^;xdebug/xdebug/g' {} + |
Enable global PHP extensions.
# sudoedit /etc/php/conf.d/defaults.ini |
extension=bz2 extension=exif extension=gd extension=gettext extension=gmp extension=iconv extension=intl extension=sodium extension=mysqli extension=odbc extension=pdo_mysql extension=pdo_odbc extension=pdo_sqlite extension=sockets extension=sqlite3 ; opcache zend_extension=opcache opcache.enable = 1 opcache.interned_strings_buffer = 8 opcache.max_accelerated_files = 10000 opcache.memory_consumption = 128 opcache.save_comments = 1 opcache.revalidate_freq = 1 |
Create a php-fpm pool for the domain being setup (use a different pool for each site/domain).
# sudoedit /etc/php/php-fpm.d/domain_com.conf |
; $KYAULabs: domain_com.conf,v 1.0.0 2021/05/01 12:36:14 kyau Exp $ [domain_com] include = /etc/php/php-fpm.d/defaults.inc env[HOSTNAME] = domain.com env[PATH] = /usr/local/bin:/usr/bin:/bin env[TMP] = /tmp env[TMPDIR] = /tmp env[TEMP] = /tmp ; vim: ft=dosini sts=4 sw=4 ts=4 noet : |
One can temporarily disable sites/domains by renaming the config to .conf.disable and reloading the php-fpm service |
Be sure to set the file permissions properly.
# sudo chmod 644 /etc/php/conf.d/defaults.ini /etc/php/php-fpm.d/* |
Start and enable the php-fpm service.
# sudo systemctl enable --now php-fpm.service |
NGINX
Create a blank configuration file.
# sudo install -g http -m 660 -o http /dev/null /nginx/conf.d/nginx.conf |
Copy the MIME types file.
# sudo install -g http -m 660 -o http /etc/nginx/mime.types /nginx/conf.d/mime.types |
Remove the default config in nginx.conf and replace it with an include (to the new config location).
# sudoedit /etc/nginx/nginx.conf |
include /nginx/conf.d/nginx.conf; |
Create the nginx config file.
# sudoedit /nginx/conf.d/nginx.conf |
# $KYAULabs: nginx.conf,v 1.1.7 2021/05/03 18:14:27 kyau Exp $ # Help / Additional Info {{{ # always test configuration before reload! # $ sudo nginx -t # reload the configuration by using reload not restart! # $ sudo systemctl reload nginx # https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/ # }}} # enables the use of “just-in-time compilation” for the regular expressions # known by the time of configuration parsing pcre_jit on; # user and group credentials used by worker processes user http http; # number of worker processes (auto will autodetect number of CPU cores) worker_processes auto; # binds worker processes automatically to available CPUs worker_cpu_affinity auto; # number of file descriptors used for nginx worker_rlimit_nofile 65535; events { # worker process will accept one/all (off/on) connection(s) at a time multi_accept on; # maximum number of simultaneous connections that can be opened by a worker worker_connections 4096; } http { # mime types include /nginx/conf.d/mime.types; # to boost I/O on HDD we can disable access logs access_log off; # read and send using multi-threading, without blocking a worker process aio threads; # hide index pages autoindex off; # add to 'Content-Type' response header charset utf-8; # request timed out -- default 60 client_body_timeout 10; # sets the maximum allowed size of the client request body -- default 1 client_max_body_size 16m; # default mime type default_type text/plain; # enable gzipping of responses gzip on; # disables gzipping of responses for msie6 and below gzip_disable "msie6"; # minimum length of a response that will be gzipped -- default 20 gzip_min_length 1024; # gzip compression level -- default 1 gzip_comp_level 6; gzip_vary on; gzip_proxied expired no-cache no-store private auth; # text/html is always compressed gzip_types text/css text/javascript text/xml text/x-component application/javascript application/x-javascript application/json application/xml application/rss+xml application/atom+xml font/truetype font/opentype application/vnd.ms-fontobject image/svg+xml; # files that will be used as an index, checked in the specified order index index.php index.html index.htm index.txt; # enables keep-alive connections with all browsers keepalive_disable none; # keep-alive client connections stay active for -- default 75 keepalive_timeout 30s; # specifies log format log_format main '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent"'; # disables logging of errors about not found files into error_log log_not_found off; # cache open file descriptors, directories and file lookup errors open_file_cache max=10240 inactive=20s; open_file_cache_valid 30s; open_file_cache_min_uses 2; open_file_cache_errors on; # allow the server to close connection on non responding client, this will # free up memory reset_timedout_connection on; # if client stops responding, free up memory -- default 60 send_timeout 8; # copies data between one FD and other from within the kernel faster than # read() + write() sendfile on; # bucket size for the server names hash tables server_names_hash_bucket_size 128; # disables emitting nginx version on error pages and in the "server" # response header field server_tokens off; # send headers in one piece, it is better than sending them one by one tcp_nopush on; # don't buffer data sent, good for small data bursts in real time tcp_nodelay on; # hash table maximum size -- default 1024 types_hash_max_size 4096; # include domain configuration files include /nginx/vhosts.d/*.conf; # redirect all non-encrypted (http) traffic to encrypted (https) server { server_name _; listen *:80 default_server; listen [::]:80 default_server; return 301 https://$host$request_uri; } } # vim: ft=nginx sts=4 sw=4 ts=4 noet : |
Create a vhost defaults config.
# sudoedit /nginx/conf.d/vhost_defaults |
# $KYAULabs: vhost.defaults,v 1.0.7 2021/05/16 12:48:55 kyau Exp $ ## SSL/TLS (https://cipherlist.dev/) ssl_dhparam /nginx/ssl/dhparam4096.pem; # openssl dhparam -out dhparam4096.pem 4096 ssl_protocols TLSv1.3; # Requires nginx >= 1.13.0 ssl_ciphers EECDH+CHACHA20:EECDH+AES; ssl_ecdh_curve X25519; # Requires nginx >= 1.1.0 ssl_session_cache shared:SSL:10m; ssl_session_tickets off; # Requires nginx >= 1.5.9 ssl_session_timeout 10m; ssl_stapling on; # Requires nginx >= 1.3.7 ssl_stapling_verify on; # Requires nginx >= 1.3.7 ssl_prefer_server_ciphers on; resolver 1.1.1.1 1.0.0.1 [2606:4700:4700::1111] [2606:4700:4700::1001] valid=60s; # Change if you run your own DNS servers resolver_timeout 2s; # security settings add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block"; # vim: ft=nginx sts=4 sw=4 ts=4 noet : |
Create a URI defaults config.
# sudoedit /nginx/conf.d/uri_defaults |
# $KYAULabs: uri_defaults,v 1.0.2 2021/05/05 17:55:10 kyau Exp $ # remove `robots.txt` and all favicons from the logs location ~* "^/(favicon\.\S{3,5}|robots\.txt)$" { access_log off; allow all; log_not_found off; } # disable dot (hidden) files while allowing `.well-known` location ~* /\.(?!well-known).* { access_log off; deny all; log_not_found off; } # deny access to any sensitive material location ~* (?:#.*#|\.(?:bak|conf|dist|fla|in[ci]|log|orig|phps|psd|sass|scss|sh|sql|sw[op])|~)$ { access_log on; deny all; log_not_found on; } # asset/media cache location ~* \.(?:css(\.map)?|js(\.map)?|jpe?g|png|gif|ico|cur|heic|webp|tiff?|mp3|m4a|aac|ogg|midi?|wav|mp4|mov|webm|mpe?g|avi|ogv|flv|wmv)$ { access_log off; expires 7d; } # fonts/svg cache and access location ~* \.(?:svgz?|ttf|ttc|otf|eot|woff2?)$ { access_log off; add_header Access-Control-Allow-Origin "*"; expires 7d; } # html processing location ~* \.html$ { try_files $uri $uri/ /index.html =404; } # http error pages error_page 404 /404; error_page 500 502 503 504 /50x; location = /404 { root /nginx/https/error; index 404.php; } location = /50x { root /nginx/https/error; index 50x.php; } # vim: ft=nginx sts=4 sw=4 ts=4 noet : |
FastCGI
Create a fastcgi_params config file (PHP environmental variable defaults).
# sudoedit /nginx/conf.d/fastcgi_params |
# $KYAULabs: fastcgi_params,v 1.0.5 2021/05/03 17:31:37 kyau Exp $ fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_FILENAME $request_filename; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; #fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param SERVER_SOFTWARE nginx; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; # PHP only, required if PHP was built with --enable-force-cgi-redirect fastcgi_param REDIRECT_STATUS 200; # Mitigate https://httpoxy.org/ vulnerabilities fastcgi_param HTTP_PROXY ""; # vim: ft=nginx sts=4 sw=4 ts=4 noet : |
SSL/TLS
Create the dhparam as indicated above.
# sudo -u http openssl dhparam -out /nginx/ssl/dhparam4096.pem 4096 |
Set permissions properly.
# sudo chmod 660 /nginx/ssl/dhparam4096.pem |
Virtual Hosts
Virtual Hosts are created in domain config files keeping all subdomains in a single file. The following template can be used, simply replace domain_com and domain.com with the actual domain name.
# sudoedit /nginx/vhosts.d/domain_com.conf |
# $KYAULabs: domain_com.conf,v 1.1.5 2021/05/05 18:06:34 kyau Exp $ ## Redirect all WWW to Non-WWW (SSL) server { listen *:443 ssl http2; listen [::]:443 ssl http2; server_name www.domain.com; #access_log /nginx/logs/domain_com/www-access.log; error_log /nginx/logs/domain_com/www-error.log; ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem; ssl_trusted_certificate /etc/letsencrypt/live/domain.com/chain.pem; include /nginx/conf.d/vhost_defaults; return 301 https://domain.com$request_uri; } ## domain.com server { listen *:443 ssl http2; listen [::]:443 ssl http2; server_name domain.com; #access_log /nginx/logs/domain_com/domain_com-access.log; error_log /nginx/logs/domain_com/domain_com-error.log; ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem; ssl_trusted_certificate /etc/letsencrypt/live/domain.com/chain.pem; include /nginx/conf.d/vhost_defaults; root /nginx/https/domain_com/www; location / { try_files $uri $uri/ @rewrite; } location @rewrite { #rewrite ^/directory/$ /script.php?x=directory last; } #location ^~ /app/ { #proxy_pass http://127.0.0.1:8080/; #proxy_http_version 1.1; #proxy_set_header Connection "upgrade"; #proxy_set_header Upgrade $http_upgrade; #proxy_set_header X-Forwarded-For $remote_addr; #proxy_set_header X-Forwarded-Proto $scheme; # by defaults nginx times out connections in one minute #proxy_read_timeout 1d; #} include /nginx/conf.d/uri_defaults; # php scripts location ~* [^/]\.php(/|$) { try_files $fastcgi_script_name =404; include /nginx/conf.d/fastcgi_params; fastcgi_buffers 8 16k; fastcgi_buffer_size 32k; fastcgi_index index.php; fastcgi_split_path_info ^(.+?\.php)(/.*)$; fastcgi_pass unix:/run/php-fpm/php-fpm-domain_com.sock; } } ## api.domain.com server { listen *:443 ssl http2; listen [::]:443 ssl http2; server_name api.domain.com; #access_log /nginx/logs/domain_com/api-access.log; error_log /nginx/logs/domain_com/api-error.log; ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem; ssl_trusted_certificate /etc/letsencrypt/live/domain.com/chain.pem; include /nginx/conf.d/vhost_defaults; root /nginx/https/domain_com/api; location / { try_files $uri $uri/ @rewrite; } location @rewrite { #rewrite ^/directory/$ /script.php?x=directory last; } include /nginx/conf.d/uri_defaults; # php scripts location ~* [^/]\.php(/|$) { try_files $fastcgi_script_name =404; include /nginx/conf.d/fastcgi_params; fastcgi_buffers 8 16k; fastcgi_buffer_size 32k; fastcgi_index index.php; fastcgi_split_path_info ^(.+?\.php)(/.*)$; fastcgi_pass unix:/run/php-fpm/php-fpm-domain_com.sock; } } # vim: ft=nginx sts=4 sw=4 ts=4 noet : |