Project

General

Profile

Support #622

Updated by Daniel Curtis about 8 years ago

{{>toc}} 

 Here is a procedure to install a FreeBSD with Nginx, PostgreSQL and PHP server stack. If any version of the packages needs to be changed, replace the versions in the commands accordingly. 

 There are also extra additions for running Ruby web applications with Phusion Passenger, and Perl CGI web applications using FastCGI. 

 h1. Prepare the Environment 

 * Before installation of the components, make sure everything is up to date using the following command: 
 <pre> 
 pkg update -f && pkg upgrade 
 </pre> 

 * Install portmaster: 
 <pre> 
 cd /usr/ports/ports-mgmt/portmaster 
 make install clean 
 pkg2ng 
 </pre> 

 --- 

 h1. Install Nginx 

 * Install Nginx 
 <pre> 
 portmaster www/nginx 
 </pre> 

 * Start and enable nginx at boot: 
 <pre> 
 echo 'nginx_enable="YES"' >> /etc/rc.conf 
 service nginx start 
 </pre> 

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

 * Edit the main nginx config file: 
 <pre> 
 vi /usr/local/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> 
 load_module /usr/local/libexec/nginx/ngx_mail_module.so; 
 load_module /usr/local/libexec/nginx/ngx_stream_module.so; 

 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; 
     keepalive_timeout    65; 

     # Load config files from the /etc/nginx/conf.d directory 
     include /usr/local/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 /usr/local/www/www.example.com 
 </pre> 

 * Add a *default site server block*: 
 <pre> 
 vi /usr/local/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     /usr/local/www/www.example.com; 
         index    index.html index.htm; 
     } 

     # redirect server error pages to the static page /50x.html 
     error_page     500 502 503 504    /50x.html; 
     location = /50x.html { 
         root     /usr/local/www/nginx-dist; 
     } 
 } 
 </pre> 

 --- 

 h1. Install PostgreSQL 9.4 


 * Install PostgreSQL: 
 <pre> 
 portmaster databases/postgresql94-server 
 </pre> 

 * Enable PostgreSQL at boot: 
 <pre> 
 echo 'postgresql_enable="YES"' >> /etc/rc.conf 
 </pre> 

 * Initialize the database: 
 <pre> 
 service postgresql initdb 
 </pre> 

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

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

 * Edit the pg_hba config file: 
 <pre> 
 vi /usr/local/etc/pgsql/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 nginx and postgresql servers: 
 <pre> 
 service nginx restart 
 service postgresql restart 
 </pre> 

 h2. Create a new user and database 

 * Switch to the pgsql user: 
 <pre> 
 su pgsql 
 </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 template1 
 GRANT ALL PRIVILEGES ON DATABASE "somepgdb" to somepguser; 
 \q 
 </pre> 

 * Exit from the pgsql user 
 <pre> 
 exit 
 </pre> 

 --- 

 h1. Install PHP 

 The PHP support in FreeBSD is extremely modular so the base install is very limited. It is very easy to add support using the _lang/php5-extensions_ port. This port provides a menu driven interface to PHP extension installation. Alternatively, individual extensions can be installed using the appropriate port. 

 * Install PHP 5.6 and other supporting packages: 
 <pre> 
 portmaster lang/php56 
 </pre> 

 * Install PHP extensions and a few modules: 
 <pre> 
 portmaster lang/php56-extensions databases/php56-pgsql databases/php56-pdo_pgsql www/php56-session 
 </pre> 
 #* *NOTE*: There are many more PHP modules, to search for more PHP modules run: 
 <pre> 
 find /usr/ports/ -name "php56-*" 
 </pre> 
 #* *NOTE*: PHP capabilities can be further extended by using PECL packages, to search for more PECL packages run: 
 <pre> 
 find /usr/ports/ -name "pecl-*" 
 </pre> 

 * Configure the default PHP settings 
 <pre> 
 cp /usr/local/etc/php.ini-production /usr/local/etc/php.ini 
 </pre> 

 h2. Configure PHP-FPM 

 * Edit @/usr/local/etc/php-fpm.conf@: 
 <pre> 
 vi /usr/local/etc/php-fpm.conf 
 </pre> 
 #* Make the following changes: 
 <pre> 
 listen = /var/run/php-fpm.sock 
 listen.owner = www 
 listen.group = www 
 listen.mode = 0660 
 </pre> 

 * Start and enable PHP-FPM at boot: 
 <pre> 
 echo 'php_fpm_enable="YES"' >> /etc/rc.conf 
 service php-fpm start 
 </pre> 

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

 h2. PHP Website 

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

 * Add a *phpapp.example.com server block*: 
 <pre> 
 vi /usr/local/etc/nginx/conf.d/phpapp.example.com.conf 
 </pre> 
 #* Add the following: 
 <pre> 
 server { 
     listen         80; 
     server_name    phpapp.example.com; 
     root           /usr/local/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:/var/run/php-fpm.sock; 
         fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 
         fastcgi_param PATH_INFO $fastcgi_script_name; 
         include fastcgi_params; 
     } 
 } 
 </pre> 

 --- 

 h1. Install Phusion Passenger (Ruby) 

 * Install Passenger 
 <pre> 
 portmaster www/rubygem-passenger 
 </pre> 
 #* *NOTE*: Make sure to enable *@[X]NGINX@* while configuring rubygem-passenger 
 #* *NOTE*: Enabling *[X]SYMLINK* makes upgrading passenger easier later on. 
 #* *NOTE*: Ruby capabilities can be further extended by using rubygem packages, to search for more packages run: 
 <pre> 
 find /usr/ports/ -name "rubygem-*" 
 </pre> 

 * Reinstall nginx with passenger support: 
 <pre> 
 cd /usr/ports/www/nginx 
 make config 
 portmaster www/nginx 
 </pre> 
 #* *NOTE*: Make sure to enable *@[X]PASSENGER@* while configuring _nginx_ 

 h2.    Configure Passenger 

 * Edit the main nginx config file: 
 <pre> 
 vi /usr/local/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/lib/ruby/gems/2.1/gems/passenger; 
     passenger_ruby /usr/local/bin/ruby21; 
     passenger_max_pool_size 15; 
     passenger_pool_idle_time 300; 

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

 * Restart nginx to load passenger: 
 <pre> 
 service nginx restart 
 </pre> 

 h2. Ruby Website 

 * Create a directory for the web application: 
 <pre> 
 mkdir /usr/local/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           /usr/local/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      www; 
     passenger_group     www; 
 } 
 </pre> 

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

 --- 

 h1. Install FastCGI (Perl) 

 I occasionally need to run a perl CGI script, FastCGI is capable of handling this task. 

 * Install fcgiwrap 
 <pre> 
 pkg install fcgiwrap p5-FCGI 
 </pre> 

 * Start and enable fcgiwrap at boot: 
 <pre> 
 echo 'fcgiwrap_enable="YES"' >> /etc/rc.conf 
 echo 'fcgiwrap_profiles="main"' >> /etc/rc.conf 
 echo 'fcgiwrap_main_socket="unix:/tmp/fcgiwrap.sock"' >> /etc/rc.conf 
 echo 'fcgiwrap_main_user="www"' >> /etc/rc.conf 
 service fcgiwrap start 
 </pre> 

 h2. CGI Website 

 * Create a directory for the web application: 
 <pre> 
 mkdir /usr/local/www/cgi-app.example.com 
 </pre> 

 * Add a *cgi-app.example.com server block*: 
 <pre> 
 vi /usr/local/etc/nginx/conf.d/cgi-app.example.com.conf 
 </pre> 
 #* Add the following: 
 <pre> 
 upstream fcgiwrap { 
    server unix:/tmp/fcgiwrap.sock; 
 } 

 server { 
     listen         80; 
     server_name    cgi-app.example.com; 
     root           /usr/local/www/cgi-app.example.com; 
     access_log     /var/log/cgi-app.example.com-access.log; 
     error_log      /var/log/cgi-app.example.com-error.log; 

     location / { 
             try_files $uri $uri/ =404; 
     } 

     location ~ \.cgi$ { 
         include /usr/local/etc/nginx/fastcgi_params; 
         fastcgi_index index.cgi; 
         fastcgi_pass fcgiwrap; 
         fastcgi_param    SCRIPT_FILENAME    $document_root$fastcgi_script_name; 
     } 
 } 
 </pre> 

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

 --- 

 h1. Install uWSGI (Python) 

 * Install a couple dependencies: 
 <pre> 
 pkg install bash    py27-{pip,virtualenv} sqlite3 uwsgi 
 </pre> 

 * Create a user for the python app to run a virtual environment under: 
 <pre> 
 pw group add pydev 
 pw user add pydev -m -g pydev -s /usr/local/bin/bash -c "Python Dev" 
 </pre> 

 * Switch to the pydev user: 
 <pre> 
 su - pydev 
 </pre> 

 * Create a virtualenv for python_app: 
 <pre> 
 mkdir ~/venv && cd ~/venv 
 virtualenv python_app 
 </pre> 

 * Activate the python_app virtualenv: 
 <pre> 
 source ~/venv/python_app/bin/activate 
 </pre> 

 * Install your python app, this example just installs django: 
 <pre> 
 pip install Django 
 django-admin.py startproject python_app 
 cd python_app 
 </pre> 

 * Initialize the SQLite database: 
 <pre> 
 pip install pysqlite 
 ./manage.py migrate 
 </pre> 

 * Create an administrative user for the python_app: 
 ./manage.py createsuperuser 

 * Create a wsgi config file for the python_app: 
 <pre> 
 vi ~/python_app/wsgi.ini 
 </pre> 
 #* And add the following: 
 <pre> 
 [uwsgi] 
 master            = true 
 processes         = 10 
 chdir             = /home/pydev/python_app 
 module            = python_app.wsgi 
 home              = /home/pydev/venv/python_app 
 vacuum            = true 
 </pre> 

 * Exit from the pydev user session, back into the root session: 
 <pre> 
 exit 
 </pre> 

 * Start and enable uwsgi at boot with additional arguments to specify a www profile: 
 <pre> 
 echo 'uwsgi_enable="YES"' >> /etc/rc.conf 
 echo 'uwsgi_profiles="www"' >> /etc/rc.conf 
 echo 'uwsgi_www_socket="/tmp/www_uwsgi.sock"' >> /etc/rc.conf 
 echo 'uwsgi_www_uid="1004"' >> /etc/rc.conf 
 echo 'uwsgi_www_gid="1004"' >> /etc/rc.conf 
 echo 'uwsgi_www_flags="-M -L --ini /home/pydev/python_app/wsgi.ini"' >> /etc/rc.conf 
 service uwsgi start 
 </pre> 

 h2. Python Website 

 * Add a *python.example.com server block*: 
 <pre> 
 vi /usr/local/etc/nginx/conf.d/python.example.com.conf 
 </pre> 
 #* Add the following: 
 <pre> 
 upstream django { 
    server unix:/tmp/www_uwsgi.sock; 
 } 

 server { 
     listen         80; 
     server_name    python.example.com; 
     access_log     /var/log/python.example.com-access.log; 
     error_log      /var/log/python.example.com-error.log; 

     location /media    { 
         alias /home/pydev/python_app/media; 
     } 

     location /static { 
         alias /home/pydev/python_app/static; 
     } 

     location / { 
         uwsgi_pass    django; 
         include       /usr/local/etc/nginx/uwsgi_params; 
     } 
 } 
 </pre> 

 * Restart nginx to apply the configuration: 
 <pre> 
 service nginx restart 
 </pre> 

 --- 

 h1. Securing Nginx With SSL 

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

 * Install OpenSSL: 
 <pre> 
 pkg install openssl 
 </pre> 

 * Setup the Diffie-Hellman Key Exchange Parameters 
 <pre> 
 cd /usr/local/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 /usr/local/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, like a CA intermediate bundle, add them together like so: 
 <pre> 
 cd /usr/local/etc/nginx 
 cat www.example.com.crt startcom.class1.bundle > www.example.com.chained.crt 
 </pre> 

 * Setup the default site configuration: 
 <pre> 
 vi /usr/local/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 /usr/local/etc/nginx/www.example.com.crt; 
     ssl_certificate_key /usr/local/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 /usr/local/etc/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 /usr/local/www/; 
     index index.html index.htm; 
     autoindex on; 
 } 
 </pre> 

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

 h1. Resources 

 * http://www.bsdnow.tv/tutorials/nginx 
 * http://forums.freebsd.org/viewtopic.php?t=30268 
 * https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html 
 * http://uwsgi-docs.readthedocs.io/en/latest/tutorials/Django_and_nginx.html

Back