Project

General

Profile

Support #692

Updated by Daniel Curtis over 8 years ago

{{>toc}} 

 Here is a procedure to install Nginx, PostgreSQL and PHP web server stack on Arch Linux. 

 h1. Prepare the Environment 

 * Before installation of the components, make sure everything is up to date using the following command: 
 <pre> 
 pacman -Syu 
 </pre> 

 * Install a few dependencies: 
 <pre> 
 pacman -S sudo git curl 
 </pre> 

 * Add the sudo group 
 <pre> 
 groupadd sudo 
 </pre> 

 * Edit the sudoers file: 
 <pre> 
 visudo 
 </pre> 
 #* And uncomment the %sudo line to allow users in the sudo group access to sudo: 
 <pre> 
 %sudo 	 ALL=(ALL) ALL 
 </pre> 

 * Add a webuser 
 <pre> 
 useradd -m -g users -s /bin/bash webuser 
 </pre> 
 #* And add webuser to the sudo group: 
 <pre> 
 usermod -aG sudo webuser 
 </pre> 

 --- 

 h1. Install Nginx 

 * Install Nginx 
 <pre> 
 pacman -S nginx 
 </pre> 

 * Start and enable nginx at boot: 
 <pre> 
 systemctl enable nginx 
 systemctl start nginx 
 </pre> 

 * Create a configuration directory to make managing individual server blocks easier 
 <pre> 
 mkdir /etc/nginx/conf.d 
 </pre> 

 * Edit the main nginx config file: 
 <pre> 
 vi /etc/nginx/nginx.conf 
 </pre> 
 #* And strip down the config file and add the include statement at the end to make it easier to handle various server blocks: 
 <pre> 
 #user    nobody; 
 worker_processes    1; 
 error_log    /var/log/nginx-error.log; 

 events { 
     worker_connections    1024; 
 } 

 http { 
     include         mime.types; 
     default_type    application/octet-stream; 

     sendfile          on; 
     #tcp_nopush       on; 

     #keepalive_timeout    0; 
     keepalive_timeout    65; 

     #gzip    on; 

     # Load config files from the /etc/nginx/conf.d directory 
     include /etc/nginx/conf.d/*.conf; 
 } 
 </pre> 

 h2. Default Static Website 

 Start by setting up a simple static website, no server-side stuff PHP or Ruby; just plain HTML, CSS, JavaScript, etc. 

 * Create a directory for the web site: 
 <pre> 
 mkdir -p /var/www/www.example.com 
 </pre> 

 * Add a *default site server block*: 
 <pre> 
 vi /etc/nginx/conf.d/www.example.com.conf 
 </pre> 
 #* Add the following: 
 <pre> 
 server { 
     listen         80 default_server; 
     server_name    www.example.com; 

     access_log    /var/log/www.example.com.log    main; 

     location / { 
         root     /var/www/www.example.com; 
         index    index.html index.htm; 
     } 
 } 
 </pre> 

 --- 

 h1. Install PostgreSQL 9.4 

 * Make sure to enable en_US.UTF-8 in the locale generation file: 
 <pre> 
 sed -i -e 's/\#en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen 
 </pre> 
 #* And regenerate the local locales: 
 <pre> 
 locale-gen 
 </pre>  

 * Install PostgreSQL: 
 <pre> 
 pacman -S postgresql 
 </pre> 

 * Enable PostgreSQL at boot: 
 <pre> 
 systemctl enable postgresql 
 </pre> 

 *NOTE*: If the postgresql database is on a btrfs filesystem, make sure to disable Copy-on-Write for the postgresql database folder: 
 <pre> 
 chattr +C /var/lib/postgres/data 
 </pre> 

 * Switch to the postgresql user: 
 <pre> 
 su - postgres 
 </pre> 
 #* Initialize the database: 
 <pre> 
 initdb --locale en_US.UTF-8 -E UTF8 -D '/var/lib/postgres/data' 
 </pre> 
 #* Then exit the postgresql user: 
 <pre> 
 exit 
 </pre> 

 * Start PostgreSQL: 
 <pre> 
 systemctl start postgresql 
 </pre> 

 * Edit the postgres config file: 
 <pre> 
 vi /var/lib/postgres/data/postgresql.conf 
 </pre> 
 #* And modify the following: 
 <pre> 
 listen_addresses = '*' 
 </pre> 

 * Edit the pg_hba config file: 
 <pre> 
 vi /var/lib/postgres/data/pg_hba.conf 
 </pre> 
 #* And modify the following: 
 <pre> 
 # TYPE    DATABASE      USER          CIDR-ADDRESS            METHOD only 

 # Local connections 
 local     all           all                                 trust 

 # IPv4 local connections: 
 host      all           all           127.0.0.1/32            trust 

 # IPv6 local connections: 
 host      all           all           ::1/128                 trust 

 # IPv4 connections: 
 host      all           all           192.168.10.0/24         md5 

 # IPv6 local connections: 
 host      all           all           1234::abcd/64           md5 
 </pre> 

 * And wrap up by restarting the postgresql server: 
 <pre> 
 systemctl restart postgresql 
 </pre> 

 h2. Create a new user and database 

 * Switch to the pgsql user: 
 <pre> 
 su - postgres 
 </pre> 
 #* Create the somepgdb database: 
 <pre> 
 createdb somepgdb 
 </pre> 
 #* Then create the somepguser user: 
 <pre> 
 createuser -P 
 </pre> 
 #* Grant all privileges to somepgdb to somepguser: 
 <pre> 
 psql -d template1 
 GRANT ALL PRIVILEGES ON DATABASE "somepgdb" to somepguser; 
 \q 
 </pre> 
 #* Exit from the postgresql user 
 <pre> 
 exit 
 </pre> 

 --- 

 h1. Install PHP 

 * Install PHP 5.6 and php-fpm: 
 <pre> 
 pacman -S php php-fpm 
 </pre> 

 * Install PHP extensions and a few modules: 
 <pre> 
 pacman -S php-pgsql php-pear 
 </pre> 
 #* *NOTE*: There are many more PHP modules, to search for more PHP modules run: 
 <pre> 
 pacman -Ss php 
 </pre> 

 h2. Configure PHP-FPM 

 * Enable php-fpm at boot: 
 <pre> 
 systemctl enable php-fpm 
 </pre> 

 * Edit the php-fpm config: 
 <pre> 
 vi /etc/php/php-fpm.conf 
 </pre> 
 #* Make the following changes: 
 <pre> 
 listen = /run/php-fpm/php-fpm.sock 
 listen.owner = http 
 listen.group = http 
 listen.mode = 0660 
 </pre> 

 * Start php-fpm: 
 <pre> 
 systemctl start php-fpm 
 </pre> 

 h2. PHP Website 

 * Create a directory for the web application: 
 <pre> 
 mkdir /var/www/phpapp.example.com 
 </pre> 

 * Add a *phpapp.example.com server block*: 
 <pre> 
 vi /etc/nginx/conf.d/phpapp.example.com.conf 
 </pre> 
 #* Add the following: 
 <pre> 
 server { 
     listen         80; 
     server_name    phpapp.example.com; 
     root           /var/www/phpapp.example.com; 
     access_log     /var/log/phpapp.example.com-access.log; 
     error_log      /var/log/phpapp.example.com-error.log; 

     location / { 
         index    index.php index.html index.htm; 
     } 

     # For all PHP requests, pass them on to PHP-FPM via FastCGI 
     location ~ \.php$ { 
         fastcgi_pass unix:/run/php-fpm/php-fpm.sock; 
         fastcgi_param SCRIPT_FILENAME /var/www/phpapp.example.com$fastcgi_script_name; 
         fastcgi_param PATH_INFO $fastcgi_script_name; 
         include fastcgi_params; # include extra FCGI params 
     } 
 } 
 </pre> 

 * Add the PHP files for the site and change the ownership to the http user: 
 <pre> 
 chown R http:http /var/www/phpapp.example.com 
 </pre> 

 * Restart nginx: 
 <pre> 
 systemctl restart nginx 
 </pre> 

 --- 

 h1. (Extra) Install Phusion Passenger 

 * Remove the system nginx package: 
 <pre> 
 pacman -R nginx 
 </pre> 
 #* Remove the old nginx configuration directory 
 <pre> 
 rm -rf /etc/nginx 
 </pre> 

 * Install the base-devel package: 
 <pre> 
 pacman -S base-devel 
 </pre> 

 * Install RVM: 
 <pre> 
 curl -L get.rvm.io | bash -s stable 
 </pre> 

 * Then add the following line to the end of your @~/.bash_login@ file 
 <pre> 
 echo '[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"' >> ~/.bash_login 
 </pre> 
 #* Now logout and log back in for rvm to take effect 

 * Add the http user to the rvm group: 
 <pre> 
 usermod -aG rvm http 
 </pre> 

 * See if there are any dependency requirements for your installation by running: 
 <pre> 
 rvm requirements 
 </pre> 

 * Install ruby 2.1: 
 <pre> 
 rvm install 2.1.5 
 </pre> 

 * Run the following to allow passenger install nginx: 
 <pre> 
 rvm 2.1.5  
 gem install passenger 
 rvmsudo passenger-install-nginx-module 
 </pre> 

 * Link the new nginx configuration folder in the /etc folder: 
 <pre> 
 ln -s /opt/nginx/conf /etc/nginx 
 </pre> 
 #* Don't forget to remake the conf.d folder in the nginx configuration folder: 
 <pre> 
 mkdir /etc/nginx/conf.d 
 </pre> 

 * Edit the main nginx config file: 
 <pre> 
 vi /etc/nginx/nginx.conf 
 </pre> 
 #* And add the Passenger config parameters: 
 <pre> 
 #user    nobody; 
 worker_processes    1; 
 error_log    /var/log/nginx-error.log; 

 events { 
     worker_connections    1024; 
 } 

 http { 
     include         mime.types; 
     default_type    application/octet-stream; 

     sendfile          on; 
     #tcp_nopush       on; 

     #keepalive_timeout    0; 
     keepalive_timeout    65; 

     #gzip    on; 

     # Load Phusion Passenger module globally 
     passenger_root /usr/local/rvm/gems/ruby-2.1.5/gems/passenger-5.0.21; 
     passenger_ruby /usr/local/rvm/wrappers/ruby-2.1.5/ruby; 
     passenger_max_pool_size 15; 
     passenger_pool_idle_time 300; 

     # Load config files from the /etc/nginx/conf.d directory 
     include /etc/nginx/conf.d/*.conf; 
 } 
 </pre> 

 * Create a new Restart nginx systemd init script: to load passenger: 
 <pre> 
 vi /etc/systemd/system/nginx.service 
 </pre> 
 #* And add the following: 
 <pre> 
 [Unit] 
 Description=Nginx 
 After=syslog.target network.target 

 [Service] 
 Type=forking 
 ExecStart=/etc/nginx/sbin/nginx 
 ExecReload=/etc/nginx/sbin/nginx -s reload 

 [Install] 
 WantedBy=multi-user.target 
 </pre> 

 * Start and enable nginx at boot:: 
 <pre> 
 systemctl enable nginx 
 systemctl start restart nginx 
 </pre> 

 h2. Ruby Website 

 * Create a directory for the web application: 
 <pre> 
 mkdir /var/www/rubyapp.example.com 
 </pre> 

 * Add a *rubyapp.example.com server block*: 
 <pre> 
 vi /usr/local/etc/nginx/conf.d/rubyapp.example.com.conf 
 </pre> 
 #* Add the following: 
 <pre> 
 server { 
     listen         80; 
     server_name    rubyapp.example.com; 
     root           /var/www/rubyapp.example.com/public; 
     access_log     /var/log/rubyapp.example.com-access.log; 
     error_log      /var/log/rubyapp.example.com-error.log 

     passenger_enabled on; 
     passenger_user      http; 
     passenger_group     http; 
 } 
 </pre> 

 * Restart nginx to load the website config: 
 <pre> 
 service nginx restart 
 </pre> 

 --- 

 h1. Securing Nginx With SSL 

 * Install OpenSSL: 
 <pre> 
 pacman -S openssl 
 </pre> 

 Enabling SSL in Nginx is simple. First add the ssl directive in the server listen option, then add the SSL certificate and key paths. 

 * The basic SSL server block should be look similar to the following: 
 <pre> 
 server { 
     listen                443 ssl; 
     server_name           www.example.com; 
     ssl_certificate       www.example.com.crt; 
     ssl_certificate_key www.example.com.key; 
 } 
 </pre> 

 * Setup the Diffie-Hellman Key Exchange Parameters 
 <pre> 
 cd /etc/nginx 
 openssl dhparam -out dhparam.pem 4096 
 </pre> 

 * Generate a strong SSL key and a CSR to send for signing by a CA: 
 <pre> 
 cd /etc/nginx 
 openssl req -sha512 -out www.example.com.csr -new -newkey rsa:4096 -nodes -keyout www.example.com.key 
 </pre> 
 #* If the received SSL certificate requires additional bundle certificates, add them together like so: 
 <pre> 
 cd /etc/nginx 
 cat www.example.com.crt www.example.com.bundle > www.example.com.chained.crt 
 </pre> 

 * Setup the default site configuration: 
 <pre> 
 vi /etc/nginx/conf.d/www.example.com.conf 
 </pre> 
 #* Then add or modify the configuration to look similar to the following: 
 <pre> 
 server { 
     listen 80;  
     listen 443 default ssl; 
     server_name www.example.com; 

     # Turn on ans set SSL key/cert 
     ssl on; 
     ssl_certificate /etc/nginx/www.example.com.crt; 
     ssl_certificate_key /etc/nginx/www.example.com.key; 

     # Strong SSL configuration 
     ssl_ciphers 'AES128+EECDH:AES128+EDH:!aNULL'; 
     ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 
     ssl_session_cache    builtin:1000    shared:SSL:10m; 
     ssl_stapling on; 
     ssl_stapling_verify on; 
     ssl_prefer_server_ciphers on; 
     ssl_dhparam /nginx/dhparam.pem; 
     add_header Strict-Transport-Security max-age=63072000; 
     add_header X-Frame-Options SAMEORIGIN; 
     add_header X-Content-Type-Options nosniff; 

     root /var/www/; 
     index index.html index.htm; 
     autoindex on; 
 } 
 </pre> 

 * Restart nginx to load the new website config: 
 <pre> 
 service nginx restart 
 </pre> 

 h2. Certificate Bundles 

 Some browsers may complain about a certificate signed by a well-known certificate authority, while other browsers may accept the certificate without issues. This occurs because the issuing authority has signed the server certificate using an intermediate certificate that is not present in the certificate base of well-known trusted certificate authorities which is distributed with a particular browser. In this case the authority provides a bundle of chained certificates which should be concatenated to the signed server certificate.  

 * The server certificate must appear before the chained certificates in the combined file: 
 <pre> 
 cat www.example.com.crt bundle.crt > www.example.com.chained.crt 
 </pre> 

 * The resulting file should be used in the ssl_certificate directive: 
 <pre> 
 server { 
     listen                443 ssl; 
     server_name           www.example.com; 
     ssl_certificate       www.example.com.chained.crt; 
     ssl_certificate_key www.example.com.key; 
 } 
 </pre> 

 h1. Resources 

 * https://wiki.archlinux.org/index.php/Ruby_on_Rails#The_Perfect_Rails_Setup 
 * https://wiki.archlinux.org/index.php/RVM 
 * https://wiki.archlinux.org/index.php/PostgreSQL

Back