Goal
Set up an online server and get it to return "Hello World" in response to an HTTP request.
Components: DigitalOcean (a cloud server provider), Nginx (a web server), Gunicorn (a Python WSGI web server), and Python (a programming language).
Contents
- Goal
- Contents
- Brief Summary
- Summary
- Notes
- Project Log
Brief Summary
Hello World achieved. Encountered some difficulty configuring Nginx to a) serve a static file containing "hello world" b) to connect to Gunicorn, both of which turned out to be mainly due to SELinux permission settings.
Summary
Hello World achieved. Encountered some difficulty configuring Nginx to a) serve a static file containing "hello world" b) to connect to Gunicorn, both of which turned out to be mainly due to SELinux permission settings.
Steps taken:
- Studied the utility of using Nginx as a reverse proxy in front of Gunicorn. Essentially, this utility is the fact that Nginx handles the slow client problem by buffering requests until they're completed.
- Created a new VPS (running CentOS 7.6 x64) on DigitalOcean, with ssh access from my local workstation Shovel. I set the domain edgecasesystems.com to point to this VPS.
- Studied some of the main differences between Apache and Nginx.
- Using the Yum package manager:
-- I installed the CentOS 7 EPEL repository (version 7-11).
-- I installed Nginx (version 1.12.2).
--- This included integration with systemd, so that commands such as
systemctl start nginx
work. I enabled Nginx via
systemctl enable nginx
and confirmed that it starts on boot by power cycling the VPS. - I browsed to http://edgecasesystems.com, which displayed the default Nginx welcome page, located at /usr/share/nginx/html/index.html.
- I chose:
/srv/edgecase/www
as my root directory for web content.
- Studied some basics of Nginx configuration.
-- The command
nginx -t
will check nginx.conf for syntax errors. -- I needed Nginx to load various new configurations. The command
systemctl reload nginx
did not work. The command
systemctl restart nginx
did.
-- The access log and error log file paths are set in the Nginx configuration file /etc/nginx/nginx.conf. By default, they were
/var/log/nginx/error.log
and
/var/log/nginx/access.log
. I read the most recent error / access via
tail
e.g.
tail -1 /var/log/nginx/error.log
. - I created a text file containing "hello world" in /srv/edgecase/www and configured nginx to serve it (and to use it as an index page). However, when I browsed to http://edgecasesystems.com/test.txt, I got a 403 Forbidden error. Some research showed that it was probably due to a default SELinux restriction that prevents webservers accessing anything outside particular directories such as /var/www.
- I created a text file containing "hello world" in /var/www/edgecase/basic to see if working from /var/www would solve the problem. I changed the Nginx configuration to match. However, I got the same 403 Forbidden error.
- I used the command
chcon -t httpd_sys_rw_content_t /var/www/ -R
to change the SELinux permissions on the directory /var/www and its descendants. The setting
httpd_sys_rw_content_t
allows webserver ("httpd") services to read / write from /var/www. - I recalled that Nginx had originally been able to serve its default page at /usr/share/nginx/html/index.html. Using the command
ls -Z /usr/share/nginx
to check this directory's SELinux permissions, I could see that it only had the
httpd_sys_content_t
setting. Presumably, this is only read permission, not read / write permission, and I could have limited myself to that setting in the previous step. - I browsed to http://edgecasesystems.com and got "hello world".
- I deleted /var/www/edgecase and moved back to working at /srv/edgecase. I changed the Nginx configuration to match. I changed the SELinux permission on /srv/edgecase/www to
httpd_sys_content_t
, using the command
chcon -v --type=httpd_sys_content_t www -R
. The command
curl http://edgecasesystems.com/test.txt
produced the result "hello world".
- Using the Yum package manager, I installed pip 8.1.2.
- Using the Pip package manager, I installed gunicorn (version 19.9.0).
- I created an example test.py Python file for Gunicorn to serve, which returned "Hello, World!".
- I was able to start the Gunicorn server manually (serving on localhost:8080) using the command
gunicorn --bind=localhost:8080 --workers=1 test:app
and
curl
"Hello, World!" from it. In this case,
curl
was run on the VPS i.e. the same machine as the running Gunicorn server. I found that Gunicorn could also serve to the wider net when started with the command
gunicorn --bind=edgecasesystems.com:8080 --workers=1 test:app
. - I configured Nginx to act as a proxy and pass all its requests to Gunicorn. I browsed to http://edgecasesystems.com and got "nginx error!". The Nginx error log showed "13: Permission denied". Disabling the SELinux setting "httpd_can_network_connect" allowed the Nginx server to connect to the Gunicorn server via HTTP.
- I decided to switch to using a Unix socket instead of a network connection. I re-enabled the SELinux setting "httpd_can_network_connect".
- I configured Gunicorn to use a socket located at /tmp/gunicorn.sock and started it using the command
gunicorn --bind=unix:/tmp/gunicorn.sock --workers=1 test:app
.I was able to
curl
"Hello, World!" from the socket using the commands
curl --unix-socket /tmp/gunicorn.sock http://test
or
curl --unix-socket /tmp/gunicorn.sock h
(but not
curl --unix-socket /tmp/gunicorn.sock
). - I configured Nginx to pass its requests to this socket. I browsed to http://edgecasesystems.com and got "nginx error!". The Nginx error log showed "2: No such file or directory". This was strange. I confirmed that the socket file existed at /tmp/gunicorn.sock.
- I learned that sockets can't be placed in /tmp, as they can't be seen by other processes:
Excerpt from:
serverfault.com/questions/463993/nginx-unix-domain-socket-error/464025#464025
You can't place sockets intended for interprocess communication in/tmp.
For security reasons, recent versions of Fedora use namespaced temporary directories [ http://fedoraproject.org/wiki/Features/ServicesPrivateTmp ], meaning every service sees a completely different/tmpand can only see its own files in that directory.
To resolve the issue, place the socket in a different directory, such as/run(formerly known as/var/run).
answered Jan 8 '13 at 14:41
Michael Hampton
- I changed the location of the socket from /tmp/gunicorn.sock to /run/gunicorn.sock. I changed the Nginx configuration to match. I browsed to http://edgecasesystems.com and got "nginx error!". The Nginx error log showed "13: Permission denied". The nginx server could now see the socket, but it didn't have permission to connect to it.
- Disabling SELinux allowed Nginx to connect to the socket. Using
curl
to get "Hello, World!" from edgecasesystems.com worked. - I changed the SELinux label on /run/gunicorn.sock from "var_run_t" to "httpd_sys_content_t" using the command
semanage fcontext -a -t httpd_sys_content_t /var/run/gunicorn.sock
.This didn't work, but perhaps it allowed the next step to work.
- I generated a new SELinux policy for nginx using the command
grep nginx /var/log/audit/audit.log | audit2allow -M nginx
.The -M flag caused this policy to be compiled and saved. The audit2allow tool takes in records of failed access attempts (stored in the SELinux log at /var/log/audit/audit.log) and uses them to generate the new policy.
- I activated the policy using
semodule -i nginx.pp
and confirmed its inclusion using
semodule -l | grep nginx
. - I browsed to http://edgecasesystems.com and got "Hello, World!".
The Notes section contains the following parts:
- Acronyms
- System details
- Summary of an explanation of the slow client problem and how Nginx can handle it when used as a reverse proxy
- Original and final Nginx configurations
Notes
Parts
- Acronyms
- System details
- Summary of an explanation of the slow client problem and how Nginx can handle it when used as a reverse proxy
- Original and final Nginx configurations
Acronyms
HTTP = HyperText Transfer Protocol
WSGI = Web Server Gateway Interface
IP = Internet Protocol
DNS = Domain Name System
VPS = Virtual Private Server
System details
Local workstation details:
- Name: Shovel
- Specifications: HP 6005 Pro SFF. 3 GHz x86_64 processor (AMD II x4 B95 Quad Core), 4 GB RAM, 1 TB hard drive. Running CentOS 7.6.1810 (Core).
- More information: New computer: Shovel
- Installed items: GCC 4.8.5, Make 3.82, Vim 7.4, Python 2.7.5, Python 3.3.2, Gnome 3.28.2, gedit 3.28.1, GPG 1.4.10.
DigitalOcean Droplet (VPS) details:
- Distribution = CentOS 7.6 x64
- Choose a plan = Standard
- Memory = 1 GB
- vCPUS = 1 vCPU
- SSD Disk = 25 GB
- Transfer = 1000 GB
- Price = $5/mo, $0.007/hr
- Datacentre region = London
- hostname = edgecase2
Summary of an explanation of the slow client problem and how Nginx can handle it when used as a reverse proxy
I'll rewrite / summarise this source
www.brianstorti.com/the-role-of-a-reverse-proxy-to-protect-your-application-against-slow-clients
Author: Brian Storti
which explains the slow client problem and how to use a reverse proxy to handle it.
Summary
Some application servers, such as Unicorn (and Gunicorn), use a "forking model", which means that a new process is spawned in order to handle a new request.
A "slow client" is a user accessing the application via a slow connection. This connection could actually be slow (e.g. a mobile network connection) or an attacker could artificially cause his client's responses to be slow.
Scenario: A slow client tries to send a large request e.g. an upload of a 5MB file. The application server spawns a new process to handle this request. This process will be blocked, and remain idle, while the data is slowly received. Similarly, when the process sends a response back to the client, it will be blocked / idle while the client slowly receives the response data.
There is a finite limit on the number of simultaneous server processes. When all of them are busy (perhaps just handling requests from slow clients), the entire application stops receiving new requests, even though it's not actually doing much work.
A reverse proxy (e.g. Nginx) can be placed in front of the application server and be used as a buffering system. It can handle an enormous number of simultaneous requests and is not affected by slow clients.
Nginx uses a non-blocking Evented I/O model, in which a read call (an I/O operation) is performed in order to handle a new request. The "wait until request is finished" job is passed to the operating system, and the Nginx process is immediately ready to handle a new request. When the read operation finishes, the operating system sends an event notification to Nginx, which will then pass the entire request to the application server.
The application server never needs to wait for a slow request to be completed. Nginx buffers requests until they are finished, then passes them to the application server, which will process them and return a response. Nginx also buffers outgoing responses in the same way that it buffers incoming requests.
End Summary
Original and final Nginx configurations
Original configuration:
/etc/nginx/nginx.conf
# For more information on configuration, see:
# * Official English Documentation: http://nginx.org/en/docs/
# * Official Russian Documentation: http://nginx.org/ru/docs/
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf;
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
# Settings for a TLS enabled server.
#
# server {
# listen 443 ssl http2 default_server;
# listen [::]:443 ssl http2 default_server;
# server_name _;
# root /usr/share/nginx/html;
#
# ssl_certificate "/etc/pki/nginx/server.crt";
# ssl_certificate_key "/etc/pki/nginx/private/server.key";
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 10m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
#
# # Load configuration files for the default server block.
# include /etc/nginx/default.d/*.conf;
#
# location / {
# }
#
# error_page 404 /404.html;
# location = /40x.html {
# }
#
# error_page 500 502 503 504 /50x.html;
# location = /50x.html {
# }
# }
}
Final configuration:
/etc/nginx/nginx.conf
# For more information on configuration, see:
# * Official English Documentation: http://nginx.org/en/docs/
# * Official Russian Documentation: http://nginx.org/ru/docs/
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf;
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /srv/edgecase/www;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
proxy_pass http://unix:/run/gunicorn.sock;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
# Settings for a TLS enabled server.
#
# server {
# listen 443 ssl http2 default_server;
# listen [::]:443 ssl http2 default_server;
# server_name _;
# root /usr/share/nginx/html;
#
# ssl_certificate "/etc/pki/nginx/server.crt";
# ssl_certificate_key "/etc/pki/nginx/private/server.key";
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 10m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
#
# # Load configuration files for the default server block.
# include /etc/nginx/default.d/*.conf;
#
# location / {
# }
#
# error_page 404 /404.html;
# location = /40x.html {
# }
#
# error_page 500 502 503 504 /50x.html;
# location = /50x.html {
# }
# }
}
The key section that has changed is this:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /srv/edgecase/www;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
proxy_pass http://unix:/run/gunicorn.sock;
}
Notes:
- Use spaces, not tabs, for nginx.conf spacing.
- Use
nginx -t
to check nginx.conf for syntax errors. Project Log
Components: DigitalOcean (a cloud server provider), Nginx (a web server), Gunicorn (a Python WSGI web server), and Python (a programming language).
Let's go through these components.
They form a series of layers, in this order:
- DigitalOcean
- Nginx
- Gunicorn
- Python [hello world application code]
Here is the sequence of events (in my current understanding):
- An HTTP request will be sent to a particular destination IP address by a client at a source IP address.
- The destination IP address is linked to a particular server via the DNS system. The request will arrive at this server. In this project, the server will be a virtual machine running on the DigitalOcean cloud platform.
- The HTTP request will be directed to port 80 on the server. The server will pass the request to the Nginx server, which will be listening at port 80.
- The Nginx server will buffer HTTP requests and, when they are completely received, pass them to the Gunicorn server. In this case, the Nginx server is acting as a reverse proxy, preventing any slow clients from overloading the Gunicorn server.
- The Gunicorn server will translate the HTTP request into a Python dictionary and pass the result to a pre-forked worker process, which will have already have the Python interpreter loaded up and ready to run.
- The worker process will use the Python interpreter to execute the Python hello world application code, which will process the HTTP request data and produce a response.
- The response will be passed back along the chain of components and sent back to the source IP address that originally made the HTTP request.
Links:
www.fullstackpython.com/green-unicorn-gunicorn.html
www.brianstorti.com/the-role-of-a-reverse-proxy-to-protect-your-application-against-slow-clients
docs.gunicorn.org/en/stable/deploy.html
www.nginx.com/resources/wiki
I'll rewrite / summarise this source
www.brianstorti.com/the-role-of-a-reverse-proxy-to-protect-your-application-against-slow-clients
Author: Brian Storti
which explains the slow client problem and how to use a reverse proxy to handle it.
Summary
Some application servers, such as Unicorn (and Gunicorn), use a "forking model", which means that a new process is spawned in order to handle a new request.
A "slow client" is a user accessing the application via a slow connection. This connection could actually be slow (e.g. a mobile network connection) or an attacker could artificially cause his client's responses to be slow.
Scenario: A slow client tries to send a large request e.g. an upload of a 5MB file. The application server spawns a new process to handle this request. This process will be blocked, and remain idle, while the data is slowly received. Similarly, when the process sends a response back to the client, it will be blocked / idle while the client slowly receives the response data.
There is a finite limit on the number of simultaneous server processes. When all of them are busy (perhaps just handling requests from slow clients), the entire application stops receiving new requests, even though it's not actually doing much work.
A reverse proxy (e.g. Nginx) can be placed in front of the application server and be used as a buffering system. It can handle an enormous number of simultaneous requests and is not affected by slow clients.
Nginx uses a non-blocking Evented I/O model, in which a read call (an I/O operation) is performed in order to handle a new request. The "wait until request is finished" job is passed to the operating system, and the Nginx process is immediately ready to handle a new request. When the read operation finishes, the operating system sends an event notification to Nginx, which will then pass the entire request to the application server.
The application server never needs to wait for a slow request to be completed. Nginx buffers requests until they are finished, then passes them to the application server, which will process them and return a response. Nginx also buffers outgoing responses in the same way that it buffers incoming requests.
End Summary
System details:
- Name: Shovel
- Specifications: HP 6005 Pro SFF. 3 GHz x86_64 processor (AMD II x4 B95 Quad Core), 4 GB RAM, 1 TB hard drive. Running CentOS 7.6.1810 (Core).
- More information: New computer: Shovel
- Installed items: GCC 4.8.5, Make 3.82, Vim 7.4, Python 2.7.5, Python 3.3.2, Gnome 3.28.2, gedit 3.28.1, GPG 1.4.10.
Next: Create a new "droplet" (a virtual private server) on DigitalOcean.
Log in to DigitalOcean.
In DigitalOcean / Projects / edgecasesoftware, click Create, then Droplets.
I now see the "Create Droplets" interface.
Choose these droplet details:
- Distribution = CentOS 7.6 x64
- Choose a plan = Standard
- Memory = 1 GB
- vCPUS = 1 vCPU
- SSD Disk = 25 GB
- Transfer = 1000 GB
- Price = $5/mo, $0.007/hr
- Datacentre region = London
In the section "Add your SSH keys", choose "shovel" (the SSH key for my computer Shovel has already been uploaded to DigitalOcean).
Set hostname to "edgecase2".
Click Create Droplet.
I now see the Project interface. New droplet is being created.
New droplet finished. It has the IP address 46.101.86.226.
I have a spare domain listed in this project: edgecasesystems.com
Click it. The "Create new record" interface opens.
It already has 3 Nameserver records pointing to the DigitalOcean nameservers.
It also has an A record left over from a previous project.
Edit the A record. Set it to point to "edgecase2".
"TTL (Seconds)" is set to 3600.
3600 seconds = 1 hour.
Click Save.
Open a terminal.
[spiano@localhost ~]$ ping 46.101.86.226
PING 46.101.86.226 (46.101.86.226) 56(84) bytes of data.
64 bytes from 46.101.86.226: icmp_seq=1 ttl=54 time=34.0 ms
64 bytes from 46.101.86.226: icmp_seq=2 ttl=54 time=22.9 ms
64 bytes from 46.101.86.226: icmp_seq=3 ttl=54 time=33.7 ms
^C
--- 46.101.86.226 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 22.910/30.251/34.060/5.192 ms
[spiano@localhost ~]$ ping edgecasesystems.com
PING edgecasesystems.com (139.59.182.146) 56(84) bytes of data.
64 bytes from 139.59.182.146 (139.59.182.146): icmp_seq=1 ttl=54 time=20.3 ms
64 bytes from 139.59.182.146 (139.59.182.146): icmp_seq=2 ttl=54 time=19.7 ms
64 bytes from 139.59.182.146 (139.59.182.146): icmp_seq=3 ttl=54 time=19.5 ms
64 bytes from 139.59.182.146 (139.59.182.146): icmp_seq=4 ttl=54 time=20.8 ms
^C
--- edgecasesystems.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3005ms
rtt min/avg/max/mdev = 19.543/20.123/20.869/0.512 ms
The IP addresses are different. The A record change has not yet propagated.
time: 08:43
time: 09:23
ping edgecasesystems.com
still hits 139.59.182.146. time: 09:59
ping edgecasesystems.com
now hits 46.101.86.226. From Shovel, log in to VPS.
[spiano@localhost ~]$ ssh root@edgecasesystems.com
The authenticity of host 'edgecasesystems.com (46.101.86.226)' can't be established.
ECDSA key fingerprint is SHA256:LKLzCfqqB7NQLA2qKNgkBcObeYd3qmCR7gbGXSXoPok.
ECDSA key fingerprint is MD5:36:4d:35:df:54:5f:ce:de:ce:23:0b:16:ee:97:86:51.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'edgecasesystems.com,46.101.86.226' (ECDSA) to the list of known hosts.
[root@edgecase2 ~]#
Next: Install Nginx on edgecase2 VPS and test it.
Links:
www.digitalocean.com/community/tutorials/nginx-essentials-installation-and-configuration-troubleshooting
www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-16-04
www.digitalocean.com/community/tutorials/apache-vs-nginx-practical-considerations
www.digitalocean.com/community/tutorials/understanding-nginx-server-and-location-block-selection-algorithms
Excerpts from:
www.digitalocean.com/community/tutorials/apache-vs-nginx-practical-considerations
Posted: January 28, 2015
Author: Justin Ellingwood
In 2002, Igor Sysoev began work on Nginx as an answer to the C10K problem, which was a challenge for web servers to begin handling ten thousand concurrent connections as a requirement for the modern web. The initial public release was made in 2004, meeting this goal by relying on an asynchronous, events-driven architecture.
Nginx has grown in popularity since its release due to its light-weight resource utilization and its ability to scale easily on minimal hardware. Nginx excels at serving static content quickly and is designed to pass dynamic requests off to other software that is better suited for those purposes.
[...]
Nginx came onto the scene after Apache, with more awareness of the concurrency problems that would face sites at scale. Leveraging this knowledge, Nginx was designed from the ground up to use an asynchronous, non-blocking, event-driven connection handling algorithm.
Nginx spawns worker processes, each of which can handle thousands of connections. The worker processes accomplish this by implementing a fast looping mechanism that continuously checks for and processes events. Decoupling actual work from connections allows each worker to concern itself with a connection only when a new event has been triggered.
Each of the connections handled by the worker are placed within the event loop where they exist with other connections. Within the loop, events are processed asynchronously, allowing work to be handled in a non-blocking manner. When the connection closes, it is removed from the loop.
This style of connection processing allows Nginx to scale incredibly far with limited resources. Since the server is single-threaded and processes are not spawned to handle each new connection, the memory and CPU usage tends to stay relatively consistent, even at times of heavy load.
[...]
Nginx does not have any ability to process dynamic content natively. To handle PHP and other requests for dynamic content, Nginx must pass to an external processor for execution and wait for the rendered content to be sent back. The results can then be relayed to the client.
For administrators, this means that communication must be configured between Nginx and the processor over one of the protocols Nginx knows how to speak (http, FastCGI, SCGI, uWSGI, memcache). This can complicate things slightly, especially when trying to anticipate the number of connections to allow, as an additional connection will be used for each call to the processor.
However, this method has some advantages as well. Since the dynamic interpreter is not embedded in the worker process, its overhead will only be present for dynamic content. Static content can be served in a straight-forward manner and the interpreter will only be contacted when needed.
[...]
For administrators, one of the most readily apparent differences between these two pieces of software is whether directory-level configuration is permitted within the content directories.
Apache
Apache includes an option to allow additional configuration on a per-directory basis by inspecting and interpreting directives in hidden files within the content directories themselves. These files are known as.htaccessfiles.
Since these files reside within the content directories themselves, when handling a request, Apache checks each component of the path to the requested file for an.htaccessfile and applies the directives found within. This effectively allows decentralized configuration of the web server, which is often used for implementing URL rewrites, access restrictions, authorization and authentication, even caching policies.
While the above examples can all be configured in the main Apache configuration file,.htaccessfiles have some important advantages. First, since these are interpreted each time they are found along a request path, they are implemented immediately without reloading the server. Second, it makes it possible to allow non-privileged users to control certain aspects of their own web content without giving them control over the entire configuration file.
This provides an easy way for certain web software, like content management systems, to configure their environment without providing access to the central configuration file. This is also used by shared hosting providers to retain control of the main configuration while giving clients control over their specific directories.
Nginx
Nginx does not interpret.htaccessfiles, nor does it provide any mechanism for evaluating per-directory configuration outside of the main configuration file. This may be less flexible than the Apache model, but it does have its own advantages.
The most notable improvement over the.htaccesssystem of directory-level configuration is increased performance. For a typical Apache setup that may allow.htaccessin any directory, the server will check for these files in each of the parent directories leading up to the requested file, for each request. If one or more.htaccessfiles are found during this search, they must be read and interpreted. By not allowing directory overrides, Nginx can serve requests faster by doing a single directory lookup and file read for each request (assuming that the file is found in the conventional directory structure).
Another advantage is security related. Distributing directory-level configuration access also distributes the responsibility of security to individual users, who may not be trusted to handle this task well. Ensuring that the administrator maintains control over the entire web server can prevent some security missteps that may occur when access is given to other parties.
[...]
Nginx
Nginx was created to be both a web server and a proxy server. Due to the architecture required for these two roles, it works primarily with URIs, translating to the filesystem when necessary.
This can be seen in some of the ways that Nginx configuration files are constructed and interpreted. Nginx does not provide a mechanism for specifying configuration for a filesystem directory and instead parses the URI itself.
For instance, the primary configuration blocks for Nginx areserverandlocationblocks. Theserverblock interprets the host being requested, while thelocationblocks are responsible for matching portions of the URI that comes after the host and port. At this point, the request is being interpreted as a URI, not as a location on the filesystem.
For static files, all requests eventually have to be mapped to a location on the filesystem. First, Nginx selects the server and location blocks that will handle the request and then combines the document root with the URI, adapting anything necessary according to the configuration specified.
[...]
Parsing requests primarily as URIs instead of filesystem locations allows Nginx to more easily function in both web, mail, and proxy server roles. Nginx is configured simply by laying out how to respond to different request patterns. Nginx does not check the filesystem until it is ready to serve the request, which explains why it does not implement a form of.htaccessfiles.
[...]
Nginx also implements a module system, but it is quite different from the Apache system. In Nginx, modules are not dynamically loadable, so they must be selected and compiled into the core software.
For many users, this will make Nginx much less flexible. This is especially true for users who are not comfortable maintaining their own compiled software outside of their distribution's conventional packaging system. While distributions' packages tend to include the most commonly used modules, if you require a non-standard module, you will have to build the server from source yourself.
Nginx modules are still very useful though, and they allow you to dictate what you want out of your server by only including the functionality you intend to use. Some users also may consider this more secure, as arbitrary components cannot be hooked into the server. However, if your server is ever put in a position where this is possible, it is likely compromised already.
Nginx modules allow many of the same capabilities as Apache modules. For instance, Nginx modules can provide proxying support, compression, rate limiting, logging, rewriting, geolocation, authentication, encryption, streaming, and mail functionality.
[...]
Administrators are also somewhat more likely to have experience working with Apache not only due to its prevalence, but also because many people start off in shared-hosting scenarios which almost exclusively rely on Apache due to the.htaccessdistributed management capabilities.
[...]
Nginx is experiencing increased support as more users adopt it for its performance profile, but it still has some catching up to do in some key areas.
In the past, it was difficult to find comprehensive English-language documentation regarding Nginx due to the fact that most of the early development and documentation were in Russian. As interest in the project grew, the documentation has been filled out and there are now plenty of administration resources on the Nginx site and through third parties.
In regards to third-party applications, support and documentation is becoming more readily available, and package maintainers are beginning, in some cases, to give choices between auto-configuring for Apache and Nginx. Even without support, configuring Nginx to work with alternative software is usually straight-forward so long as the project itself documents its requirements (permissions, headers, etc).
Using Apache and Nginx Together
After going over the benefits and limitations of both Apache and Nginx, you may have a better idea of which server is more suited to your needs. However, many users find that it is possible to leverage each server's strengths by using them together.
The conventional configuration for this partnership is to place Nginx in front of Apache as a reverse proxy. This will allow Nginx to to handle all requests from clients. This takes advantage of Nginx's fast processing speed and ability to handle large numbers of connections concurrently.
For static content, which Nginx excels at, the files will be served quickly and directly to the client. For dynamic content, for instance PHP files, Nginx will proxy the request to Apache, which can then process the results and return the rendered page. Nginx can then pass the content back to the client.
This setup works well for many people because it allows Nginx to function as a sorting machine. It will handle all requests it can and pass on the ones that it has no native ability to serve. By cutting down on the requests the Apache server is asked to handle, we can alleviate some of the blocking that occurs when an Apache process or thread is occupied.
This configuration also allows you to scale out by adding additional backend servers as necessary. Nginx can be configured to pass to a pool of servers easily, increasing this configuration's resilience to failure and performance.
[root@edgecase2 ~]# nginx -v
-bash: nginx: command not found
[root@edgecase2 ~]# yum search nginx
[...]
pcp-pmda-nginx.x86_64 : Performance Co-Pilot (PCP) metrics for the Nginx
: Webserver
[...]
Excerpts from:
www.digitalocean.com/community/tutorials/how-to-install-nginx-on-centos-7
Posted: July 22, 2014
Author: Mitchell Anicas
This tutorial will teach you how to install and start Nginx on your CentOS 7 server.
[...]
Step One - Add Nginx Repository
To add the CentOS 7 EPEL repository, open terminal and use the following command:
sudo yum install epel-release
Step Two - Install Nginx
Now that the Nginx repository is installed on your server, install Nginx using the following yum command:
sudo yum install nginx
After you answer yes to the prompt, Nginx will finish installing on your virtual private server (VPS).
Step Three - Start Nginx
Nginx does not start on its own. To get Nginx running, type:
sudo systemctl start nginx
[...]
You can do a spot check right away to verify that everything went as planned by visiting your server's public IP address in your web browser.
[...]
You will see the default CentOS 7 Nginx web page, which is there for informational and testing purposes.
[...]
Before continuing, you will probably want to enable Nginx to start when your system boots. To do so, enter the following command:
sudo systemctl enable nginx
[...]
Server Root and Configuration
If you want to start serving your own pages or application through Nginx, you will want to know the locations of the Nginx configuration files and default server root directory.
Default Server Root
The default server root directory is/usr/share/nginx/html. Files that are placed in there will be served on your web server. This location is specified in the default server block configuration file that ships with Nginx, which is located at/etc/nginx/conf.d/default.conf.
Server Block Configuration
Any additional server blocks, known as Virtual Hosts in Apache, can be added by creating new configuration files in/etc/nginx/conf.d. Files that end with.confin that directory will be loaded when Nginx is started.
Nginx Global Configuration
The main Nginx configuration file is located at/etc/nginx/nginx.conf. This is where you can change settings like the user that runs the Nginx daemon processes, and the number of worker processes that get spawned when Nginx is running, among other things.
[root@edgecase2 ~]# yum repolist
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* base: mirrors.clouvider.net
* extras: mirror.mhd.uk.as44574.net
* updates: mirrors.clouvider.net
repo id repo name status
base/7/x86_64 CentOS-7 - Base 10,019
extras/7/x86_64 CentOS-7 - Extras 419
updates/7/x86_64 CentOS-7 - Updates 2,146
repolist: 12,584
[root@edgecase2 ~]# yum install epel-release
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* base: mirrors.clouvider.net
* extras: mirror.mhd.uk.as44574.net
* updates: mirrors.clouvider.net
Resolving Dependencies
--> Running transaction check
---> Package epel-release.noarch 0:7-11 will be installed
--> Finished Dependency Resolution
Dependencies Resolved
================================================================================
Package Arch Version Repository Size
================================================================================
Installing:
epel-release noarch 7-11 extras 15 k
Transaction Summary
================================================================================
Install 1 Package
Total download size: 15 k
Installed size: 24 k
Is this ok [y/d/N]: y
Downloading packages:
warning: /var/cache/yum/x86_64/7/extras/packages/epel-release-7-11.noarch.rpm: Header V3 RSA/SHA256 Signature, key ID f4a80eb5: NOKEY
Public key for epel-release-7-11.noarch.rpm is not installed
epel-release-7-11.noarch.rpm | 15 kB 00:00
Retrieving key from file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
Importing GPG key 0xF4A80EB5:
Userid : "CentOS-7 Key (CentOS 7 Official Signing Key) <security@centos.org>"
Fingerprint: 6341 ab27 53d7 8a78 a7c2 7bb1 24c6 a8a7 f4a8 0eb5
Package : centos-release-7-6.1810.2.el7.centos.x86_64 (installed)
From : /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
Is this ok [y/N]: y
]Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
Installing : epel-release-7-11.noarch 1/1
Verifying : epel-release-7-11.noarch 1/1
Installed:
epel-release.noarch 0:7-11
Complete!
[root@edgecase2 ~]# yum search nginx
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
epel/x86_64/metalink | 25 kB 00:00
* base: mirrors.clouvider.net
* epel: www.mirrorservice.org
* extras: mirror.mhd.uk.as44574.net
* updates: mirrors.clouvider.net
epel | 5.4 kB 00:00
(1/3): epel/x86_64/group_gz | 88 kB 00:00
(2/3): epel/x86_64/updateinfo | 986 kB 00:00
(3/3): epel/x86_64/primary_db | 6.8 MB 00:00
============================== N/S matched: nginx ==============================
collectd-nginx.x86_64 : Nginx plugin for collectd
munin-nginx.noarch : NGINX support for Munin resource monitoring
nextcloud-nginx.noarch : Nginx integration for NextCloud
nginx-all-modules.noarch : A meta package that installs all available Nginx
: modules
nginx-filesystem.noarch : The basic directory layout for the Nginx server
nginx-mod-http-geoip.x86_64 : Nginx HTTP geoip module
nginx-mod-http-image-filter.x86_64 : Nginx HTTP image filter module
nginx-mod-http-perl.x86_64 : Nginx HTTP perl module
nginx-mod-http-xslt-filter.x86_64 : Nginx XSLT module
nginx-mod-mail.x86_64 : Nginx mail modules
nginx-mod-stream.x86_64 : Nginx stream modules
owncloud-nginx.noarch : Nginx integration for ownCloud
pcp-pmda-nginx.x86_64 : Performance Co-Pilot (PCP) metrics for the Nginx
: Webserver
python2-certbot-nginx.noarch : The nginx plugin for certbot
nginx.x86_64 : A high performance web server and reverse proxy server
Name and summary matches only, use "search all" for everything.
[root@edgecase2 ~]# yum install nginx
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* base: mirrors.clouvider.net
* epel: www.mirrorservice.org
* extras: mirror.mhd.uk.as44574.net
* updates: mirrors.clouvider.net
Resolving Dependencies
--> Running transaction check
---> Package nginx.x86_64 1:1.12.2-3.el7 will be installed
--> Processing Dependency: nginx-all-modules = 1:1.12.2-3.el7 for package: 1:nginx-1.12.2-3.el7.x86_64
--> Processing Dependency: nginx-filesystem = 1:1.12.2-3.el7 for package: 1:nginx-1.12.2-3.el7.x86_64
--> Processing Dependency: nginx-filesystem for package: 1:nginx-1.12.2-3.el7.x86_64
--> Processing Dependency: libprofiler.so.0()(64bit) for package: 1:nginx-1.12.2-3.el7.x86_64
--> Running transaction check
---> Package gperftools-libs.x86_64 0:2.6.1-1.el7 will be installed
---> Package nginx-all-modules.noarch 1:1.12.2-3.el7 will be installed
--> Processing Dependency: nginx-mod-http-geoip = 1:1.12.2-3.el7 for package: 1:nginx-all-modules-1.12.2-3.el7.noarch
--> Processing Dependency: nginx-mod-http-image-filter = 1:1.12.2-3.el7 for package: 1:nginx-all-modules-1.12.2-3.el7.noarch
--> Processing Dependency: nginx-mod-http-perl = 1:1.12.2-3.el7 for package: 1:nginx-all-modules-1.12.2-3.el7.noarch
--> Processing Dependency: nginx-mod-http-xslt-filter = 1:1.12.2-3.el7 for package: 1:nginx-all-modules-1.12.2-3.el7.noarch
--> Processing Dependency: nginx-mod-mail = 1:1.12.2-3.el7 for package: 1:nginx-all-modules-1.12.2-3.el7.noarch
--> Processing Dependency: nginx-mod-stream = 1:1.12.2-3.el7 for package: 1:nginx-all-modules-1.12.2-3.el7.noarch
---> Package nginx-filesystem.noarch 1:1.12.2-3.el7 will be installed
--> Running transaction check
---> Package nginx-mod-http-geoip.x86_64 1:1.12.2-3.el7 will be installed
---> Package nginx-mod-http-image-filter.x86_64 1:1.12.2-3.el7 will be installed
--> Processing Dependency: gd for package: 1:nginx-mod-http-image-filter-1.12.2-3.el7.x86_64
--> Processing Dependency: libgd.so.2()(64bit) for package: 1:nginx-mod-http-image-filter-1.12.2-3.el7.x86_64
---> Package nginx-mod-http-perl.x86_64 1:1.12.2-3.el7 will be installed
--> Processing Dependency: perl >= 5.006001 for package: 1:nginx-mod-http-perl-1.12.2-3.el7.x86_64
--> Processing Dependency: perl(:MODULE_COMPAT_5.16.3) for package: 1:nginx-mod-http-perl-1.12.2-3.el7.x86_64
--> Processing Dependency: perl(Exporter) for package: 1:nginx-mod-http-perl-1.12.2-3.el7.x86_64
--> Processing Dependency: perl(XSLoader) for package: 1:nginx-mod-http-perl-1.12.2-3.el7.x86_64
--> Processing Dependency: perl(constant) for package: 1:nginx-mod-http-perl-1.12.2-3.el7.x86_64
--> Processing Dependency: perl(strict) for package: 1:nginx-mod-http-perl-1.12.2-3.el7.x86_64
--> Processing Dependency: perl(warnings) for package: 1:nginx-mod-http-perl-1.12.2-3.el7.x86_64
--> Processing Dependency: libperl.so()(64bit) for package: 1:nginx-mod-http-perl-1.12.2-3.el7.x86_64
---> Package nginx-mod-http-xslt-filter.x86_64 1:1.12.2-3.el7 will be installed
--> Processing Dependency: libxslt.so.1(LIBXML2_1.0.11)(64bit) for package: 1:nginx-mod-http-xslt-filter-1.12.2-3.el7.x86_64
--> Processing Dependency: libxslt.so.1(LIBXML2_1.0.18)(64bit) for package: 1:nginx-mod-http-xslt-filter-1.12.2-3.el7.x86_64
--> Processing Dependency: libexslt.so.0()(64bit) for package: 1:nginx-mod-http-xslt-filter-1.12.2-3.el7.x86_64
--> Processing Dependency: libxslt.so.1()(64bit) for package: 1:nginx-mod-http-xslt-filter-1.12.2-3.el7.x86_64
---> Package nginx-mod-mail.x86_64 1:1.12.2-3.el7 will be installed
---> Package nginx-mod-stream.x86_64 1:1.12.2-3.el7 will be installed
--> Running transaction check
---> Package gd.x86_64 0:2.0.35-26.el7 will be installed
--> Processing Dependency: libjpeg.so.62(LIBJPEG_6.2)(64bit) for package: gd-2.0.35-26.el7.x86_64
packet_write_wait: Connection to 46.101.86.226 port 22: Broken pipe
[spiano@localhost ~]$ ssh root@edgecasesystems.com
Last login: Thu Jul 4 09:00:46 2019 from [deleted]
[root@edgecase2 ~]# nginx -v
-bash: nginx: command not found
[root@edgecase2 ~]# yum list installed | grep epel
epel-release.noarch 7-11 @extras
[root@edgecase2 ~]# yum list installed | grep nginx
[root@edgecase2 ~]# yum install nginx
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* base: mirrors.clouvider.net
* epel: www.mirrorservice.org
* extras: mirror.mhd.uk.as44574.net
* updates: mirrors.clouvider.net
Resolving Dependencies
--> Running transaction check
---> Package nginx.x86_64 1:1.12.2-3.el7 will be installed
--> Processing Dependency: nginx-all-modules = 1:1.12.2-3.el7 for package: 1:nginx-1.12.2-3.el7.x86_64
--> Processing Dependency: nginx-filesystem = 1:1.12.2-3.el7 for package: 1:nginx-1.12.2-3.el7.x86_64
--> Processing Dependency: nginx-filesystem for package: 1:nginx-1.12.2-3.el7.x86_64
--> Processing Dependency: libprofiler.so.0()(64bit) for package: 1:nginx-1.12.2-3.el7.x86_64
--> Running transaction check
---> Package gperftools-libs.x86_64 0:2.6.1-1.el7 will be installed
---> Package nginx-all-modules.noarch 1:1.12.2-3.el7 will be installed
--> Processing Dependency: nginx-mod-http-geoip = 1:1.12.2-3.el7 for package: 1:nginx-all-modules-1.12.2-3.el7.noarch
--> Processing Dependency: nginx-mod-http-image-filter = 1:1.12.2-3.el7 for package: 1:nginx-all-modules-1.12.2-3.el7.noarch
--> Processing Dependency: nginx-mod-http-perl = 1:1.12.2-3.el7 for package: 1:nginx-all-modules-1.12.2-3.el7.noarch
--> Processing Dependency: nginx-mod-http-xslt-filter = 1:1.12.2-3.el7 for package: 1:nginx-all-modules-1.12.2-3.el7.noarch
--> Processing Dependency: nginx-mod-mail = 1:1.12.2-3.el7 for package: 1:nginx-all-modules-1.12.2-3.el7.noarch
--> Processing Dependency: nginx-mod-stream = 1:1.12.2-3.el7 for package: 1:nginx-all-modules-1.12.2-3.el7.noarch
---> Package nginx-filesystem.noarch 1:1.12.2-3.el7 will be installed
--> Running transaction check
---> Package nginx-mod-http-geoip.x86_64 1:1.12.2-3.el7 will be installed
---> Package nginx-mod-http-image-filter.x86_64 1:1.12.2-3.el7 will be installed
--> Processing Dependency: gd for package: 1:nginx-mod-http-image-filter-1.12.2-3.el7.x86_64
--> Processing Dependency: libgd.so.2()(64bit) for package: 1:nginx-mod-http-image-filter-1.12.2-3.el7.x86_64
---> Package nginx-mod-http-perl.x86_64 1:1.12.2-3.el7 will be installed
--> Processing Dependency: perl >= 5.006001 for package: 1:nginx-mod-http-perl-1.12.2-3.el7.x86_64
--> Processing Dependency: perl(:MODULE_COMPAT_5.16.3) for package: 1:nginx-mod-http-perl-1.12.2-3.el7.x86_64
--> Processing Dependency: perl(Exporter) for package: 1:nginx-mod-http-perl-1.12.2-3.el7.x86_64
--> Processing Dependency: perl(XSLoader) for package: 1:nginx-mod-http-perl-1.12.2-3.el7.x86_64
--> Processing Dependency: perl(constant) for package: 1:nginx-mod-http-perl-1.12.2-3.el7.x86_64
--> Processing Dependency: perl(strict) for package: 1:nginx-mod-http-perl-1.12.2-3.el7.x86_64
--> Processing Dependency: perl(warnings) for package: 1:nginx-mod-http-perl-1.12.2-3.el7.x86_64
--> Processing Dependency: libperl.so()(64bit) for package: 1:nginx-mod-http-perl-1.12.2-3.el7.x86_64
---> Package nginx-mod-http-xslt-filter.x86_64 1:1.12.2-3.el7 will be installed
--> Processing Dependency: libxslt.so.1(LIBXML2_1.0.11)(64bit) for package: 1:nginx-mod-http-xslt-filter-1.12.2-3.el7.x86_64
--> Processing Dependency: libxslt.so.1(LIBXML2_1.0.18)(64bit) for package: 1:nginx-mod-http-xslt-filter-1.12.2-3.el7.x86_64
--> Processing Dependency: libexslt.so.0()(64bit) for package: 1:nginx-mod-http-xslt-filter-1.12.2-3.el7.x86_64
--> Processing Dependency: libxslt.so.1()(64bit) for package: 1:nginx-mod-http-xslt-filter-1.12.2-3.el7.x86_64
---> Package nginx-mod-mail.x86_64 1:1.12.2-3.el7 will be installed
---> Package nginx-mod-stream.x86_64 1:1.12.2-3.el7 will be installed
--> Running transaction check
---> Package gd.x86_64 0:2.0.35-26.el7 will be installed
--> Processing Dependency: libjpeg.so.62(LIBJPEG_6.2)(64bit) for package: gd-2.0.35-26.el7.x86_64
--> Processing Dependency: libjpeg.so.62()(64bit) for package: gd-2.0.35-26.el7.x86_64
--> Processing Dependency: libfontconfig.so.1()(64bit) for package: gd-2.0.35-26.el7.x86_64
--> Processing Dependency: libXpm.so.4()(64bit) for package: gd-2.0.35-26.el7.x86_64
--> Processing Dependency: libX11.so.6()(64bit) for package: gd-2.0.35-26.el7.x86_64
---> Package libxslt.x86_64 0:1.1.28-5.el7 will be installed
---> Package perl.x86_64 4:5.16.3-294.el7_6 will be installed
--> Processing Dependency: perl(Socket) >= 1.3 for package: 4:perl-5.16.3-294.el7_6.x86_64
--> Processing Dependency: perl(Scalar::Util) >= 1.10 for package: 4:perl-5.16.3-294.el7_6.x86_64
--> Processing Dependency: perl-macros for package: 4:perl-5.16.3-294.el7_6.x86_64
--> Processing Dependency: perl(threads::shared) for package: 4:perl-5.16.3-294.el7_6.x86_64
--> Processing Dependency: perl(threads) for package: 4:perl-5.16.3-294.el7_6.x86_64
--> Processing Dependency: perl(Time::Local) for package: 4:perl-5.16.3-294.el7_6.x86_64
--> Processing Dependency: perl(Time::HiRes) for package: 4:perl-5.16.3-294.el7_6.x86_64
--> Processing Dependency: perl(Storable) for package: 4:perl-5.16.3-294.el7_6.x86_64
--> Processing Dependency: perl(Socket) for package: 4:perl-5.16.3-294.el7_6.x86_64
--> Processing Dependency: perl(Scalar::Util) for package: 4:perl-5.16.3-294.el7_6.x86_64
--> Processing Dependency: perl(Pod::Simple::XHTML) for package: 4:perl-5.16.3-294.el7_6.x86_64
--> Processing Dependency: perl(Pod::Simple::Search) for package: 4:perl-5.16.3-294.el7_6.x86_64
--> Processing Dependency: perl(Getopt::Long) for package: 4:perl-5.16.3-294.el7_6.x86_64
--> Processing Dependency: perl(Filter::Util::Call) for package: 4:perl-5.16.3-294.el7_6.x86_64
--> Processing Dependency: perl(File::Temp) for package: 4:perl-5.16.3-294.el7_6.x86_64
--> Processing Dependency: perl(File::Spec::Unix) for package: 4:perl-5.16.3-294.el7_6.x86_64
--> Processing Dependency: perl(File::Spec::Functions) for package: 4:perl-5.16.3-294.el7_6.x86_64
--> Processing Dependency: perl(File::Spec) for package: 4:perl-5.16.3-294.el7_6.x86_64
--> Processing Dependency: perl(File::Path) for package: 4:perl-5.16.3-294.el7_6.x86_64
--> Processing Dependency: perl(Cwd) for package: 4:perl-5.16.3-294.el7_6.x86_64
--> Processing Dependency: perl(Carp) for package: 4:perl-5.16.3-294.el7_6.x86_64
---> Package perl-Exporter.noarch 0:5.68-3.el7 will be installed
---> Package perl-constant.noarch 0:1.27-2.el7 will be installed
---> Package perl-libs.x86_64 4:5.16.3-294.el7_6 will be installed
--> Running transaction check
---> Package fontconfig.x86_64 0:2.13.0-4.3.el7 will be installed
--> Processing Dependency: fontpackages-filesystem for package: fontconfig-2.13.0-4.3.el7.x86_64
--> Processing Dependency: dejavu-sans-fonts for package: fontconfig-2.13.0-4.3.el7.x86_64
---> Package libX11.x86_64 0:1.6.5-2.el7 will be installed
--> Processing Dependency: libX11-common >= 1.6.5-2.el7 for package: libX11-1.6.5-2.el7.x86_64
--> Processing Dependency: libxcb.so.1()(64bit) for package: libX11-1.6.5-2.el7.x86_64
---> Package libXpm.x86_64 0:3.5.12-1.el7 will be installed
---> Package libjpeg-turbo.x86_64 0:1.2.90-6.el7 will be installed
---> Package perl-Carp.noarch 0:1.26-244.el7 will be installed
---> Package perl-File-Path.noarch 0:2.09-2.el7 will be installed
---> Package perl-File-Temp.noarch 0:0.23.01-3.el7 will be installed
---> Package perl-Filter.x86_64 0:1.49-3.el7 will be installed
---> Package perl-Getopt-Long.noarch 0:2.40-3.el7 will be installed
--> Processing Dependency: perl(Pod::Usage) >= 1.14 for package: perl-Getopt-Long-2.40-3.el7.noarch
--> Processing Dependency: perl(Text::ParseWords) for package: perl-Getopt-Long-2.40-3.el7.noarch
---> Package perl-PathTools.x86_64 0:3.40-5.el7 will be installed
---> Package perl-Pod-Simple.noarch 1:3.28-4.el7 will be installed
--> Processing Dependency: perl(Pod::Escapes) >= 1.04 for package: 1:perl-Pod-Simple-3.28-4.el7.noarch
--> Processing Dependency: perl(Encode) for package: 1:perl-Pod-Simple-3.28-4.el7.noarch
---> Package perl-Scalar-List-Utils.x86_64 0:1.27-248.el7 will be installed
---> Package perl-Socket.x86_64 0:2.010-4.el7 will be installed
---> Package perl-Storable.x86_64 0:2.45-3.el7 will be installed
---> Package perl-Time-HiRes.x86_64 4:1.9725-3.el7 will be installed
---> Package perl-Time-Local.noarch 0:1.2300-2.el7 will be installed
---> Package perl-macros.x86_64 4:5.16.3-294.el7_6 will be installed
---> Package perl-threads.x86_64 0:1.87-4.el7 will be installed
---> Package perl-threads-shared.x86_64 0:1.43-6.el7 will be installed
--> Running transaction check
---> Package dejavu-sans-fonts.noarch 0:2.33-6.el7 will be installed
--> Processing Dependency: dejavu-fonts-common = 2.33-6.el7 for package: dejavu-sans-fonts-2.33-6.el7.noarch
---> Package fontpackages-filesystem.noarch 0:1.44-8.el7 will be installed
---> Package libX11-common.noarch 0:1.6.5-2.el7 will be installed
---> Package libxcb.x86_64 0:1.13-1.el7 will be installed
--> Processing Dependency: libXau.so.6()(64bit) for package: libxcb-1.13-1.el7.x86_64
---> Package perl-Encode.x86_64 0:2.51-7.el7 will be installed
---> Package perl-Pod-Escapes.noarch 1:1.04-294.el7_6 will be installed
---> Package perl-Pod-Usage.noarch 0:1.63-3.el7 will be installed
--> Processing Dependency: perl(Pod::Text) >= 3.15 for package: perl-Pod-Usage-1.63-3.el7.noarch
--> Processing Dependency: perl-Pod-Perldoc for package: perl-Pod-Usage-1.63-3.el7.noarch
---> Package perl-Text-ParseWords.noarch 0:3.29-4.el7 will be installed
--> Running transaction check
---> Package dejavu-fonts-common.noarch 0:2.33-6.el7 will be installed
---> Package libXau.x86_64 0:1.0.8-2.1.el7 will be installed
---> Package perl-Pod-Perldoc.noarch 0:3.20-4.el7 will be installed
--> Processing Dependency: perl(parent) for package: perl-Pod-Perldoc-3.20-4.el7.noarch
--> Processing Dependency: perl(HTTP::Tiny) for package: perl-Pod-Perldoc-3.20-4.el7.noarch
---> Package perl-podlators.noarch 0:2.5.1-3.el7 will be installed
--> Running transaction check
---> Package perl-HTTP-Tiny.noarch 0:0.033-3.el7 will be installed
---> Package perl-parent.noarch 1:0.225-244.el7 will be installed
--> Finished Dependency Resolution
Dependencies Resolved
================================================================================
Package Arch Version Repository
Size
================================================================================
Installing:
nginx x86_64 1:1.12.2-3.el7 epel 531 k
Installing for dependencies:
dejavu-fonts-common noarch 2.33-6.el7 base 64 k
dejavu-sans-fonts noarch 2.33-6.el7 base 1.4 M
fontconfig x86_64 2.13.0-4.3.el7 base 254 k
fontpackages-filesystem noarch 1.44-8.el7 base 9.9 k
gd x86_64 2.0.35-26.el7 base 146 k
gperftools-libs x86_64 2.6.1-1.el7 base 272 k
libX11 x86_64 1.6.5-2.el7 base 606 k
libX11-common noarch 1.6.5-2.el7 base 164 k
libXau x86_64 1.0.8-2.1.el7 base 29 k
libXpm x86_64 3.5.12-1.el7 base 55 k
libjpeg-turbo x86_64 1.2.90-6.el7 base 134 k
libxcb x86_64 1.13-1.el7 base 214 k
libxslt x86_64 1.1.28-5.el7 base 242 k
nginx-all-modules noarch 1:1.12.2-3.el7 epel 16 k
nginx-filesystem noarch 1:1.12.2-3.el7 epel 17 k
nginx-mod-http-geoip x86_64 1:1.12.2-3.el7 epel 23 k
nginx-mod-http-image-filter x86_64 1:1.12.2-3.el7 epel 27 k
nginx-mod-http-perl x86_64 1:1.12.2-3.el7 epel 36 k
nginx-mod-http-xslt-filter x86_64 1:1.12.2-3.el7 epel 26 k
nginx-mod-mail x86_64 1:1.12.2-3.el7 epel 54 k
nginx-mod-stream x86_64 1:1.12.2-3.el7 epel 76 k
perl x86_64 4:5.16.3-294.el7_6 updates 8.0 M
perl-Carp noarch 1.26-244.el7 base 19 k
perl-Encode x86_64 2.51-7.el7 base 1.5 M
perl-Exporter noarch 5.68-3.el7 base 28 k
perl-File-Path noarch 2.09-2.el7 base 26 k
perl-File-Temp noarch 0.23.01-3.el7 base 56 k
perl-Filter x86_64 1.49-3.el7 base 76 k
perl-Getopt-Long noarch 2.40-3.el7 base 56 k
perl-HTTP-Tiny noarch 0.033-3.el7 base 38 k
perl-PathTools x86_64 3.40-5.el7 base 82 k
perl-Pod-Escapes noarch 1:1.04-294.el7_6 updates 51 k
perl-Pod-Perldoc noarch 3.20-4.el7 base 87 k
perl-Pod-Simple noarch 1:3.28-4.el7 base 216 k
perl-Pod-Usage noarch 1.63-3.el7 base 27 k
perl-Scalar-List-Utils x86_64 1.27-248.el7 base 36 k
perl-Socket x86_64 2.010-4.el7 base 49 k
perl-Storable x86_64 2.45-3.el7 base 77 k
perl-Text-ParseWords noarch 3.29-4.el7 base 14 k
perl-Time-HiRes x86_64 4:1.9725-3.el7 base 45 k
perl-Time-Local noarch 1.2300-2.el7 base 24 k
perl-constant noarch 1.27-2.el7 base 19 k
perl-libs x86_64 4:5.16.3-294.el7_6 updates 688 k
perl-macros x86_64 4:5.16.3-294.el7_6 updates 44 k
perl-parent noarch 1:0.225-244.el7 base 12 k
perl-podlators noarch 2.5.1-3.el7 base 112 k
perl-threads x86_64 1.87-4.el7 base 49 k
perl-threads-shared x86_64 1.43-6.el7 base 39 k
Transaction Summary
================================================================================
Install 1 Package (+48 Dependent packages)
Total download size: 16 M
Installed size: 50 M
Is this ok [y/d/N]: y
Downloading packages:
(1/49): dejavu-fonts-common-2.33-6.el7.noarch.rpm | 64 kB 00:00
(2/49): fontconfig-2.13.0-4.3.el7.x86_64.rpm | 254 kB 00:00
(3/49): fontpackages-filesystem-1.44-8.el7.noarch.rpm | 9.9 kB 00:00
(4/49): dejavu-sans-fonts-2.33-6.el7.noarch.rpm | 1.4 MB 00:00
(5/49): gd-2.0.35-26.el7.x86_64.rpm | 146 kB 00:00
(6/49): libX11-common-1.6.5-2.el7.noarch.rpm | 164 kB 00:00
(7/49): libXau-1.0.8-2.1.el7.x86_64.rpm | 29 kB 00:00
(8/49): libX11-1.6.5-2.el7.x86_64.rpm | 606 kB 00:00
(9/49): libXpm-3.5.12-1.el7.x86_64.rpm | 55 kB 00:00
(10/49): libjpeg-turbo-1.2.90-6.el7.x86_64.rpm | 134 kB 00:00
(11/49): libxcb-1.13-1.el7.x86_64.rpm | 214 kB 00:00
(12/49): libxslt-1.1.28-5.el7.x86_64.rpm | 242 kB 00:00
(13/49): gperftools-libs-2.6.1-1.el7.x86_64.rpm | 272 kB 00:00
warning: /var/cache/yum/x86_64/7/epel/packages/nginx-1.12.2-3.el7.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID 352c64e5: NOKEY
Public key for nginx-1.12.2-3.el7.x86_64.rpm is not installed
(14/49): nginx-1.12.2-3.el7.x86_64.rpm | 531 kB 00:00
(15/49): nginx-all-modules-1.12.2-3.el7.noarch.rpm | 16 kB 00:00
(16/49): nginx-filesystem-1.12.2-3.el7.noarch.rpm | 17 kB 00:00
(17/49): nginx-mod-http-geoip-1.12.2-3.el7.x86_64.rpm | 23 kB 00:00
(18/49): nginx-mod-http-image-filter-1.12.2-3.el7.x86_64.r | 27 kB 00:00
(19/49): nginx-mod-http-perl-1.12.2-3.el7.x86_64.rpm | 36 kB 00:00
(20/49): nginx-mod-http-xslt-filter-1.12.2-3.el7.x86_64.rp | 26 kB 00:00
(21/49): nginx-mod-mail-1.12.2-3.el7.x86_64.rpm | 54 kB 00:00
(22/49): nginx-mod-stream-1.12.2-3.el7.x86_64.rpm | 76 kB 00:00
(23/49): perl-Exporter-5.68-3.el7.noarch.rpm | 28 kB 00:00
(24/49): perl-5.16.3-294.el7_6.x86_64.rpm | 8.0 MB 00:00
(25/49): perl-Carp-1.26-244.el7.noarch.rpm | 19 kB 00:00
(26/49): perl-File-Path-2.09-2.el7.noarch.rpm | 26 kB 00:00
(27/49): perl-File-Temp-0.23.01-3.el7.noarch.rpm | 56 kB 00:00
(28/49): perl-Getopt-Long-2.40-3.el7.noarch.rpm | 56 kB 00:00
(29/49): perl-Filter-1.49-3.el7.x86_64.rpm | 76 kB 00:00
(30/49): perl-HTTP-Tiny-0.033-3.el7.noarch.rpm | 38 kB 00:00
(31/49): perl-PathTools-3.40-5.el7.x86_64.rpm | 82 kB 00:00
(32/49): perl-Encode-2.51-7.el7.x86_64.rpm | 1.5 MB 00:00
(33/49): perl-Pod-Perldoc-3.20-4.el7.noarch.rpm | 87 kB 00:00
(34/49): perl-Pod-Usage-1.63-3.el7.noarch.rpm | 27 kB 00:00
(35/49): perl-Pod-Simple-3.28-4.el7.noarch.rpm | 216 kB 00:00
(36/49): perl-Scalar-List-Utils-1.27-248.el7.x86_64.rpm | 36 kB 00:00
(37/49): perl-Socket-2.010-4.el7.x86_64.rpm | 49 kB 00:00
(38/49): perl-Text-ParseWords-3.29-4.el7.noarch.rpm | 14 kB 00:00
(39/49): perl-Time-Local-1.2300-2.el7.noarch.rpm | 24 kB 00:00
(40/49): perl-Time-HiRes-1.9725-3.el7.x86_64.rpm | 45 kB 00:00
(41/49): perl-constant-1.27-2.el7.noarch.rpm | 19 kB 00:00
(42/49): perl-macros-5.16.3-294.el7_6.x86_64.rpm | 44 kB 00:00
(43/49): perl-parent-0.225-244.el7.noarch.rpm | 12 kB 00:00
(44/49): perl-podlators-2.5.1-3.el7.noarch.rpm | 112 kB 00:00
(45/49): perl-threads-1.87-4.el7.x86_64.rpm | 49 kB 00:00
(46/49): perl-threads-shared-1.43-6.el7.x86_64.rpm | 39 kB 00:00
(47/49): perl-Pod-Escapes-1.04-294.el7_6.noarch.rpm | 51 kB 00:00
(48/49): perl-Storable-2.45-3.el7.x86_64.rpm | 77 kB 00:00
(49/49): perl-libs-5.16.3-294.el7_6.x86_64.rpm | 688 kB 00:00
--------------------------------------------------------------------------------
Total 11 MB/s | 16 MB 00:01
Retrieving key from file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
Importing GPG key 0x352C64E5:
Userid : "Fedora EPEL (7) <epel@fedoraproject.org>"
Fingerprint: 91e9 7d7c 4a5e 96f1 7f3e 888f 6a2f aea2 352c 64e5
Package : epel-release-7-11.noarch (@extras)
From : /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
Is this ok [y/N]: y
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
Installing : fontpackages-filesystem-1.44-8.el7.noarch 1/49
Installing : dejavu-fonts-common-2.33-6.el7.noarch 2/49
Installing : dejavu-sans-fonts-2.33-6.el7.noarch 3/49
Installing : fontconfig-2.13.0-4.3.el7.x86_64 4/49
Installing : 1:perl-parent-0.225-244.el7.noarch 5/49
Installing : perl-HTTP-Tiny-0.033-3.el7.noarch 6/49
Installing : perl-podlators-2.5.1-3.el7.noarch 7/49
Installing : perl-Pod-Perldoc-3.20-4.el7.noarch 8/49
Installing : 1:perl-Pod-Escapes-1.04-294.el7_6.noarch 9/49
Installing : perl-Encode-2.51-7.el7.x86_64 10/49
Installing : perl-Text-ParseWords-3.29-4.el7.noarch 11/49
Installing : perl-Pod-Usage-1.63-3.el7.noarch 12/49
Installing : 4:perl-libs-5.16.3-294.el7_6.x86_64 13/49
Installing : 4:perl-macros-5.16.3-294.el7_6.x86_64 14/49
Installing : 4:perl-Time-HiRes-1.9725-3.el7.x86_64 15/49
Installing : perl-Exporter-5.68-3.el7.noarch 16/49
Installing : perl-constant-1.27-2.el7.noarch 17/49
Installing : perl-Time-Local-1.2300-2.el7.noarch 18/49
Installing : perl-Socket-2.010-4.el7.x86_64 19/49
Installing : perl-Carp-1.26-244.el7.noarch 20/49
Installing : perl-Storable-2.45-3.el7.x86_64 21/49
Installing : perl-PathTools-3.40-5.el7.x86_64 22/49
Installing : perl-Scalar-List-Utils-1.27-248.el7.x86_64 23/49
Installing : 1:perl-Pod-Simple-3.28-4.el7.noarch 24/49
Installing : perl-File-Temp-0.23.01-3.el7.noarch 25/49
Installing : perl-File-Path-2.09-2.el7.noarch 26/49
Installing : perl-threads-shared-1.43-6.el7.x86_64 27/49
Installing : perl-threads-1.87-4.el7.x86_64 28/49
Installing : perl-Filter-1.49-3.el7.x86_64 29/49
Installing : perl-Getopt-Long-2.40-3.el7.noarch 30/49
Installing : 4:perl-5.16.3-294.el7_6.x86_64 31/49
Installing : 1:nginx-filesystem-1.12.2-3.el7.noarch 32/49
Installing : libX11-common-1.6.5-2.el7.noarch 33/49
Installing : gperftools-libs-2.6.1-1.el7.x86_64 34/49
Installing : libXau-1.0.8-2.1.el7.x86_64 35/49
Installing : libxcb-1.13-1.el7.x86_64 36/49
Installing : libX11-1.6.5-2.el7.x86_64 37/49
Installing : libXpm-3.5.12-1.el7.x86_64 38/49
Installing : libxslt-1.1.28-5.el7.x86_64 39/49
Installing : libjpeg-turbo-1.2.90-6.el7.x86_64 40/49
Installing : gd-2.0.35-26.el7.x86_64 41/49
Installing : 1:nginx-mod-http-image-filter-1.12.2-3.el7.x86_64 42/49
Installing : 1:nginx-mod-mail-1.12.2-3.el7.x86_64 43/49
Installing : 1:nginx-mod-stream-1.12.2-3.el7.x86_64 44/49
Installing : 1:nginx-mod-http-xslt-filter-1.12.2-3.el7.x86_64 45/49
Installing : 1:nginx-mod-http-perl-1.12.2-3.el7.x86_64 46/49
Installing : 1:nginx-mod-http-geoip-1.12.2-3.el7.x86_64 47/49
Installing : 1:nginx-all-modules-1.12.2-3.el7.noarch 48/49
Installing : 1:nginx-1.12.2-3.el7.x86_64 49/49
Verifying : 1:nginx-all-modules-1.12.2-3.el7.noarch 1/49
Verifying : fontconfig-2.13.0-4.3.el7.x86_64 2/49
Verifying : perl-HTTP-Tiny-0.033-3.el7.noarch 3/49
Verifying : 1:nginx-mod-http-image-filter-1.12.2-3.el7.x86_64 4/49
Verifying : perl-threads-shared-1.43-6.el7.x86_64 5/49
Verifying : 4:perl-Time-HiRes-1.9725-3.el7.x86_64 6/49
Verifying : 1:perl-Pod-Escapes-1.04-294.el7_6.noarch 7/49
Verifying : perl-Exporter-5.68-3.el7.noarch 8/49
Verifying : perl-constant-1.27-2.el7.noarch 9/49
Verifying : perl-PathTools-3.40-5.el7.x86_64 10/49
Verifying : 1:nginx-1.12.2-3.el7.x86_64 11/49
Verifying : 1:nginx-mod-mail-1.12.2-3.el7.x86_64 12/49
Verifying : 1:nginx-mod-stream-1.12.2-3.el7.x86_64 13/49
Verifying : dejavu-fonts-common-2.33-6.el7.noarch 14/49
Verifying : fontpackages-filesystem-1.44-8.el7.noarch 15/49
Verifying : libjpeg-turbo-1.2.90-6.el7.x86_64 16/49
Verifying : 1:perl-parent-0.225-244.el7.noarch 17/49
Verifying : 1:nginx-mod-http-xslt-filter-1.12.2-3.el7.x86_64 18/49
Verifying : 4:perl-libs-5.16.3-294.el7_6.x86_64 19/49
Verifying : perl-File-Temp-0.23.01-3.el7.noarch 20/49
Verifying : 1:perl-Pod-Simple-3.28-4.el7.noarch 21/49
Verifying : perl-Time-Local-1.2300-2.el7.noarch 22/49
Verifying : libxcb-1.13-1.el7.x86_64 23/49
Verifying : 4:perl-macros-5.16.3-294.el7_6.x86_64 24/49
Verifying : perl-Socket-2.010-4.el7.x86_64 25/49
Verifying : libXpm-3.5.12-1.el7.x86_64 26/49
Verifying : 1:nginx-mod-http-perl-1.12.2-3.el7.x86_64 27/49
Verifying : perl-Carp-1.26-244.el7.noarch 28/49
Verifying : libxslt-1.1.28-5.el7.x86_64 29/49
Verifying : libX11-1.6.5-2.el7.x86_64 30/49
Verifying : perl-Storable-2.45-3.el7.x86_64 31/49
Verifying : dejavu-sans-fonts-2.33-6.el7.noarch 32/49
Verifying : perl-Scalar-List-Utils-1.27-248.el7.x86_64 33/49
Verifying : gd-2.0.35-26.el7.x86_64 34/49
Verifying : 1:nginx-mod-http-geoip-1.12.2-3.el7.x86_64 35/49
Verifying : perl-Pod-Usage-1.63-3.el7.noarch 36/49
Verifying : perl-Encode-2.51-7.el7.x86_64 37/49
Verifying : perl-Pod-Perldoc-3.20-4.el7.noarch 38/49
Verifying : perl-podlators-2.5.1-3.el7.noarch 39/49
Verifying : libXau-1.0.8-2.1.el7.x86_64 40/49
Verifying : perl-File-Path-2.09-2.el7.noarch 41/49
Verifying : perl-threads-1.87-4.el7.x86_64 42/49
Verifying : gperftools-libs-2.6.1-1.el7.x86_64 43/49
Verifying : libX11-common-1.6.5-2.el7.noarch 44/49
Verifying : perl-Filter-1.49-3.el7.x86_64 45/49
Verifying : perl-Getopt-Long-2.40-3.el7.noarch 46/49
Verifying : perl-Text-ParseWords-3.29-4.el7.noarch 47/49
Verifying : 4:perl-5.16.3-294.el7_6.x86_64 48/49
Verifying : 1:nginx-filesystem-1.12.2-3.el7.noarch 49/49
Installed:
nginx.x86_64 1:1.12.2-3.el7
Dependency Installed:
dejavu-fonts-common.noarch 0:2.33-6.el7
dejavu-sans-fonts.noarch 0:2.33-6.el7
fontconfig.x86_64 0:2.13.0-4.3.el7
fontpackages-filesystem.noarch 0:1.44-8.el7
gd.x86_64 0:2.0.35-26.el7
gperftools-libs.x86_64 0:2.6.1-1.el7
libX11.x86_64 0:1.6.5-2.el7
libX11-common.noarch 0:1.6.5-2.el7
libXau.x86_64 0:1.0.8-2.1.el7
libXpm.x86_64 0:3.5.12-1.el7
libjpeg-turbo.x86_64 0:1.2.90-6.el7
libxcb.x86_64 0:1.13-1.el7
libxslt.x86_64 0:1.1.28-5.el7
nginx-all-modules.noarch 1:1.12.2-3.el7
nginx-filesystem.noarch 1:1.12.2-3.el7
nginx-mod-http-geoip.x86_64 1:1.12.2-3.el7
nginx-mod-http-image-filter.x86_64 1:1.12.2-3.el7
nginx-mod-http-perl.x86_64 1:1.12.2-3.el7
nginx-mod-http-xslt-filter.x86_64 1:1.12.2-3.el7
nginx-mod-mail.x86_64 1:1.12.2-3.el7
nginx-mod-stream.x86_64 1:1.12.2-3.el7
perl.x86_64 4:5.16.3-294.el7_6
perl-Carp.noarch 0:1.26-244.el7
perl-Encode.x86_64 0:2.51-7.el7
perl-Exporter.noarch 0:5.68-3.el7
perl-File-Path.noarch 0:2.09-2.el7
perl-File-Temp.noarch 0:0.23.01-3.el7
perl-Filter.x86_64 0:1.49-3.el7
perl-Getopt-Long.noarch 0:2.40-3.el7
perl-HTTP-Tiny.noarch 0:0.033-3.el7
perl-PathTools.x86_64 0:3.40-5.el7
perl-Pod-Escapes.noarch 1:1.04-294.el7_6
perl-Pod-Perldoc.noarch 0:3.20-4.el7
perl-Pod-Simple.noarch 1:3.28-4.el7
perl-Pod-Usage.noarch 0:1.63-3.el7
perl-Scalar-List-Utils.x86_64 0:1.27-248.el7
perl-Socket.x86_64 0:2.010-4.el7
perl-Storable.x86_64 0:2.45-3.el7
perl-Text-ParseWords.noarch 0:3.29-4.el7
perl-Time-HiRes.x86_64 4:1.9725-3.el7
perl-Time-Local.noarch 0:1.2300-2.el7
perl-constant.noarch 0:1.27-2.el7
perl-libs.x86_64 4:5.16.3-294.el7_6
perl-macros.x86_64 4:5.16.3-294.el7_6
perl-parent.noarch 1:0.225-244.el7
perl-podlators.noarch 0:2.5.1-3.el7
perl-threads.x86_64 0:1.87-4.el7
perl-threads-shared.x86_64 0:1.43-6.el7
Complete!
[root@edgecase2 ~]# yum repolist
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* base: mirrors.clouvider.net
* epel: www.mirrorservice.org
* extras: mirror.mhd.uk.as44574.net
* updates: mirrors.clouvider.net
repo id repo name status
base/7/x86_64 CentOS-7 - Base 10,019
epel/x86_64 Extra Packages for Enterprise Linux 7 - x86_64 13,278
extras/7/x86_64 CentOS-7 - Extras 419
updates/7/x86_64 CentOS-7 - Updates 2,146
repolist: 25,862
[root@edgecase2 ~]# nginx --version
nginx: invalid option: "-"
[root@edgecase2 ~]# nginx -v
nginx version: nginx/1.12.2
In the output of the first run of
yum repolist
, "epel" is not present. In the output of the second, it is. Browse to:
http://edgecasesystems.com
Result:
{Unable to connect}
[root@edgecase2 ~]# systemctl start nginx
[root@edgecase2 ~]# systemctl status nginx
[...]
Active: active (running) since Thu 2019-07-04 10:06:29 UTC; 12s ago
[...]
Browse to:
http://edgecasesystems.com
Result:
Welcome to nginx on Fedora!
This page is used to test the proper operation of the nginx HTTP server after it has been installed. If you can read this page, it means that the web server installed at this site is working properly.
Website Administrator
This is the defaultindex.htmlpage that is distributed with nginx on Fedora. It is located in/usr/share/nginx/html.
You should now put your content in a location of your choice and edit therootconfiguration directive in the nginx configuration file/etc/nginx/nginx.conf.
Good.
[root@edgecase2 ~]# systemctl enable nginx
Created symlink from /etc/systemd/system/multi-user.target.wants/nginx.service to /usr/lib/systemd/system/nginx.service.
Let's confirm that the nginx server starts on boot.
Go to DigitalOcean / Manage / Droplets
Click edgecase2
Click Power
Click Power Cycle
After a minute or so, a pop-up message confirms that power cycle has finished.
Browse to:
http://edgecasesystems.com
Result:
Welcome to nginx on Fedora!
[...]
Good.
[root@edgecase2 ~]#
packet_write_wait: Connection to 46.101.86.226 port 22: Broken pipe
[spiano@localhost ~]$ ssh root@edgecasesystems.com
Last login: Thu Jul 4 09:59:13 2019 from [deleted]
[root@edgecase2 ~]# systemctl status nginx
[...]
Active: active (running) since Thu 2019-07-04 10:06:29 UTC; 12s ago
[...]
Next: Choose a location for the web application, put a "hello world" file there, and configure nginx to serve this file.
[root@edgecase2 ~]# ls -1 /etc/nginx
conf.d
default.d
fastcgi.conf
fastcgi.conf.default
fastcgi_params
fastcgi_params.default
koi-utf
koi-win
mime.types
mime.types.default
nginx.conf
nginx.conf.default
scgi_params
scgi_params.default
uwsgi_params
uwsgi_params.default
win-utf
serverfault.com/questions/144598/where-should-the-web-server-root-directory-go-in-linux
superuser.com/questions/635289/what-is-the-recommended-directory-to-store-website-content
I choose:
/srv/edgecase/www
[root@edgecase2 html]# cd /srv
[root@edgecase2 srv]# ls
[root@edgecase2 srv]# mkdir -p edgecase/www
[root@edgecase2 srv]# cd edgecase/www
[root@edgecase2 www]# echo "hello world" > test.txt
[root@edgecase2 www]# cat test.txt
hello world
Next: Configure nginx to serve the hello world file.
/etc/nginx/nginx.conf
# For more information on configuration, see:
# * Official English Documentation: http://nginx.org/en/docs/
# * Official Russian Documentation: http://nginx.org/ru/docs/
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf;
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
# Settings for a TLS enabled server.
#
# server {
# listen 443 ssl http2 default_server;
# listen [::]:443 ssl http2 default_server;
# server_name _;
# root /usr/share/nginx/html;
#
# ssl_certificate "/etc/pki/nginx/server.crt";
# ssl_certificate_key "/etc/pki/nginx/private/server.key";
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 10m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
#
# # Load configuration files for the default server block.
# include /etc/nginx/default.d/*.conf;
#
# location / {
# }
#
# error_page 404 /404.html;
# location = /40x.html {
# }
#
# error_page 500 502 503 504 /50x.html;
# location = /50x.html {
# }
# }
}
Excerpts from:
nginx.org/en/docs/beginners_guide.html
An important web server task is serving out files (such as images or static HTML pages). You will implement an example where, depending on the request, files will be served from different local directories: /data/www (which may contain HTML files) and /data/images (containing images). This will require editing of the configuration file and setting up of a server block inside the http block with two location blocks.
[...]
Generally, the configuration file may include several server blocks distinguished by ports on which they listen to and by server names. Once nginx decides which server processes a request, it tests the URI specified in the request's header against the parameters of the location directives defined inside the server block.
Notes (made from the entire linked document, not just the excerpts):
- The location block's URI (in this case
/
) starts from the server block's
root
value (in this case
/usr/share/nginx/html
). So: In this case, the single location block handles all HTTP requests with URIs that start with
/usr/share/nginx/html
. Excerpt from:
docs.nginx.com/nginx/admin-guide/basic-functionality/managing-configuration-files
For HTTP traffic (thehttpcontext), eachserverdirective controls the processing of requests for resources at particular domains or IP addresses. One or morelocationcontexts in aservercontext define how to process specific sets of URIs.
Excerpt from:
docs.nginx.com/nginx/admin-guide/web-server/web-server
Theserverconfiguration block usually includes alistendirective to specify the IP address and port (or Unix domain socket and path) on which the server listens for requests. Both IPv4 and IPv6 addresses are accepted; enclose IPv6 addresses in square brackets (.
The example below shows configuration of a server that listens on IP address 127.0.0.1 and port 8080:
server { listen 127.0.0.1:8080; # The rest of server configuration }
If a port is omitted, the standard port is used. Likewise, if an address is omitted, the server listens on all addresses. If the listen directive is not included at all, the "standard" port is 80/tcp and the "default" port is 8000/tcp, depending on superuser privileges.
If there are several servers that match the IP address and port of the request, NGINX Plus tests the request'sHostheader field against theserver_namedirectives in theserverblocks. The parameter toserver_namecan be a full (exact) name, a wildcard, or a regular expression. A wildcard is a character string that includes the asterisk (*) at its beginning, end, or both; the asterisk matches any sequence of characters. NGINX Plus uses the Perl syntax for regular expressions; precede them with the tilde (~). This example illustrates an exact name.
server { listen 80; server_name example.org www.example.org; ... }
If several names match theHostheader, NGINX Plus selects one by searching for names in the following order and using the first match it finds:
1. Exact name
2. Longest wildcard starting with an asterisk, such as *.example.org
3. Longest wildcard ending with an asterisk, such as mail.*
4. First matching regular expression (in order of appearance in the configuration file)
If theHostheader field does not match a server name, NGINX Plus routes the request to the default server for the port on which the request arrived. The default server is the first one listed in thenginx.conffile, unless you include thedefault_serverparameter to thelistendirective to explicitly designate a server as the default.
server { listen 80 default_server; ... }
Notes:
- I think that these two lines in nginx.conf:
listen 80 default_server;
listen [::]:80 default_server;
capture all requests on port 80 from any IP address.
- This line:
root /usr/share/nginx/html;
sets the document root for these requests.
- Any further settings should be placed in the location block:
location / {
}
Excerpts from:
docs.nginx.com/nginx/admin-guide/web-server/serving-static-content
If a request ends with a slash, NGINX treats it as a request for a directory and tries to find an index file in the directory. Theindexdirective defines the index file's name (the default value is index.html).
[...]
You can list more than one filename in theindexdirective. NGINX searches for files in the specified order and returns the first one it finds.
location / { index index.$geo.html index.htm index.html; }
The $geo variable used here here is a custom variable set through thegeodirective. The value of the variable depends on the client's IP address.
So, I can do this:
location / {
index test.txt index.htm index.html;
}
in order to direct the URI edgecasesystems.com to /test.txt.
Ok. In order to set nginx to serve from /srv/edgecase/www, and to have test.txt be the default page, change this section of /etc/nginx/nginx.conf:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
}
to this:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /srv/edgecase/www;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
index test.txt;
}
On the VPS,
vi
is present, but not
vim
. Use vi to edit nginx.conf to the desired state. Note: Use spaces, not tabs, for nginx.conf spacing.
Use
nginx -t
to check nginx.conf for syntax errors.
[root@edgecase2 nginx]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@edgecase2 nginx]# systemctl reload nginx
Browse to:
http://edgecasesystems.com
Result:
Welcome to nginx on Fedora!
[...]
[root@edgecase2 nginx]# systemctl restart nginx
Browse to:
http://edgecasesystems.com/test.txt
Result:
403 Forbidden
nginx/1.12.2
Hm.
[root@edgecase2 nginx]# tail -1 /var/log/nginx/error.log
2019/07/05 11:14:29 [error] 8449#0: *1 open() "/srv/edgecase/www/test.txt" failed (13: Permission denied), client: [deleted], server: _, request: "GET /test.txt HTTP/1.1", host: "edgecasesystems.com"
[reading and experimentation occurs here]
Excerpt from:
unix.stackexchange.com/questions/285461/user-permissions-problem-in-centos-7-permission-denied
answered Dec 1 '18 at 3:21
telcoM
You're using CentOS 7, which has SELinux enabled by default.
RHEL/CentOS has a default SELinux configuration that usually has a pretty negligible effect on regular user accounts, but it can place some strict limits on system services - like a web server, for example.
Under SELinux, it is possible to restrict a process and all of its descendants from certain actions - independently from traditional Unix-style user/group/permissions system. Those restrictions can be configured to automatically "latch on" when certain binaries are executed, for certain system users, and on a multitude of other conditions.
One of the default SELinux restrictions for a webserver is that access to anything outside specifically enabled directories like /var/www is blocked, unless specifically enabled using a SELinux boolean, a kind of switchable option in SELinux ruleset. I think this might be another thing stopping the web3 user from accessing the Drush application.
If you want a web server (or any of its descendants, like a PHP interpreter) to access any content that is not under /var/www and is created by other users, you'll need to run this command:
# setsebool -P httpd_read_user_content 1
On RHEL/CentOS, each system service has an additional man page, named like<service name>_selinux, that contains information on SELinux restrictions and booleans for that specific service. Those man pages come in a RPM package namedselinux-policy-doc: here's more information about that package [ http://centos.pkgs.org/7/centos-x86_64/selinux-policy-doc-3.13.1-192.el7.noarch.rpm.html ]. If you're using a system with SELinux enabled, you really should read those man pages for all the services you're planning to run: they make dealing with SELinux just so much easier.
Of course, you may find on the internet a lot of suggestions on how to disable SELinux, but if you are planning to run a secure server, that might not be the best option.
Hm. Ok. Let's try with /var/www/edgecase/basic instead of /srv/edgecase/www.
[root@edgecase2 nginx]# ls /var/www
ls: cannot access /var/www: No such file or directory
[root@edgecase2 nginx]# mkdir -p /var/www/edgecase/basic
[root@edgecase2 nginx]# echo "hello world" > /var/www/edgecase/basic/test.txt
[root@edgecase2 nginx]# ls /var/www/edgecase/basic
test.txt
change this section of /etc/nginx/nginx.conf:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
}
to this:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /var/www/edgecase/basic;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
index test.txt;
}
[root@edgecase2 nginx]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@edgecase2 nginx]# systemctl restart nginx
Browse to:
http://edgecasesystems.com/test.txt
Result:
403 Forbidden
nginx/1.12.2
[root@edgecase2 nginx]# tail -1 /var/log/nginx/error.log
2019/07/05 11:39:31 [error] 8616#0: *4 open() "/var/www/edgecase/basic/test.txt" failed (13: Permission denied), client: [deleted], server: _, request: "GET /test.txt HTTP/1.1", host: "edgecasesystems.com"
Excerpt from:
www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls
The [Filesystem Hierarchy Standard](https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard "Filesystem Hierarchy Standard on WikiPedia") defines where data should exist. You should definitely read it. The short version is that you want your web content to exist in either /var/www/, /srv, /usr/share/www.
Using the Default Document Root
NGINX packages that exist in Ubuntu, Debian, or other operating systems, as an easy-to-install package will often provide a 'default' configuration file as an example of configuration methods, and will often include a document root to hold a basic HTML file.
Most of these packaging systems do not check to see if files are modified or exist within the default document root, which can result in code loss when the packages are upgraded. Experienced system administrators know that there is no expectation of the data inside the default document root to remain untouched during upgrades.
You should not use the default document root for any site-critical files. There is no expectation that the default document root will be left untouched by the system and there is an extremely high possibility that your site-critical data may be lost upon updates and upgrades to the NGINX packages for your operating system.
[root@edgecase2 nginx]# namei -om /usr/share/nginx/html/index.html
f: /usr/share/nginx/html/index.html
dr-xr-xr-x root root /
drwxr-xr-x root root usr
drwxr-xr-x root root share
drwxr-xr-x root root nginx
drwxr-xr-x root root html
-rw-r--r-- root root index.html
[root@edgecase2 nginx]# namei -om /var/www/edgecase/basic/test.txt
f: /var/www/edgecase/basic/test.txt
dr-xr-xr-x root root /
drwxr-xr-x root root var
drwxr-xr-x root root www
drwxr-xr-x root root edgecase
drwxr-xr-x root root basic
-rw-r--r-- root root test.txt
Excerpts from:
introvertedengineer.com/2017/03/21/fixing-permission-denied-centos-selinux
Fixing Permission Denied on CentOS7 (SELinux)
Date: March 21, 2017
Author: Said Ketchman
You've configured your server, setup permissions properly, and still you get the frustrating error message:Permission denied in /var/www/... on line xyz. If you're using a newer linux based OS, chances are you've overlooked SELinux and need to also set the proper permissions for write access to your directory and files.
If you have a WordPress, Joomla, Drupal, OpenCart, or any other CMS site and can't update your plugins automatically, chances are you have this issue. The fix is really simple, so that's good news!
Allowing Read/Write Access via SELinux
First thing is to check the current SELinux permissions for your website's home directory. You'll need to ssh into your server and then run the following command:
ls -Z /path/to/website/root
You will most likely see something like this:
drwxrwsr-x. root root unconfined_u:object_r:httpd_sys_content_t:s0 mywebsite.com
The key part to look at is theunconfined_u:object_r:httpd_sys_content_t:s0portion. If you seehttpd_sys_content_tthen you know right away that your web server and application (Apache, PHP, etc.) will not be able to write to your directories.
To allow for write access to your directories, you'll need to issue the following command:
sudo chcon -t httpd_sys_rw_content_t mywebsite.com/ -R
Note! This will make your entire website home directory writeable via SELinux, so you will probably want to selectively choose folders that you want your web server to be able to write to.
Run the ls -Z command again and you should see the new attributehttpd_sys_rw_content_tinstead of the previoushttpd_sys_content_t.
You should be all set at this point. SELinux is a security layer above the standard chmod permissions, so make sure both are set properly in order to have the permissions you need.
Linux variations that implement SELinux:
- Red Hat
- CentOS/REHL
- Fedora
- Debian
- Ubuntu
- CoreOS
[...]
I'm beginning to see this issue pop up quite often as more and more people move towards hosting with a non-managed virtual private server. So it's always worth understanding the fundamentals.
Ok. Let's try this.
[root@edgecase2 nginx]# ls -Z /var/www
drwxr-xr-x. root root unconfined_u:object_r:var_t:s0 edgecase
[root@edgecase2 nginx]# chcon -t httpd_sys_rw_content_t /var/www/ -R
[root@edgecase2 nginx]# ls -Z /var/www
drwxr-xr-x. root root unconfined_u:object_r:httpd_sys_rw_content_t:s0 edgecase
[root@edgecase2 nginx]# systemctl restart nginx
Browse to:
http://edgecasesystems.com/test.txt
Result:
hello world
Success.
[root@edgecase2 nginx]# ls -Z /usr/share/nginx/
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 html
drwxr-xr-x. root root system_u:object_r:usr_t:s0 modules
Looks like I only actually needed the
httpd_sys_content_t
permission (read-only permission?) on /var/www/edgecase/basic, not
httpd_sys_rw_content_t
permission (read/write permission). Browse to:
http://edgecasesystems.com
Result:
hello world
The
index
configuration works. Next: Delete /var/www/edgecase and move back to /srv/edgecase/www. Set SELinux read permission on /srv/edgecase/www.
[root@edgecase2 edgecase]# cd /var/www
[root@edgecase2 www]# ls
edgecase
[root@edgecase2 www]# rm -fr edgecase
[root@edgecase2 www]# cd /srv/edgecase
[root@edgecase2 edgecase]# ls
www
[root@edgecase2 edgecase]# ls -Z
drwxr-xr-x. root root unconfined_u:object_r:var_t:s0 www
[root@edgecase2 edgecase]# ls -Z www
-rw-r--r--. root root unconfined_u:object_r:var_t:s0 404.html
-rw-r--r--. root root unconfined_u:object_r:var_t:s0 50x.html
-rw-r--r--. root root unconfined_u:object_r:var_t:s0 index.html
-rw-r--r--. root root unconfined_u:object_r:var_t:s0 nginx-logo.png
-rw-r--r--. root root unconfined_u:object_r:var_t:s0 poweredby.png
-rw-r--r--. root root unconfined_u:object_r:var_t:s0 test.txt
[root@edgecase2 edgecase]# chcon -t httpd_sys_r_content_t www -R
chcon: failed to change context of 'test.txt' to 'unconfined_u:object_r:httpd_sys_r_content_t:s0': Invalid argument
chcon: failed to change context of '404.html' to 'unconfined_u:object_r:httpd_sys_r_content_t:s0': Invalid argument
chcon: failed to change context of '50x.html' to 'unconfined_u:object_r:httpd_sys_r_content_t:s0': Invalid argument
chcon: failed to change context of 'index.html' to 'unconfined_u:object_r:httpd_sys_r_content_t:s0': Invalid argument
chcon: failed to change context of 'nginx-logo.png' to 'unconfined_u:object_r:httpd_sys_r_content_t:s0': Invalid argument
chcon: failed to change context of 'poweredby.png' to 'unconfined_u:object_r:httpd_sys_r_content_t:s0': Invalid argument
chcon: failed to change context of 'www' to 'unconfined_u:object_r:httpd_sys_r_content_t:s0': Invalid argument
[root@edgecase2 edgecase]# chcon -v --type=httpd_sys_content_t www
changing security context of 'www'
[root@edgecase2 edgecase]# ls -Z
drwxr-xr-x. root root unconfined_u:object_r:httpd_sys_content_t:s0 www
[root@edgecase2 edgecase]# chcon -v --type=httpd_sys_content_t www -R
changing security context of 'www/test.txt'
changing security context of 'www/404.html'
changing security context of 'www/50x.html'
changing security context of 'www/index.html'
changing security context of 'www/nginx-logo.png'
changing security context of 'www/poweredby.png'
changing security context of 'www'
[root@edgecase2 edgecase]# ls -Z www
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 404.html
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 50x.html
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 index.html
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 nginx-logo.png
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 poweredby.png
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 test.txt
Hm. Strange that
chcon -t httpd_sys_r_content_t www -R
didn't work, but
chcon -v --type=httpd_sys_content_t www -R
did.
When searching / reading, I noted that the
--type=httpd_sys_content_t
option was used on this page:wiki.centos.org/HowTos/SELinux
change this section of /etc/nginx/nginx.conf:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
}
to this:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /srv/edgecase/www;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
index test.txt;
}
[root@edgecase2 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@edgecase2 ~]# systemctl restart nginx
[root@edgecase2 ~]# curl http://edgecasesystems.com/test.txt
hello world
[root@edgecase2 nginx]# tail -1 /var/log/nginx/access.log
[deleted] - - [15/Sep/2019:15:38:12 +0000] "GET /test.txt HTTP/1.1" 200 12 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0" "-"
Excellent.
Next: Install Gunicorn on edgecase2 VPS and test it.
Excerpt from:
docs.gunicorn.org/en/stable/install.html
Requirements: Python 2.x >= 2.6 or Python 3.x >= 3.2
[root@edgecase2 ~]# pip --version
-bash: pip: command not found
[root@edgecase2 ~]# yum search pip
[...]
python-virtualenv-api.noarch : An API for virtualenv/pip
python2-pip.noarch : A tool for installing and managing Python 2 packages
python34-pip.noarch : A tool for installing and managing Python3 packages
python36-pip.noarch : A tool for installing and managing Python3 packages
[...]
[root@edgecase2 ~]# python --version
Python 2.7.5
[root@edgecase2 ~]# yum install pip
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
epel/x86_64/metalink | 30 kB 00:00:00
* base: mirror.sov.uk.goscomb.net
* epel: mirrors.coreix.net
* extras: mirror.mhd.uk.as44574.net
* updates: mirror.mhd.uk.as44574.net
base | 3.6 kB 00:00:00
epel | 5.3 kB 00:00:00
extras | 3.4 kB 00:00:00
updates | 3.4 kB 00:00:00
(1/4): epel/x86_64/updateinfo | 1.0 MB 00:00:00
(2/4): epel/x86_64/primary_db | 6.8 MB 00:00:00
(3/4): extras/7/x86_64/primary_db | 215 kB 00:00:00
(4/4): updates/7/x86_64/primary_db | 7.4 MB 00:00:00
No package pip available.
Error: Nothing to do
[root@edgecase2 ~]# yum install python2-pip.noarch
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* base: mirror.sov.uk.goscomb.net
* epel: mirrors.coreix.net
* extras: mirror.mhd.uk.as44574.net
* updates: mirror.mhd.uk.as44574.net
Resolving Dependencies
--> Running transaction check
---> Package python2-pip.noarch 0:8.1.2-10.el7 will be installed
--> Finished Dependency Resolution
Dependencies Resolved
====================================================================================
Package Arch Version Repository Size
====================================================================================
Installing:
python2-pip noarch 8.1.2-10.el7 epel 1.7 M
Transaction Summary
====================================================================================
Install 1 Package
Total download size: 1.7 M
Installed size: 7.2 M
Is this ok [y/d/N]: y
Downloading packages:
python2-pip-8.1.2-10.el7.noarch.rpm | 1.7 MB 00:00:00
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
Installing : python2-pip-8.1.2-10.el7.noarch 1/1
Verifying : python2-pip-8.1.2-10.el7.noarch 1/1
Installed:
python2-pip.noarch 0:8.1.2-10.el7
Complete!
[root@edgecase2 ~]# pip --version
pip 8.1.2 from /usr/lib/python2.7/site-packages (python 2.7)
[root@edgecase2 ~]# pip install gunicorn
Collecting gunicorn
Downloading https://files.pythonhosted.org/packages/8c/da/b8dd8deb741bff556db53902d4706774c8e1e67265f69528c14c003644e6/gunicorn-19.9.0-py2.py3-none-any.whl (112kB)
100% |________________________________| 122kB 5.4MB/s
Installing collected packages: gunicorn
Successfully installed gunicorn-19.9.0
You are using pip version 8.1.2, however version 19.2.3 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
[root@edgecase2 ~]# gunicorn --version
gunicorn (version 19.9.0)
[root@edgecase2 ~]# which gunicorn
/usr/bin/gunicorn
[root@edgecase2 ~]# file /usr/bin/gunicorn
/usr/bin/gunicorn: Python script, ASCII text executable
[root@edgecase2 ~]# cat /usr/bin/gunicorn
#!/usr/bin/python2
# -*- coding: utf-8 -*-
import re
import sys
from gunicorn.app.wsgiapp import run
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(run())
[some experimentation and reading occurs here, drawing mainly from the following links]
docs.gunicorn.org/en/stable/run.html
docs.gunicorn.org/en/stable/deploy.html
Example test application:
def app(environ, start_response):
"""Simplest possible application object"""
data = 'Hello, World!\n'
status = '200 OK'
response_headers = [
('Content-type','text/plain'),
('Content-Length', str(len(data)))
]
start_response(status, response_headers)
return iter([data])
[root@edgecase2 ~]# vi test.py
[paste in the example test application shown above]
[root@edgecase2 ~]# gunicorn --bind=localhost:8080 --workers=2 test:app
[2019-09-15 18:05:07 +0000] [29303] [INFO] Starting gunicorn 19.9.0
[2019-09-15 18:05:07 +0000] [29303] [INFO] Listening at: http://127.0.0.1:8080 (29303)
[2019-09-15 18:05:07 +0000] [29303] [INFO] Using worker: sync
[2019-09-15 18:05:07 +0000] [29308] [INFO] Booting worker with pid: 29308
[2019-09-15 18:05:07 +0000] [29309] [INFO] Booting worker with pid: 29309
[open another bash shell here and log in to edgecase2 VPS:]
[root@edgecase2 ~]# curl localhost
hello world
[root@edgecase2 ~]# curl localhost:8080
Hello, World!
[root@edgecase2 ~]# curl edgecasesystems.com:80
hello world
[root@edgecase2 ~]# curl edgecasesystems.com:8080
curl: (7) Failed connect to edgecasesystems.com:8080; Connection refused
[switch back to the original bash shell. press ctrl-C to stop the gunicorn process.]
^C[2019-09-15 18:06:07 +0000] [29303] [INFO] Handling signal: int
[2019-09-15 18:06:07 +0000] [29308] [INFO] Worker exiting (pid: 29308)
[2019-09-15 18:06:07 +0000] [29309] [INFO] Worker exiting (pid: 29309)
[2019-09-15 18:06:07 +0000] [29303] [INFO] Shutting down: Master
[root@edgecase2 ~]# gunicorn --bind=edgecasesystems.com:8080 --workers=1 test:app
[2019-09-15 18:10:00 +0000] [29325] [INFO] Starting gunicorn 19.9.0
[2019-09-15 18:10:00 +0000] [29325] [INFO] Listening at: http://46.101.86.226:8080 (29325)
[2019-09-15 18:10:00 +0000] [29325] [INFO] Using worker: sync
[2019-09-15 18:10:00 +0000] [29330] [INFO] Booting worker with pid: 29330
[switch to second bash shell]
[root@edgecase2 ~]# curl localhost
hello world
[root@edgecase2 ~]# curl localhost:80
hello world
[root@edgecase2 ~]# curl localhost:8080
curl: (7) Failed connect to localhost:8080; Connection refused
[root@edgecase2 ~]# curl edgecasesystems.com
hello world
[root@edgecase2 ~]# curl edgecasesystems.com:80
hello world
[root@edgecase2 ~]# curl edgecasesystems.com:8080
Hello, World!
[switch back to the original bash shell. press ctrl-C to stop the gunicorn process.]
^C[2019-09-15 18:35:22 +0000] [29325] [INFO] Handling signal: int
[2019-09-15 18:35:22 +0000] [29330] [INFO] Worker exiting (pid: 29330)
[2019-09-15 18:35:22 +0000] [29325] [INFO] Shutting down: Master
Good. The gunicorn server is serving on the domain edgecasesystems.com on port 8080.
Next: Configure nginx to pass all requests to the gunicorn server.
In second bash shell, set gunicorn server process running:
[root@edgecase2 ~]# gunicorn --bind=localhost:8080 --workers=1 test:app
Switch to first bash shell:
Change this section of /etc/nginx/nginx.conf:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
}
to this:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /srv/edgecase/www;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
proxy_pass http://localhost:8080;
}
[root@edgecase2 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@edgecase2 ~]# systemctl restart nginx
Browse to http://edgecasesystems.com:
nginx error!
[...]
[root@edgecase2 ~]# tail -1 /var/log/nginx/error.log
2019/09/15 19:36:17 [crit] 29584#0: *1 connect() to [::1]:8080 failed (13: Permission denied) while connecting to upstream, client: 46.101.86.226, server: _, request: "GET / HTTP/1.1", upstream: "http://[::1]:8080/", host: "edgecasesystems.com"
[experimentation + searching + reading occurs here]
I'll follow some suggestions from:
stackoverflow.com/questions/23948527/13-permission-denied-while-connecting-to-upstreamnginx
[root@edgecase2 ~]# getsebool -a | grep httpd
httpd_anon_write --> off
httpd_builtin_scripting --> on
httpd_can_check_spam --> off
httpd_can_connect_ftp --> off
httpd_can_connect_ldap --> off
httpd_can_connect_mythtv --> off
httpd_can_connect_zabbix --> off
httpd_can_network_connect --> off
httpd_can_network_connect_cobbler --> off
httpd_can_network_connect_db --> off
httpd_can_network_memcache --> off
httpd_can_network_relay --> off
httpd_can_sendmail --> off
httpd_dbus_avahi --> off
httpd_dbus_sssd --> off
httpd_dontaudit_search_dirs --> off
httpd_enable_cgi --> on
httpd_enable_ftp_server --> off
httpd_enable_homedirs --> off
httpd_execmem --> off
httpd_graceful_shutdown --> on
httpd_manage_ipa --> off
httpd_mod_auth_ntlm_winbind --> off
httpd_mod_auth_pam --> off
httpd_read_user_content --> off
httpd_run_ipa --> off
httpd_run_preupgrade --> off
httpd_run_stickshift --> off
httpd_serve_cobbler_files --> off
httpd_setrlimit --> off
httpd_ssi_exec --> off
httpd_sys_script_anon_write --> off
httpd_tmp_exec --> off
httpd_tty_comm --> off
httpd_unified --> off
httpd_use_cifs --> off
httpd_use_fusefs --> off
httpd_use_gpg --> off
httpd_use_nfs --> off
httpd_use_openstack --> off
httpd_use_sasl --> off
httpd_verify_dns --> off
[root@edgecase2 ~]# setsebool -P httpd_can_network_connect 1
[root@edgecase2 ~]# getsebool -a | grep httpd | grep network
httpd_can_network_connect --> on
httpd_can_network_connect_cobbler --> off
httpd_can_network_connect_db --> off
httpd_can_network_memcache --> off
httpd_can_network_relay --> off
[root@edgecase2 ~]# curl edgecasesystems.com
Hello, World!
Cool. Works.
Now remove the SELinux permission. I'll switch to using a Unix socket instead of a network connection.
[root@edgecase2 ~]# setsebool -P httpd_can_network_connect 0
[root@edgecase2 ~]# getsebool -a | grep httpd | grep network
httpd_can_network_connect --> off
httpd_can_network_connect_cobbler --> off
httpd_can_network_connect_db --> off
httpd_can_network_memcache --> off
httpd_can_network_relay --> off
Next: Configure nginx to pass requests to the gunicorn server via a Unix socket.
First, stop the gunicorn server, then start it again, this time listening on a socket.
[switch back to the second bash shell. press ctrl-C to stop the gunicorn process.]
^C[2019-09-15 19:45:34 +0000] [29379] [INFO] Handling signal: int
[2019-09-15 19:45:34 +0000] [29384] [INFO] Worker exiting (pid: 29384)
[2019-09-15 19:45:34 +0000] [29379] [INFO] Shutting down: Master
[2019-09-15 19:48:46 +0000] [29632] [INFO] Starting gunicorn 19.9.0
[2019-09-15 19:48:46 +0000] [29632] [INFO] Listening at: unix:/tmp/gunicorn.sock (29632)
[2019-09-15 19:48:46 +0000] [29632] [INFO] Using worker: sync
[2019-09-15 19:48:46 +0000] [29637] [INFO] Booting worker with pid: 29637
[switch to first bash shell]
Hello, World!
curl: no URL specified!
curl: try 'curl --help' or 'curl --manual' for more information
Hello, World!
Hello, World!
[2019-09-15 19:45:34 +0000] [29384] [INFO] Worker exiting (pid: 29384)
[2019-09-15 19:45:34 +0000] [29379] [INFO] Shutting down: Master
[root@edgecase2 ~]# gunicorn --bind=unix:/tmp/gunicorn.sock --workers=1 test:app
[2019-09-15 19:48:46 +0000] [29632] [INFO] Starting gunicorn 19.9.0
[2019-09-15 19:48:46 +0000] [29632] [INFO] Listening at: unix:/tmp/gunicorn.sock (29632)
[2019-09-15 19:48:46 +0000] [29632] [INFO] Using worker: sync
[2019-09-15 19:48:46 +0000] [29637] [INFO] Booting worker with pid: 29637
[switch to first bash shell]
[root@edgecase2 ~]# curl --unix-socket /tmp/gunicorn.sock http://test
Hello, World!
[root@edgecase2 ~]# curl --unix-socket /tmp/gunicorn.sock
curl: no URL specified!
curl: try 'curl --help' or 'curl --manual' for more information
[root@edgecase2 ~]# curl --unix-socket /tmp/gunicorn.sock http://test
Hello, World!
[root@edgecase2 ~]# curl --unix-socket /tmp/gunicorn.sock h
Hello, World!
Change this section of /etc/nginx/nginx.conf:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
}
to this:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /srv/edgecase/www;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
proxy_pass unix:/tmp/gunicorn.sock;
}
[root@edgecase2 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@edgecase2 ~]# systemctl restart nginx
Browse to http://edgecasesystems.com:
nginx error!
[...]
[root@edgecase2 ~]# tail -1 /var/log/nginx/error.log
2019/09/15 19:58:42 [crit] 29730#0: *1 connect() to unix:/tmp/gunicorn.sock failed (2: No such file or directory) while connecting to upstream, client: 46.101.86.226, server: _, request: "GET / HTTP/1.1", upstream: "http://unix:/tmp/gunicorn.sock:/", host: "edgecasesystems.com"
[root@edgecase2 ~]# ls -l /tmp
total 0
srwxrwxrwx. 1 root root 0 Sep 15 19:48 gunicorn.sock
drwx------. 3 root root 17 Jul 4 10:14 systemd-private-7f78a3d0bfb74fa89ef2a54f4a06856c-chronyd.service-ez5kpd
drwx------. 3 root root 17 Sep 15 19:58 systemd-private-7f78a3d0bfb74fa89ef2a54f4a06856c-nginx.service-UzwWpy
The socket file should allow the nginx user to write to it.
stackoverflow.com/questions/22272943/nginx-cannot-find-unix-socket-file-with-unicorn-no-such-file-or-directory
Excerpt from:
serverfault.com/questions/463993/nginx-unix-domain-socket-error/464025#464025
You can't place sockets intended for interprocess communication in/tmp.
For security reasons, recent versions of Fedora use namespaced temporary directories [ http://fedoraproject.org/wiki/Features/ServicesPrivateTmp ], meaning every service sees a completely different/tmpand can only see its own files in that directory.
To resolve the issue, place the socket in a different directory, such as/run(formerly known as/var/run).
answered Jan 8 '13 at 14:41
Michael Hampton
Change location of socket from /tmp/gunicorn.sock to /run/gunicorn.sock
[switch back to the second bash shell. press ctrl-C to stop the gunicorn process.]
^C[2019-09-15 20:16:02 +0000] [29795] [INFO] Handling signal: int
[2019-09-15 20:16:02 +0000] [29800] [INFO] Worker exiting (pid: 29800)
[2019-09-15 20:16:02 +0000] [29795] [INFO] Shutting down: Master
[2019-09-15 20:16:06 +0000] [29813] [INFO] Starting gunicorn 19.9.0
[2019-09-15 20:16:06 +0000] [29813] [INFO] Listening at: unix:/run/gunicorn.sock (29813)
[2019-09-15 20:16:06 +0000] [29813] [INFO] Using worker: sync
[2019-09-15 20:16:06 +0000] [29818] [INFO] Booting worker with pid: 29818
^C[2019-09-15 20:16:02 +0000] [29795] [INFO] Handling signal: int
[2019-09-15 20:16:02 +0000] [29800] [INFO] Worker exiting (pid: 29800)
[2019-09-15 20:16:02 +0000] [29795] [INFO] Shutting down: Master
[root@edgecase2 ~]# gunicorn --bind=unix:/run/gunicorn.sock --workers=1 test:app
[2019-09-15 20:16:06 +0000] [29813] [INFO] Starting gunicorn 19.9.0
[2019-09-15 20:16:06 +0000] [29813] [INFO] Listening at: unix:/run/gunicorn.sock (29813)
[2019-09-15 20:16:06 +0000] [29813] [INFO] Using worker: sync
[2019-09-15 20:16:06 +0000] [29818] [INFO] Booting worker with pid: 29818
[switch to first bash shell]
Change this section of /etc/nginx/nginx.conf:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
}
to this:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /srv/edgecase/www;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
proxy_pass unix:/run/gunicorn.sock;
}
[root@edgecase2 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@edgecase2 ~]# systemctl restart nginx
[root@edgecase2 ~]# curl --unix-socket /run/gunicorn.sock h
Hello, World!
Browse to http://edgecasesystems.com:
nginx error!
[...]
[root@edgecase2 ~]# tail -1 /var/log/nginx/error.log
2019/09/15 20:16:40 [crit] 29836#0: *1 connect() to unix:/run/gunicorn.sock failed (13: Permission denied) while connecting to upstream, client: 46.101.86.226, server: _, request: "GET / HTTP/1.1", upstream: "http://unix:/run/gunicorn.sock:/", host: "edgecasesystems.com"
Ok, now the nginx server can see the socket, but it doesn't have permission to connect to it.
Check SELinux log:
[root@edgecase2 ~]# tail -2 /var/log/audit/audit.log
type=CRYPTO_KEY_USER msg=audit(1568578956.471:1212622): pid=29844 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:sshd_t:s0-s0:c0.c1023 msg='op=destroy kind=server fp=SHA256:ea:07:15:0d:68:e4:8b:bf:bd:20:b5:a2:83:df:af:c3:79:a7:2a:55:0c:b1:57:5a:7c:58:be:05:b8:eb:3a:74 direction=? spid=29844 suid=0 exe="/usr/sbin/sshd" hostname=? addr=? terminal=? res=success'
type=USER_LOGIN msg=audit(1568578956.471:1212623): pid=29844 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:sshd_t:s0-s0:c0.c1023 msg='op=login acct="(unknown)" exe="/usr/sbin/sshd" hostname=? addr=103.17.53.148 terminal=ssh res=failed'
Turn off SELinux:
[root@edgecase2 ~]# setenforce 0
[root@edgecase2 ~]# curl edgecasesystems.com
Hello, World!
Ok, works if SELinux is disabled.
[root@edgecase2 ~]# setenforce 1
[some days have passed - do a new runthrough]
[Check current status of SELinux]
[root@edgecase2 ~]# getenforce
[root@edgecase2 ~]# getenforce
Enforcing
[root@edgecase2 ~]# cat /etc/selinux/config
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - No SELinux policy is loaded.
SELINUX=enforcing
# SELINUXTYPE= can take one of three values:
# targeted - Targeted processes are protected,
# minimum - Modification of targeted policy. Only selected processes are protected.
# mls - Multi Level Security protection.
SELINUXTYPE=targeted
Change this section of /etc/nginx/nginx.conf:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
}
to this:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /srv/edgecase/www;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
proxy_pass http://unix:/run/gunicorn.sock;
}
Note: At some earlier point I changed
unix:/run/gunicorn.sock
to
http://unix:/run/gunicorn.sock
(I found it in the file when I opened it just now), but I'm not sure exactly when. Testing with
proxy_pass unix:/run/gunicorn.sock
:
[root@edgecase2 ~]# systemctl restart nginx
Job for nginx.service failed because the control process exited with error code. See "systemctl status nginx.service" and "journalctl -xe" for details.
[root@edgecase2 ~]# nginx -t
nginx: [emerg] invalid URL prefix in /etc/nginx/nginx.conf:48
nginx: configuration file /etc/nginx/nginx.conf test failed
Switch back to
proxy_pass http://unix:/run/gunicorn.sock
.
[root@edgecase2 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@edgecase2 ~]# systemctl restart nginx
[root@edgecase2 ~]# systemctl status nginx | grep Active
Active: active (running) since Sat 2019-09-21 09:27:10 UTC; 10s ago
[switch to a second bash shell]
[root@edgecase2 ~]# gunicorn --bind=unix:/run/gunicorn.sock --workers=1 test:app
[2019-09-21 09:28:03 +0000] [17502] [INFO] Starting gunicorn 19.9.0
[2019-09-21 09:28:03 +0000] [17502] [INFO] Listening at: unix:/run/gunicorn.sock (17502)
[2019-09-21 09:28:03 +0000] [17502] [INFO] Using worker: sync
[2019-09-21 09:28:03 +0000] [17507] [INFO] Booting worker with pid: 17507
[switch to a third bash shell]
[root@edgecase2 ~]# curl --unix-socket /run/gunicorn.sock h
Hello, World!
Browse to http://edgecasesystems.com:
nginx error!
[...]
[root@edgecase2 ~]# tail -1 /var/log/nginx/error.log
2019/09/21 09:29:36 [crit] 17494#0: *4 connect() to unix:/run/gunicorn.sock failed (13: Permission denied) while connecting to upstream, client: [deleted], server: _, request: "GET /favicon.ico HTTP/1.1", upstream: "http://unix:/run/gunicorn.sock:/favicon.ico", host: "edgecasesystems.com"
The nginx server can see the gunicorn socket, but it doesn't have permission to connect to it.
Check SELinux log:
[root@edgecase2 ~]# grep nginx /var/log/audit/audit.log
type=SERVICE_STOP msg=audit(1569058030.240:1301773): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg='unit=nginx comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
type=SERVICE_START msg=audit(1569058030.364:1301774): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg='unit=nginx comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
type=AVC msg=audit(1569058175.985:1301787): avc: denied { connectto } for pid=17494 comm="nginx" path="/run/gunicorn.sock" scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=unix_stream_socket permissive=0
type=SYSCALL msg=audit(1569058175.985:1301787): arch=c000003e syscall=42 success=no exit=-13 a0=c a1=559e009bb000 a2=6e a3=7fffdb49de30 items=0 ppid=17493 pid=17494 auid=4294967295 uid=997 gid=994 euid=997 suid=997 fsuid=997 egid=994 sgid=994 fsgid=994 tty=(none) ses=4294967295 comm="nginx" exe="/usr/sbin/nginx" subj=system_u:system_r:httpd_t:s0 key=(null)
type=AVC msg=audit(1569058176.055:1301788): avc: denied { connectto } for pid=17494 comm="nginx" path="/run/gunicorn.sock" scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=unix_stream_socket permissive=0
type=SYSCALL msg=audit(1569058176.055:1301788): arch=c000003e syscall=42 success=no exit=-13 a0=c a1=559e009bb000 a2=6e a3=7fffdb49de30 items=0 ppid=17493 pid=17494 auid=4294967295 uid=997 gid=994 euid=997 suid=997 fsuid=997 egid=994 sgid=994 fsgid=994 tty=(none) ses=4294967295 comm="nginx" exe="/usr/sbin/nginx" subj=system_u:system_r:httpd_t:s0 key=(null)
type=AVC msg=audit(1569058176.082:1301789): avc: denied { connectto } for pid=17494 comm="nginx" path="/run/gunicorn.sock" scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=unix_stream_socket permissive=0
type=SYSCALL msg=audit(1569058176.082:1301789): arch=c000003e syscall=42 success=no exit=-13 a0=d a1=559e009bb000 a2=6e a3=7fffdb49de30 items=0 ppid=17493 pid=17494 auid=4294967295 uid=997 gid=994 euid=997 suid=997 fsuid=997 egid=994 sgid=994 fsgid=994 tty=(none) ses=4294967295 comm="nginx" exe="/usr/sbin/nginx" subj=system_u:system_r:httpd_t:s0 key=(null)
type=AVC msg=audit(1569058176.128:1301790): avc: denied { connectto } for pid=17494 comm="nginx" path="/run/gunicorn.sock" scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=unix_stream_socket permissive=0
type=SYSCALL msg=audit(1569058176.128:1301790): arch=c000003e syscall=42 success=no exit=-13 a0=d a1=559e009bb000 a2=6e a3=7fffdb49de30 items=0 ppid=17493 pid=17494 auid=4294967295 uid=997 gid=994 euid=997 suid=997 fsuid=997 egid=994 sgid=994 fsgid=994 tty=(none) ses=4294967295 comm="nginx" exe="/usr/sbin/nginx" subj=system_u:system_r:httpd_t:s0 key=(null)
After a look at:
nts.strzibny.name/allowing-nginx-to-use-a-pumaunicorn-unix-socket-with-selinux
I'll try using:
grep nginx /var/log/audit/audit.log | audit2allow -m nginx
The output of which is a suggested SELinux policy file.
[root@edgecase2 ~]# grep nginx /var/log/audit/audit.log | audit2allow -m nginx
module nginx 1.0;
require {
type unconfined_t;
type httpd_t;
class unix_stream_socket connectto;
}
#============= httpd_t ==============
#!!!! The file '/run/gunicorn.sock' is mislabeled on your system.
#!!!! Fix with $ restorecon -R -v /run/gunicorn.sock
allow httpd_t unconfined_t:unix_stream_socket connectto;
[root@edgecase2 ~]# restorecon -R -v /run/gunicorn.sock
[root@edgecase2 ~]# ls -Z /run/gunicorn.sock
srwxrwxrwx. root root unconfined_u:object_r:var_run_t:s0 /run/gunicorn.sock
[root@edgecase2 ~]# grep nginx /var/log/audit/audit.log | audit2allow -m nginx
module nginx 1.0;
require {
type unconfined_t;
type httpd_t;
class unix_stream_socket connectto;
}
#============= httpd_t ==============
#!!!! The file '/run/gunicorn.sock' is mislabeled on your system.
#!!!! Fix with $ restorecon -R -v /run/gunicorn.sock
allow httpd_t unconfined_t:unix_stream_socket connectto;
Excerpt from:
access.redhat.com/sites/default/files/attachments/what_is_selinux_trying_to_tell_me.pdf
SELinux is all about labels. Every process, file, directory, and device on an SELinux system has a label. If these labels are wrong, SELinux will not function properly. If a file is mislabeled, a confined application might not be allowed access to the mislabeled file. If an executable is mislabeled, it may not transition to the correct label when executing, causing access violations and potentially causing it to mislabel files it creates.
Excerpts from:
www.nginx.com/blog/using-nginx-plus-with-selinux
SELinux is enabled by default on modern RHEL and CentOS servers. Each operating system object (process, file descriptor, file, etc.) is labeled with an SELinux context that defines the permissions and operations the object can perform. In RHEL 6.6/CentOS 6.6 and later, NGINX is labeled with the httpd_t context.
[...]
The httpd_t context permits NGINX to listen on common web server ports, to access configuration files in /etc/nginx, and to access content in the standard docroot location (/usr/share/nginx). It does not permit many other operations, such as proxying to upstream locations or communicating with other processes through sockets.
I'll use some commands and approaches suggested by
www.nginx.com/blog/using-nginx-plus-with-selinux
[root@edgecase2 ~]# grep nginx /var/log/audit/audit.log | audit2why
type=AVC msg=audit(1569058175.985:1301787): avc: denied { connectto } for pid=17494 comm="nginx" path="/run/gunicorn.sock" scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=unix_stream_socket permissive=0
Was caused by:
Missing type enforcement (TE) allow rule.
You can use audit2allow to generate a loadable module to allow this access.
type=AVC msg=audit(1569058176.055:1301788): avc: denied { connectto } for pid=17494 comm="nginx" path="/run/gunicorn.sock" scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=unix_stream_socket permissive=0
Was caused by:
Missing type enforcement (TE) allow rule.
You can use audit2allow to generate a loadable module to allow this access.
type=AVC msg=audit(1569058176.082:1301789): avc: denied { connectto } for pid=17494 comm="nginx" path="/run/gunicorn.sock" scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=unix_stream_socket permissive=0
Was caused by:
Missing type enforcement (TE) allow rule.
You can use audit2allow to generate a loadable module to allow this access.
type=AVC msg=audit(1569058176.128:1301790): avc: denied { connectto } for pid=17494 comm="nginx" path="/run/gunicorn.sock" scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=unix_stream_socket permissive=0
Was caused by:
Missing type enforcement (TE) allow rule.
You can use audit2allow to generate a loadable module to allow this access.
[root@edgecase2 ~]# ls -Z /run/gunicorn.sock
srwxrwxrwx. root root unconfined_u:object_r:var_run_t:s0 /run/gunicorn.sock
[root@edgecase2 ~]# semanage fcontext -a -t httpd_sys_content_t /run/gunicorn.sock
ValueError: File spec /run/gunicorn.sock conflicts with equivalency rule '/run /var/run'; Try adding '/var/run/gunicorn.sock' instead
[root@edgecase2 ~]# semanage fcontext -a -t httpd_sys_content_t /var/run/gunicorn.sock
[root@edgecase2 ~]# ls -Z /run/gunicorn.sock
srwxrwxrwx. root root unconfined_u:object_r:var_run_t:s0 /run/gunicorn.sock
[root@edgecase2 ~]# restorecon -v /run/gunicorn.sock
restorecon reset /run/gunicorn.sock context unconfined_u:object_r:var_run_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
[root@edgecase2 ~]# ls -Z /run/gunicorn.sock
srwxrwxrwx. root root unconfined_u:object_r:httpd_sys_content_t:s0 /run/gunicorn.sock
Ok. /run/gunicorn.sock now has a label "httpd_sys_content_t" instead of "var_run_t". Hopefully, this means that an httpd process (e.g. nginx) can now access it.
[root@edgecase2 ~]# grep nginx /var/log/audit/audit.log | audit2allow -m nginx
module nginx 1.0;
require {
type unconfined_t;
type httpd_t;
class unix_stream_socket connectto;
}
#============= httpd_t ==============
#!!!! The file '/run/gunicorn.sock' is mislabeled on your system.
#!!!! Fix with $ restorecon -R -v /run/gunicorn.sock
allow httpd_t unconfined_t:unix_stream_socket connectto;
Hm. Still reported as mislabeled.
[root@edgecase2 ~]# restorecon -R -v /run/gunicorn.sock
[root@edgecase2 ~]# ls -Z /run/gunicorn.sock
srwxrwxrwx. root root unconfined_u:object_r:httpd_sys_content_t:s0 /run/gunicorn.sock
Browse to http://edgecasesystems.com:
nginx error!
[...]
[root@edgecase2 ~]# tail -1 /var/log/nginx/error.log
2019/09/21 09:54:59 [crit] 17494#0: *17 connect() to unix:/run/gunicorn.sock failed (13: Permission denied) while connecting to upstream, client: 82.11.184.184, server: _, request: "GET /poweredby.png HTTP/1.1", upstream: "http://unix:/run/gunicorn.sock:/poweredby.png", host: "edgecasesystems.com", referrer: "http://edgecasesystems.com/"
To generate a compiled policy, include the -M option:
[root@edgecase2 ~]# grep nginx /var/log/audit/audit.log | audit2allow -M nginx
******************** IMPORTANT ***********************
To make this policy package active, execute:
semodule -i nginx.pp
[root@edgecase2 ~]# semodule -i nginx.pp
[Verify success]
[root@edgecase2 ~]# semodule -l | grep nginx
nginx 1.0
Browse to http://edgecasesystems.com:
Hello, World!
[root@edgecase2 ~]# tail -1 /var/log/nginx/error.log
2019/09/21 09:54:59 [crit] 17494#0: *17 connect() to unix:/run/gunicorn.sock failed (13: Permission denied) while connecting to upstream, client: 82.11.184.184, server: _, request: "GET /poweredby.png HTTP/1.1", upstream: "http://unix:/run/gunicorn.sock:/poweredby.png", host: "edgecasesystems.com", referrer: "http://edgecasesystems.com/"
[root@edgecase2 ~]# tail -1 /var/log/nginx/access.log
[deleted] - - [21/Sep/2019:09:59:14 +0000] "GET / HTTP/1.1" 200 14 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0" "-"
[root@edgecase2 ~]# curl http://edgecasesystems.com/
Hello, World!
Excellent.
Cleanup:
press ctrl-C to stop the gunicorn process.
^C[2019-09-21 10:24:14 +0000] [17502] [INFO] Handling signal: int
[2019-09-21 10:24:14 +0000] [17507] [INFO] Worker exiting (pid: 17507)
[2019-09-21 10:24:14 +0000] [17502] [INFO] Shutting down: Master
[2019-09-21 10:24:14 +0000] [17507] [INFO] Worker exiting (pid: 17507)
[2019-09-21 10:24:14 +0000] [17502] [INFO] Shutting down: Master
Exit the bash shells.
That's the end of this project.
[start of notes]
Changes from the original text:
- I have not always preserved the format of any excerpts from webpages on other sites (e.g. not preserving the original bold/italic styles, changing the list structures, not preserving hyperlinks).
- I have not always preserved the format of any computer output (e.g. from running bash commands). Examples: Setting input lines in bold text, adding/removing newlines in order to make a sequence of commands easier to read, using hyphens for lists and sublists instead of indentation, breaking wide tables into consecutive sections, replacing non-ASCII curled single quotation marks with ASCII straight single quotation marks, replacing Unicode black square characters with ASCII underline characters.
- I have replaced instances of my IP address with "[deleted]".
[end of notes]