Installing and Configuring nginx on CentOS 7
nginx has been my default web server for a few years. The config is readable and it copes with a lot of connections without tuning. Coming from Ubuntu, though, CentOS 7 always catches me out: no nginx in the base repos, firewalld closed, SELinux blocking files. Here's how I set it up, on a box where you have sudo (a DNS name is optional, an IP works for testing).
The repository
EPEL carries nginx too, but it lags behind. I use nginx.org's stable branch (1.12 at the moment). Create /etc/yum.repos.d/nginx.repo:
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1
Then install:
sudo yum -y install nginx
nginx -v
You should see nginx version: nginx/1.12.0 or later.
Start it
sudo systemctl enable nginx
sudo systemctl start nginx
sudo systemctl status nginx
The main config is /etc/nginx/nginx.conf, which includes every *.conf in /etc/nginx/conf.d/. The default site is conf.d/default.conf, root /usr/share/nginx/html.
Firewall
firewalld blocks everything except SSH by default. Open HTTP and HTTPS permanently and reload:
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
sudo firewall-cmd --list-services
At this point curl -I http://your-server-ip/ from another machine should return HTTP/1.1 200 OK and Server: nginx/1.12.0.
One server block per site
I keep one file per site in conf.d and one document root per site under /var/www. It's boring and it scales. Make the directory and a test page:
sudo mkdir -p /var/www/example.com/html
echo '<h1>example.com works</h1>' | sudo tee /var/www/example.com/html/index.html
sudo chown -R nginx:nginx /var/www/example.com
Then create /etc/nginx/conf.d/example.com.conf:
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com/html;
index index.html;
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
location / {
try_files $uri $uri/ =404;
}
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 30d;
add_header Cache-Control "public";
}
}
Rename the default server block so it does not conflict (mv default.conf default.conf.disabled) or leave it as the catch-all for requests with an unknown Host header.
SELinux
Ubuntu people forget this one. With SELinux enforcing, nginx can only read files labelled httpd_sys_content_t. /usr/share/nginx/html and /var/www get it by default, but a directory somewhere else, or files moved from a home directory with mv (which keeps the old label), gives you 403s. Make the label permanent and apply it:
sudo semanage fcontext -a -t httpd_sys_content_t "/var/www(/.*)?"
sudo restorecon -Rv /var/www
If nginx also needs to proxy to a backend, allow outbound connections:
sudo setsebool -P httpd_can_network_connect 1
Test, then reload
sudo nginx -t
sudo systemctl reload nginx
nginx -t prints syntax is ok and test is successful. I always run it before a reload. A bad config on reload fails harmlessly, but on restart it leaves you with no web server.
Does it serve?
curl -H "Host: example.com" http://127.0.0.1/
curl -I http://example.com/
sudo tail -f /var/log/nginx/example.com.access.log
The first should return your test HTML regardless of DNS. Watch the access log while you load the site in a browser to confirm requests hit the right block.
Gotchas
403 Forbiddenwith(13: Permission denied)in the error log is almost always SELinux labelling. Checkls -Z /var/www/example.com/htmlforhttpd_sys_content_t;ausearch -m avc -ts recentshows the denials.nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)means Apache (httpd) is running.systemctl disable --now httpd.nginx: [warn] conflicting server name "example.com" on 0.0.0.0:80, ignoredmeans two blocks claim the same name, usually a leftoverdefault.conf.- Works with
curlon the server but times out remotely: firewalld. Checkfirewall-cmd --list-alland that you ran--reloadafter the--permanentchanges. I've done that one more than once.