Nginx
From charlesreid1
I finally got fed up with Apache's endless permissions problems and incomprehensible labyrinth of config files and virtualhosts that never, ever work, ever, not even a single time.
I switched to nginx.
Also see Gunicorn page for running Python apps on top of nginx.
You can also run nginx with Apache. I did this because, as much as I hate Apache, all things PHP (MediaWiki and Wordpress and Mysqlaadmin) integrate better with it. So I set up nginx as a reverse proxy, so that any requests sent to nginx that are for the wiki or for wordpress are sent through to apache. Nginx Apache page has details.
Contents
Installing
Ubuntu
sudo apt-get install nginx
Basic Info
By default, nginx serves files out of
/usr/share/nginx/html
The default config file is located in
/etc/nginx/sites-available/default
To start/stop nginx, use it as a service,
sudo service nginx start sudo service nginx stop
It is generally a good idea to add virtual servers into the default configuration file, despite what I do below.
Virtual Hosts
Directory Structure and Permissions
I have created two http root directories, to serve two virtual hosts:
/www/example.com/public_html/ /www/test.com/public_html/
Both contain an index.html file with a simple hello world message.
Now I transfer ownership of these two directories to my regular username,
sudo chown -R $USER:$USER /www/example.com/public_html sudo chown -R $USER:$USER /www/test.com/public_html sudo chmod -R 755 /www/
Config File
Create a copy of the config file for each site:
sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/example.com sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/test.com
The contents:
example.com config file
/etc/nginx/sites-available/example.com -------------------------- server { listen 80; listen [::]:80; root /www/example.com/public_html; index index.html index.htm; server_name example.com www.example.com; location / { try_files $uri $uri/ =404; } }
test.com config file
/etc/nginx/sites-available/test.com -------------------------- server { listen 80 default_server; listen [::]:80 default_server ipv6only=on; root /www/test.com/public_html; index index.html index.htm; server_name test.com www.test.com; location / { try_files $uri $uri/ =404; } }
Enabling Site/Site Config
To enable the site whose config files we just created, we create symlinks in nginx's sites-enabled:
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/ sudo ln -s /etc/nginx/sites-available/test.com /etc/nginx/sites-enabled/
Then restart the nginx service:
sudo service nginx restart
Changing Hash Bucket Size
Mentioned by [1]. Edit the nginx config file:
sudo vim /etc/nginx/nginx.conf
and uncomment this line:
server_names_hash_bucket_size 64;
Restarting nginx to Implement Changes
sudo service nginx restart
Works
Works like a dream!
Virtual Hosts Revisited
I wasn't able to successfully implement virtual hosts with nginx using the procedure above, so I gave it another shot using the procedure outlined below.
Domain Records
I have two domains, doxuments.com and doxcompany.com, through NameCheap. I log in to name cheap and change the domain records of each domain.
For each domain, I create an A Name record for @ and an A Name record for www. Both point to the IP address of the server running nginx.
This makes two IP addresses, with two A Name records each, all pointing to the same IP address.
A.B.C.D
Set Permissions
I have two sites, served by a single instance of nginx out of two directories, /www/domain.com
and /www/domain2.com
. The permissions on these folders are set following [2]:
$ sudo chown -R www-data:www-data domain.com/ domain2.com/ $ sudo chmod 755 domain.com/ domain2.com/
Now onto the nginx settings.
Nginx
I change the domain records so that I have two domains, domain.com and domain2.com, pointing to the same server - one single IP address.
$ cd /etc/nginx/sites-available/ $ cat domain.com server { listen 80; listen [::]:80; root /www/domain.com/htdocs; index index.html index.htm; server_name domain.com; location / { try_files $uri $uri/ =404; } } $ cat domain2.com server { listen 80; listen [::]:80; root /www/domain2.com/htdocs; index index.html index.htm; server_name domain2.com; location / { try_files $uri $uri/ =404; } }
domain.com points to /www/domain.com/htdocs
and domain2.com points to /www/omain2.com/htdocs
. Couldn't be simpler.
Enable site
I enable these sites by copying these sites-available files to the sites-enabled folder:
$ cd /etc/nginx/sites-enabled $ sudo ln -fs ../sites-available/domain.com $ sudo ln -fs ../sites-available/domain2.com
Restart Nginx
Now restart the nginx service.
$ sudo service nginx restart
Works!
And whaddya know, it works.
Using /www
If you want to use a particular directory structure, like /www/htdocs
, you can do it this way:
Edit the file corresponding to the desired site name, something like /etc/nginx/sites-available/basic
. Change the line:
root /www/htdocs;
to reflect whatever directory structure you want. Then restart the service:
sudo service nginx restart
and you're off!
Secure Directories
Add Secure Directory to Nginx Config File
To secure a directory, add the following to your nginx sites-available configuration file's server
block:
server { [....] location /media { root /www/; index index.html index.htm; autoindex on; # htaccess auth_basic "Restricted"; auth_basic_user_file /etc/nginx/.htpasswd; } [.....] }
Create Credentials for Secure Directory
Now you can create user credentials in the file /etc/nginx/.htpasswd
and those credentials can be used to access the restricted location.
To add user to a new httpassd file:
htpasswd -c /etc/nginx/.htpasswd username
you will then be prompted for a password.
If you already have a password file:
htpasswd /etc/nginx/.htpasswd username
This will prompt you for a password. It will then be appended to the existing password file.
Using HTTPS/SSL with Nginx
!!!!!!!!!!!!!!!!!!!!!!! WARNING: OUTDATED INFORMATION. USE LETS ENCRYPT. !!!!!!!!!!!!!!!!!!!!!!
This is a three step procedure.
First, you'll create a self-signed certificate request for a commercial SSL certificate company to grant you a certificate.
Second, you'll purchase a certificate from a third party. I used thesslstore.com and was pretty happy with the price. It'll set you back about $18 for one year or $40 for three years, which all in all is pretty reasonable, considering these things can be thousands of dollars.
Third, you'll use the certificates provided by the Certificate Authority (thesslstore.com in this case) with the key you used to create the certificate request to do SSL with Nginx. This will require a few changes to the Nginx configuration file.
So, let's get started!
Creating Self-Signed Request
Equivalent to saying "trust me" at the end of every sentence.
Linux.com guide to creating a self-signed certificate: https://www.linux.com/learn/creating-self-signed-ssl-certificates-apache-linux
This will result in a key file (private key) and a certificate file (public key). These are specified in the server block that listens on 443 and implements HTTPS/SSL.
Purchasing Certificate
This is another process that broke down into several steps.
First, purchase a cheap certificate.
Then, verify I am the owner of the web domain.
Next, submit my certificate request.
Finally, download and extract the certificates.
Using Certificates with Nginx HTTPS/SSL
HTTPS Most Of The Things
Use a 301 to redirect requests to a safer and more secure protocol.
For example, you can turn specific requests into HTTPS, e.g., a login page:
server { listen 80; ... location /login { return 301 https://domain.com$request_uri; } ... }
Alternatively, you can turn everything into HTTPS:
server { listen 80 default; server_name www.domain.com domain.com access_log off; error_log off; return 301 https://$server_name$request_uri; }
Nginx and Git
Redirecting Subdomains to Ports: Gitea
If you have apps running on other ports (I have a pseudo-Github service called Gitea running on port 3000), you can redirect certain requests to that port and let that app handle serving up HTTP content. Note this is similar to the way we reverse-proxy requests to a local-only Apache server and let Nginx handle caching, whitelisting, etc.
I created an A Name record for a subdomain, git.domain.com
, to point to the server running Nginx. I then created a server block that listens for requests for that subdomain, and redirects requests to HTTPS on port 3000, which is where the Gitea service takes over. It uses Go, and has an HTTP handler built in. Requests to git.domain.com
are rewritten to domain.com:3000
and sent off to Gitea.
Gitea expects HTTPS requests, but git.charlesreid1.com
expects HTTP or HTTPS. So add two nginx configuration blocks:
server { # Rewrite requests for git.domain.com to https://domain.com:3000 listen 80; server_name git.domain.com; return 301 https://domain.com:3000$request_uri; } server { listen 443; server_name git.domain.com; location / { proxy_pass https://domain.com:3000; } }
Note that these can be defined in addition to any other servers listening on the same ports (80 and 443). They cannot and should not, however, listen on the same port as the app they're directing to (3000 in this case). One app at a time...
Note
Question: is it possible for nginx to intercept requests for particular files, and serve as a kind of proxy server? (Maybe that answers my question - maybe you need a proxy server.)