We are going to configure a couple of Apache virtual hosts, configure access restrictions on directories, deploy a basic CGI application and configure TLS security.
Install Apache
We use a RHEL 7.0 virtual server in this article.
Install a web server package group:
# yum groupinstall -y web-server
If we want to see what other groups are available, we can do:
# yum group list ids
Enable Apache service on boot and configure firewall:
# systemctl enable httpd && systemctl start httpd # firewall-cmd --permanent --add-service={http,https} # firewall-cmd --reload
Apache SELinux Related Settings
See what provides the packages that we need:
# yum provides *\sealert *\semanage *\sepolicy
Install required packages:
# yum install -y policycoreutils-python policycoreutils-devel setroubleshoot-server
Let us see the default SELinux context:
# ls -Z /var/www drwxr-xr-x. root root system_u:object_r:httpd_sys_script_exec_t:s0 cgi-bin drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 html
There are many SELinux booleans and context types for Apache. To get an overview of what’s available, do:
# getsebool -a | grep httpd # semanage fcontext --list | grep httpd
SELinux Booleans
Some the most significant boolean settings with their default values are listed below.
To allow Apache to modify public files (with the public_content_rw_t type) used for public file transfer services:
httpd_anon_write --> off
To allow Apache scripts and modules to connect to the network using TCP:
httpd_can_network_connect --> off
To allow Apache scripts and modules to connect to databases over the network:
httpd_can_network_connect_db --> off
To allow Apache to act as an FTP client connecting to the ftp port and ephemeral ports:
httpd_can_connect_ftp --> off
To allow Apache to connect to the LDAP port:
httpd_can_connect_ldap --> off
To allow Apache daemon to send mail:
httpd_can_sendmail --> off
To allow Apache CGI support:
httpd_enable_cgi --> on
To allow Apache to read home directories:
httpd_enable_homedirs --> off
To unify Apache to communicate with the terminal. Needed for entering the passphrase for certificates at the terminal:
httpd_tty_comm --> off
To allow Apache to access CIFS or NFS file systems:
httpd_use_cifs --> off httpd_use_nfs --> off
It can be tricky to remember all those SELinux setting above, therefore we need to know the place we can get some help.
The most powerful way of getting the SELinux information we need is by using man pages. On RHEL 7, however, SELinux man pages are not installed by default. We need to install them and update the manual page index caches:
# sepolicy manpage -a -p /usr/share/man/man8 # mandb
We can now search for SELinux pages:
# man -k _selinux | less
And we should find one for Apache:
httpd_selinux (8) - Security Enhanced Linux Policy for the httpd processes
SELinux Context
To mitigate security risks, different SELinux context types are available. Some are listed below:
- httpd_sys_content_t – set on directories that Apache is allowed access to,
- httpd_sys_content_rw_t – set on directories that Apache is allowed read/write access to,
- httpd_sys_script_exec_t – used for directories that contain executable scripts.
To allow Apache to modify public files used for public file transfer services, directories/files must be labeled public_content_rw_t.
SELinux Ports
SELinux prevents Apache from binding on non-default ports. To see which ports are allowed, do:
# semanage port --list | grep http http_cache_port_t tcp 8080, 8118, 8123, 10001-10010 http_cache_port_t udp 3130 http_port_t tcp 80, 81, 443, 488, 8008, 8009, 8443, 9000
Configure a Virtual Host
We are going to configure two virtual hosts, vhost1 and vhost2.
Open the file /etc/hosts
and add the following line:
10.8.8.71 vhost1.rhce.local vhost2.rhce.local
We use the “rhce.local” domain within our lab. As you may guess, it’s an RHCE preparation.
Basic Virtual Host vhost1
Create a DocumentRoot with some basic content:
# mkdir /var/www/html/vhost1 # echo "vhost1" >/var/www/html/vhost1/index.html # touch /var/www/html/vhost1/favicon.ico
Restore default SELinux security contexts:
# restorecon -Rv /var/www/html/vhost1
Create a virtual host configuration file /etc/httpd/conf.d/vhosts.conf
and add the following:
<VirtualHost *:80> ServerAdmin root@localhost ServerName vhost1.rhce.local DocumentRoot "/var/www/html/vhost1" <Directory "/var/www/html/vhost1"> Options None AllowOverride None Require all granted </Directory> LogLevel info ErrorLog "logs/vhost1-error_log" CustomLog "logs/vhost1-access_log" common </VirtualHost>
Open the file /etc/httpd/conf/httpd.conf
, find this line:
<Directory "/var/www/html">
And put the following:
Options None
Disable the default SSL site for now:
# mv /etc/httpd/conf.d/ssl.conf /etc/httpd/conf.d/ssl.conf.disabled
Test Apache configuration and restart the service:
# httpd -t # systemctl restart httpd
Check virtual hosts:
# httpd -t -D DUMP_VHOSTS VirtualHost configuration: *:80 is a NameVirtualHost default server vhost1.rhce.local (/etc/httpd/conf.d/vhosts.conf:1) port 80 namevhost vhost1.rhce.local (/etc/httpd/conf.d/vhosts.conf:1) port 80 namevhost vhost1.rhce.local (/etc/httpd/conf.d/vhosts.conf:1)
Install a CLI browser and test the site:
# yum install -y elinks # elinks http://vhost1.rhce.local/
Virtual Host on a TCP Port 8888 and Mounted iSCSI Device vhost2
Add the following to /etc/httpd/conf/httpd.conf
:
Listen 80 Listen 8888
If we now try to restart the Apache service, we’ll get the following error:
httpd[]: (13)Permission denied: AH00072: make_sock: could not bind to addres...:8888
SELinux is preventing Apache from binding to port 8888.
Allow Apache to listen on TCP port 8888:
# semanage port -a -t http_port_t -p tcp 8888
Configure firewall to allow inbound traffic:
# firewall-cmd --permanent --add-port=8888/tcp # firewall-cmd --reload
Create a DocumentRoot:
# mkdir /mnt/block1/vhost2 # echo "vhost2" >/mnt/block1/vhost2/index.html
Add file-context for everything under /mnt/block1
:
# semanage fcontext -a -t httpd_sys_content_t "/mnt/block1(/.*)?" # restorecon -Rv /mnt/block1
Open the file /etc/httpd/conf.d/vhosts.conf
and add the following:
<VirtualHost *:8888> ServerAdmin root@localhost ServerName vhost2.rhce.local DocumentRoot "/mnt/block1/vhost2" <Directory "/mnt/block1/vhost2"> Options None AllowOverride None Require all granted </Directory> LogLevel error ErrorLog "logs/vhost2-error_log" CustomLog "logs/vhost2-access_log" common </VirtualHost>
Check configuration and restart the service:
# httpd -t # systemctl restart httpd
A new virtual host should now be listed:
# httpd -t -D DUMP_VHOSTS VirtualHost configuration: *:80 is a NameVirtualHost default server vhost1.rhce.local (/etc/httpd/conf.d/vhosts.conf:1) port 80 namevhost vhost1.rhce.local (/etc/httpd/conf.d/vhosts.conf:1) port 80 namevhost vhost1.rhce.local (/etc/httpd/conf.d/vhosts.conf:1) *:8888 is a NameVirtualHost default server vhost2.rhce.local (/etc/httpd/conf.d/vhosts.conf:17) port 8888 namevhost vhost2.rhce.local (/etc/httpd/conf.d/vhosts.conf:17) port 8888 namevhost vhost2.rhce.local (/etc/httpd/conf.d/vhosts.conf:17)
Test:
# elinks http://vhost2.rhce.local:8888/
Now, if we had a virtual host on an NFS share, we would want to allow Apache to access NFS file system. We would need to tell SELinux about this by enabling the httpd_use_nfs boolean:
# setsebool -P httpd_use_nfs=1
Another way to allow Apache to access files on NFS without enabling the boolean above would be to label them as httpd_sys_content_t or public_content_t (SELinux fcontext), othewise search permissions will be missing.
Configure Access Restrictions on Directories
We are going to configure authentication on a per-directory basis.
Host-based Security
On the vhost1, create a private directory that we can use with host-based restrictions:
# mkdir /var/www/html/vhost1/private # echo "private-vh1" >/var/www/html/vhost1/private/index.html
Open the file /etc/httpd/conf.d/vhosts.conf
and add the following under the vhost1 configuration:
<Directory "/var/www/html/vhost1/private"> AllowOverride None Options None Require ip 10.8.8.1/32 </Directory>
Access to the private directory is allowed from the IP 10.8.8.1/32 only.
Now, if we try locally, we should get a 403 permission denied error.
# elinks http://vhost1.rhce.local/private/
If we wanted to allow access to every client but the IP 10.8.8.1/32, we would configure the virtual host this way:
<Directory "/var/www/html/vhost1/private"> AllowOverride None Options None <RequireAll> Require all granted Require not ip 10.8.8.1/32 </RequireAll> </Directory>
Visitors coming from the address 10.8.8.1 will not be able to see any content.
As per Apache documentation, the Require provides a variety of different ways to allow or deny access to resources. In conjunction with the RequireAll, RequireAny and RequireNone directives, these requirements may be combined in arbitrarily complex ways, to enforce whatever access policy we want to have.
By default all Require directives are handled as though contained within a RequireAny container directive. In other words, if any of the specified authorisation methods succeed, then authorisation is granted.
For example, access restriction below would allow connections to portions of our site from any client but my1337.hacker.local, *.example.com and subnet 10.8.8.0/24:
<RequireAll> Require all granted Require not host my1337.hacker.local Require not host example.com Require not ip 10.8.8.0/24 </RequireAll
Only complete components are matched, so the above example will match test.example.org but it will not match testexample.org. This configuration will cause Apache to perform a double reverse DNS lookup on the client IP address, regardless of the setting of the HostnameLookups directive. It will do a reverse DNS lookup on the IP address to find the associated hostname, and then do a forward lookup on the hostname to assure that it matches the original IP address. Only if the forward and reverse DNS are consistent and the hostname matches will access be allowed.
User-based Security
On the vhost2, create a private directory that we can use for user-based authentication:
# mkdir /mnt/block1/vhost2/private # echo "private-vh2" >/mnt/block1/vhost2/private/index.html
Create a password file /etc/httpd/conf/htpasswd
to use with Apache, and add a couple of users, alice and vince:
# htpasswd -c /etc/httpd/conf/htpasswd alice # htpasswd /etc/httpd/conf/htpasswd vince
Open the file /etc/httpd/conf.d/vhosts.conf
and add the following under the vhost2 configuration:
<Directory "/mnt/block1/vhost2/private"> AuthType Basic AuthName "Private" AuthUserFile "/etc/httpd/conf/htpasswd" Require user vince </Directory>
To make Apache authentication configuration easier to remember, we can use the httpd-manual package:
# yum install -y httpd-manual
Manual pages can be accessed on the localhost:
# elinks http://localhost/manual/
However, rather than browsing the whole site, it’s sometimes easier to open specific pages (they are located under /usr/share/httpd/manual/
) which we are interested in, for example, a manual to basic authentication:
# elinks /usr/share/httpd/manual/mod/mod_auth_basic.html
Check configuration for errors and restart the service:
# httpd -t # systemctl restart httpd
Testing time, only logging in with vince’s credentials should allow access:
# elinks http://vhost2.rhce.local:8888/private/
Group Based Security
On the vhost2, create a group directory that we can use for group-based authentication:
# mkdir /mnt/block1/vhost2/group # echo "group" >/mnt/block1/vhost2/group/index.html
Add another user, sandy, to the Apache password file:
# htpasswd /etc/httpd/conf/htpasswd sandy
Create a group file /etc/httpd/conf/htgroup
to use with Apache, and add the following:
admins: alice sandy
Open the file /etc/httpd/conf.d/vhosts.conf
and add the following under the vhost2 configuration:
<Directory "/mnt/block1/vhost2/group"> AuthType Basic AuthName "Group" AuthGroupFile "/etc/httpd/conf/htgroup" AuthUserFile "/etc/httpd/conf/htpasswd" Require group admins </Directory>
As always, check the config and restart the service:
# httpd -t # systemctl restart httpd
Now logging in with vince’s credentials shouldn’t work, as only alice and sandy are members of the admins group.
# elinks http://vhost2.rhce.local:8888/group/
Configure Group-managed Content
By default, only the root user has write access to the DocumentRoot. If we have a group of users who need to be able to write files to the DocumentRoot, we need to configure write access.
To set an ACL that allows members of the devops group write access to the DocumentRoot of the vhost2 virtual host, we can use the following commands:
# groupadd devops # setfacl -R -m g:devops:rwX /mnt/block1/vhost2 # setfacl -R -m d:g:devops:rwx /mnt/block1/vhost2
An uppercase X is used to set the execute bit only to directories and not to files.
# getfacl /mnt/block1/vhost2 # file: mnt/block1/vhost2 # owner: root # group: root user::rwx group::r-x group:devops:rwx mask::rwx other::r-x default:user::rwx default:group::r-x default:group:devops:rwx default:mask::rwx default:other::r-x
Add a user to the devops group, login and try to create a new file to see if all works as expected:
# useradd -m -G devops dev1 # su - dev1 $ touch /mnt/block1/vhost2/somefile
Write a Basic CGI Application
We are going to write a bash application on the virtual host vhost2 that sends an email to the root user. We are going to need the mailx package:
# yum install -y mailx
There should be no mail at the moment:
# mailx No mail for root
Create a folder to store web applications:
# mkdir /mnt/block1/vhost2/app
Create a web application and make it executable:
# touch /mnt/block1/vhost2/app/email.sh # chmod a+x /mnt/block1/vhost2/app/email.sh
Now, as per Apache documentation, there are two main differences between “regular” programming, and CGI programming.
First, all output from our CGI program must be preceded by a MIME-type header. This is HTTP header that tells the client what sort of content it is receiving. Most of the time, this will look like Content-type: text/html
.
Secondly, our output needs to be in HTML, or some other format that a browser will be able to display. Most of the time, this will be HTML, but occasionally we might write a CGI program that outputs a gif image, or other non-HTML content.
Taking the above into account, we can use the following content for our CGI application:
#!/bin/bash echo -e "Content-type: text/html\n\n"; echo "<html>"; echo "<body>"; echo "email from httpd"|mailx -s WebApp root; echo "Email has been sent."; echo "</body>"; echo "</html>";
The first line tells Apache that this program can be executed by feeding the file to the interpreter found at the location /bin/bash
. The second line prints the content-type declaration we talked about, followed by two carriage-return newline pairs. This puts a blank line after the header to indicate the end of the HTTP headers, and the beginning of the body. The other lines send an email to the root user and print the string “Email has been sent.”.
One other thing, we need to take care of SELinux context for the app folder.
Let us take a look at the defaults:
# ls -Z /var/www/ drwxr-xr-x. root root system_u:object_r:httpd_sys_script_exec_t:s0 cgi-bin drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 html
We are going to apply the same context as for the cgi-bin folder:
# semanage fcontext -a -t httpd_sys_script_exec_t "/mnt/block1/vhost2/app(/.*)?" # restorecon -Rv /mnt/block1/vhost2/app
Note that there is a very good example in the “Examples” section at the end of man semanage-fcontext.
We also need to allow Apache to send emails permanently, otherwise SELinux will block them:
# setsebool -P httpd_can_sendmail=1
Open the file /etc/httpd/conf.d/vhosts.conf
and add the following under the vhost2 configuration:
<Directory "/mnt/block1/vhost2/app"> AllowOverride None Options ExecCGI AddHandler cgi-script .sh Require all granted </Directory>
We basically want to allow CGI program execution for any file ending .sh in the app directory.
Remember the http-manual package that we installed previously? Handy CGI configuration examples can be found here:
# elinks /usr/share/httpd/manual/howto/cgi.html
Verify configuration and restart the service:
# httpd -t # systemctl restart httpd
Test:
# elinks http://vhost2.rhce.local:8888/app/email.sh
There should be an email received from Apache:
# mailx -H > 1 Apache Mon May 30 19:27 19/611 "WebApp"
Configure TLS Security
TLS Virtual Host
Let us take care of the firewall first, if not already configured:
# firewall-cmd --permanent --add-service=https # firewall-cmd --reload
We can generate an SSL certificate with openssl, or with genkey. For the latter, install the following:
# yum install crypto-utils
If we were to use genkey, it would look something like this:
# genkey --days 365 vhost1.rhce.local
However, a faster way for us to create a certificate is with openssl. For those struggling to remember the syntax, take a look at the file /etc/pki/tls/certs/make-dummy-cert
. It contains the following line:
openssl req -newkey rsa:2048 -keyout $PEM1 -nodes -x509 -days 365 -out $PEM2
That’s all we need to generate a new self-signed SSL certificate.
# openssl req -newkey rsa:2048 -keyout /etc/pki/tls/private/vhost1.rhce.local.key \ -nodes -x509 -days 365 -out /etc/pki/tls/certs/vhost1.rhce.local.crt
Ensure the Common Name matches with the ServerName for the virtual host the certificate is generated for.
Enable the default SSL host:
# mv /etc/httpd/conf.d/ssl.conf.disabled /etc/httpd/conf.d/ssl.conf
Open the file and add the following, right under the <VirtualHost _default_:443>
:
DocumentRoot "/var/www/html/vhost1" ServerName vhost1.rhce.local SSLEngine on SSLProtocol all -SSLv2 -SSLv3 SSLCertificateFile /etc/pki/tls/certs/vhost1.rhce.local.crt SSLCertificateKeyFile /etc/pki/tls/private/vhost1.rhce.local.key
Check configuration and restart the service:
# httpd -t # systemctl restart httpd
TLS virtual host should be present now:
# httpd -t -D DUMP_VHOSTS VirtualHost configuration: *:443 is a NameVirtualHost default server vhost1.rhce.local (/etc/httpd/conf.d/ssl.conf:56) port 443 namevhost vhost1.rhce.local (/etc/httpd/conf.d/ssl.conf:56) port 443 namevhost vhost1.rhce.local (/etc/httpd/conf.d/ssl.conf:56) *:80 is a NameVirtualHost default server vhost1.rhce.local (/etc/httpd/conf.d/vhosts.conf:1) port 80 namevhost vhost1.rhce.local (/etc/httpd/conf.d/vhosts.conf:1) port 80 namevhost vhost1.rhce.local (/etc/httpd/conf.d/vhosts.conf:1) *:8888 is a NameVirtualHost default server vhost2.rhce.local (/etc/httpd/conf.d/vhosts.conf:26) port 8888 namevhost vhost2.rhce.local (/etc/httpd/conf.d/vhosts.conf:26) port 8888 namevhost vhost2.rhce.local (/etc/httpd/conf.d/vhosts.conf:26)
Note that elinks may not work with SSL, test with curl instead:
# curl --insecure https://vhost1.rhce.local vhost1
Check if SSLv3 is disabled (it’s considered insecure nowadays):
# curl --insecure --sslv3 https://vhost1.rhce.local curl: (35) Cannot communicate securely with peer: no common encryption algorithm(s).
Redirect to TLS
We want all HTTP traffic coming to the vhost1 to be redirected to HTTPS automatically.
We may configure the above by using mod_rewrite:
RewriteEngine On RewriteCond %{HTTPS} off RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
However, if we check the manual, there is a simple redirect that we can use:
# elinks /usr/share/httpd/manual/rewrite/avoid.html
Let us add the below line to the vhost1 configuration:
Redirect / https://vhost1.rhce.local/
Test configuration and restart the service:
# httpd -t # systemctl restart httpd
Test with curl, automatic rewrite should be working:
# curl -v -L --insecure http://vhost1.rhce.local * About to connect() to vhost1.rhce.local port 80 (#0) * Trying 10.8.8.71... * Connected to vhost1.rhce.local (10.8.8.71) port 80 (#0) > GET / HTTP/1.1 > User-Agent: curl/7.29.0 > Host: vhost1.rhce.local > Accept: */* > < HTTP/1.1 302 Found < Date: Mon, 30 May 2016 18:55:44 GMT < Server: Apache/2.4.6 (Red Hat) OpenSSL/1.0.1e-fips mod_fcgid/2.3.9 < Location: https://vhost1.rhce.local/ < Content-Length: 210 < Content-Type: text/html; charset=iso-8859-1 < * Ignoring the response-body * Connection #0 to host vhost1.rhce.local left intact * Issue another request to this URL: 'https://vhost1.rhce.local/' * Found bundle for host vhost1.rhce.local: 0x7542c0 * About to connect() to vhost1.rhce.local port 443 (#1) * Trying 10.8.8.71... * Connected to vhost1.rhce.local (10.8.8.71) port 443 (#1) * Initializing NSS with certpath: sql:/etc/pki/nssdb * skipping SSL peer certificate verification * SSL connection using TLS_DHE_RSA_WITH_AES_128_CBC_SHA * Server certificate: * subject: CN=vhost1.rhce.local,O=vhost1,L=vhost1,C=GB * start date: May 30 18:22:37 2016 GMT * expire date: May 30 18:22:37 2017 GMT * common name: vhost1.rhce.local * issuer: CN=vhost1.rhce.local,O=vhost1,L=vhost1,C=GB > GET / HTTP/1.1 > User-Agent: curl/7.29.0 > Host: vhost1.rhce.local > Accept: */* > < HTTP/1.1 200 OK < Date: Mon, 30 May 2016 18:55:44 GMT < Server: Apache/2.4.6 (Red Hat) OpenSSL/1.0.1e-fips mod_fcgid/2.3.9 < Last-Modified: Mon, 30 May 2016 17:19:37 GMT < ETag: "7-534127600f458" < Accept-Ranges: bytes < Content-Length: 7 < Content-Type: text/html; charset=UTF-8 < vhost1 * Connection #1 to host vhost1.rhce.local left intact
I have been following up closely and practising on the examples on your blog , there are exceptionally explained
I have noted this sub topic “Configure Group-managed Content” on this page ,i think this goes against the objective below
HTTP/HTTPS
Configure a virtsdual host
Configure access restrictions on directories
Deploy a basic CGI application
Configure group-managed content
Configure TLS security
Group managed content should be what you explained on this sub topic below
“Group Based Security ” ,unless my understanding of the objective is skewed.
“Configure Group-managed Content” sub topic on this blog post aims to explain the RHCE objectives that are listed under the section “Configure group-managed content” on the Red Hat website.
Is the context httpd_sys_content_rw_t correct?
Worked with httpd_sys_rw_content_t though which I guess is the right one.
You’re right, it should be httpd_sys_rw_content_t rather than httpd_sys_content_rw_t. Updated the article.
It’s funny that Sander’s book also mentions httpd_sys_content_rw_t :) That’s where I got it wrong I believe.
Hi Tomas,
I follow httpd-manual to set up the host-based restriction on server1 to only allow access the “private” directory from server2.
AllowOverride None
Options None
Require host server2.example.com
I receive “403-permission denied” error (as expected) on server1; however, I but also receive the same “403-permission denied” error on server2!
I have tried using server2’s IP address instead of hostname, but still have the same error.
Do I miss any other directives for host-based access?
Do you have an index file? You may be getting 403 permission denied because you have no index file and directory listing is disabled.
Hi Tomas,
is there any difference between:
# setfacl -R -m g:devops:rwX /mnt/block1/vhost2
# setfacl -R -m d:g:devops:rwx /mnt/block1/vhost2
and
# chmod 2770 /mnt/block1/vhost2
?
There is a difference. One sets permissions based on owner group all, while another allows for much greater control over who has access to a specific file or folder.
Hi,
thanks for the great article. I think I found a typo in the SSL host configuration, line:
SSLCertificateFile /etc/pki/tls/certs/vhost1.rhce.local.key
I think you meant:
SSLCertificateFile /etc/pki/tls/certs/vhost1.rhce.local.crt
Otherwise the https virtual host won’t work because Apache won’t find the certificate generated before
You’re right, many thanks for spotting it! Fixed now.
Hi Tomas,
First of all thanks for all the articles on your site, its a great resource.
I think I got everything to work on vhosts and allowing/disallowing access to certain sites or directories. There one thing that bothers me though and I’d appreciate it if you can comment.
I have this part:
documentroot /var/www/html
order deny,allow
deny from all
allow from 127.0.0.1 ::1 192.168.4.210
servername server1.example.com
errorlog “logs/server1-error.log”
customlog “logs/server1-access.log” combined
it works fine, I see the index.html contents when allowed and I get an error message when it is disallowed.
Then I have this part:
documentroot /srv/www.test.com
allowoverride none
options none
require all granted
require not host labipa.example.com
require not ip 10.0.0.0/24
servername test.com
errorlog “logs/www.test.com-error.log”
customlog “logs/www.test.com-access.log” combined
When allowed, I get the index.html with the ‘welcome to test.com’ page. When not allowed, it actually redirects me to the default site in /var/www/html instead of giving me an error.
When I, from a host disallowed, go to /index.html, it does actually give me an error message.
The difference is that when it redirects me, I get a regular HTTP/200 but when it is disallowed, I get the HTTP/403 permission denied.
Depending on how the exam is tested, I am worried that the redirect gives the HTTP/200 and I will fail for this part.
In any case, I’d love to know how to force the error code when going to test.com as is the case with test.com/index.html. I don’t want the fallback to the default site.
Do you have any ideas?
Thanks a lot!
Ow the directives have disappeared. Hopefully this works using code tags – sorry!
[code]
documentroot /var/www/html
order deny,allow
deny from all
allow from 127.0.0.1 ::1 192.168.4.210
servername server1.example.com
errorlog “logs/server1-error.log”
customlog “logs/server1-access.log” combined
[/code]
[code]
documentroot /srv/www.example.com
allowoverride none
options none
require all granted
require not host labipa.example.com
require not ip 10.0.0.0/24
#order deny,allow
#deny from all
#allow from 127.0.0.1 ::1 192.168.4.0/24
servername http://www.example.com
errorlog “logs/www.example.com-error.log”
customlog “logs/www.example.com-access.log” combined
[/code]
I don’t think it worked, these aren’t valid HTML tags.
Try posting your Apache config but without any angle brackets. I should be able to figure it out.
As you can see WordPress isn’t great when it comes to syntax formatting.
Thanks!
Your comment contains Apache syntax for both 2.2 and 2.4, this is confusing. Which version do you use?
Hi Tomas,
Thanks for your quick reply. I am using:
httpd.x86_64 2.4.6-45.el7.centos
As for the config, it is here:
Which parts exactly are 2.2 and which are 2.4? Should I avoid 2.2 syntax?
Thanks again!
Please see here (the Access Control section): https://httpd.apache.org/docs/current/upgrading.html
2.2 use “Order”, where 2.4 should use “Require”.
Thanks Tomas.
So basically the vhost with 2.2 config works as expected, and the test.com vhost with 2.4 syntax isn’t :).
Any ideas why I see the behavior I described earlier? I just changed it to 2.2 syntax and it behaves exactly the same.
Browsing to test.com from 10.0.0./24 redirects to the default site and forcing to test.com/index.html shows the no permissions warning.
Browsing from an allowed host to test.com shows the page (index.html).
Do you have DirectoryIndex defined for the site server1.example.com? Check
httpd.conf
. If you do, make sure you have it for the other site as well.Also, make sure that SELinux does not block access to the index.html page for the test website:
http.conf contains the following, obviously with greater/smaller than characters. This is a global setting, not specific for any sites:
[IfModule dir_module]
DirectoryIndex index.html
[</IfModule]
There are no denies from selinux, the context is set and when accessing the site from a host that is allowed, the page shows.
Maybe I am looking at default behavior, I don't know.
maybe I should try setting the restrictions on the default site it redirects to, see what that does.
I was unable to replicate the problem even though I copied and pasted your Apache configuration.
Show me the output of the following please.
From a server inside 10.0.0.0/24:
Plus Apache access and error log records for the request above.
From a server inside 10.0.0.0/24:
Plus Apache access and error log records for the request above.
Also post the output of the following:
Since you can’t replicate I decided to reset both my virtual machines and start over. I do this daily anyway to practise for the exam.
If I run into the issue again, I will post the details you ask for. I see you are using curl, I am using elinks. When I look in my logs after I try to access from within 10.0.0.0/24, I first see the HTTP/403 permission denied followed by several HTTP/200 for the default. So maybe elinks is doing something automatically that curl isn’t doing. I’d be chasing a red herring, so to speak :).
In any case, thanks for taking the time to respond and help out! I’ll let you know how it works out. Exam is 6 nov and my RHCSA expires 7 nov … so no slacking allowed! ;-).
Good luck with your exam!
Hello Tomas,
Is this configuration possible.
Main Server: we setup main server with /etc/http/conf/httpd.conf (without virtual host )
Virtual Server :Then setup a new virtual host using /etc/httpd/conf.d/xx.conf
Both main server and v server should work normally
or
we need to setup both the servers under virtual hosting ?? to make them work ?
You can use any file to define your virtualhost configuration, it can go into
httpd.conf
, or can be split into separate files.I think i did not put my question well.
my question is will both servers work fine if one is defined in virtual.conf and other in httpd.conf ( with out virtual)
or do we need all the server as virtual if we want multiple servers ??
OK, I sense some confusion here. You use VirtualHost when you want to serve more than one domain (website) on a single server. Now, when you add a name-based virtual host to an existing server, and the virtual host arguments match pre-existing IP and port combinations, requests will be handled by an explicit virtual host. If you want to keep the default Apache website (which is in
/var/www/html
), I suggest you create a default virtual host for it. I hope this clarifies things.Redirection does not work for me ..
Virtual host config:
—–
DocumentRoot “/var/www/html/vhost1”
ServerName vhost1.example.local
Redirect /var/www/html/vhost1 https:// vhost1.example.local/
—-
#curl -k https:// vhost1.example.local
vhost1
—
#curl http:// vhost1.example.local
display the default apache page .
Pls support
You’re redirecting /var/www/html/vhost1 to https:// vhost1.example.local/, but when you run a test, you use / as the path and not /var/www/html/vhost1. You may want to look up mod_alias for more info.
Trying this also does not make any difference
Redirect / https:// vhost1.example.local/
I have read documentaion , but does not seem to work.
same output.
can you please give me a clue where i am making mistake.
Can you post the output of the following:
Also post full Apache config for the vhost1 virtual host. Note that if you don’t use valid HTML then your Apache directives will be lost (thanks to WordPress), therefore post the config on pastebin instead and provide the URL.
Anyone who get require to work, i have tried ip and host but nothing seems to work, running Server version: Apache/2.4.6 (CentOS).
AuthType Basic
AuthName “Restricted Files”
# (Following line optional)
AuthBasicProvider file
AuthUserFile /etc/httpd/conf/passwords
Require all granted
Require not host maui.example.com
Require user gary
What are you trying to achieve and what does not work in particular?
trying to achieve to not give access to maui, and get access to gary, gary works just fine but maui have all access.
Do you have a reverse DNS zone for the domain configured?
yes.
OK, try accessing from the host maui.example.com, and post Apache server logs for that connection.
I installed free ipa using sanders instructions.
I’m not familiar with Sander’s instructions as I use my own FreeIPA server.
Hi Tomas,
So doing the
#yum groupinstall web-server
I get and error with
There is no installed groups file.
Maybe run: yum groups mark convert (see man yum)
Loading mirror speeds from cached hostfile
Warning: group web-server does not exist.
Maybe run: yum groups mark install (see man yum)
Error: No packages in any requested group available to install or update
So understandably I don’t have the “groups file”!
How do i create that in the yum repo on my IPA server? Have any ideas? I haven’t found much when googling :(
Thanks
Now I’ve googled a bit more and have fixed it for those who are not getting groups with their local repos.
My DVD is mounted on /mnt and at the mo I’m using Apache to share my repos under /var/www/http/localrepo (change to ftp folder if using vsftp)
With that you can fix it with 2 lines:
[root@ipa localrepo]# cp /mnt/repodata/*comps*.xml /var/www/http/localrepo/repodata/comps.xml
[root@ipa localrepo]# createrepo -g repodata/comps.xml .
Good to know :)
Thanks, I’m glad that you figured it out.
Hello, Tomas. This blog is very useful, thank you!
I have a problem (rhel 7.4, httpd 2.4.6, elinks 0.12-0.36).
After I configured user-based or group-based security using this manual line-by-line (httpd’s syntax was checked and the service was restarted), when I try to check this configuration by the elinks, after the ht user logins I get the message: 301 Moved Permanently “The document has moved here”.
If I specify the absolute path elinks http:// vhost2.rhce.local:8888/private/index.html, I get 401 Unauthorized.
The log contents the messages only: 192.168.10.3 – alice … “GET /private/index.html HTP/1.1”
No error/warning messages found.
I tried to reconfigure a secure directory to vhost1.rhel.local, the htpasswd configuration, other user’s credentials but the same error was showed. And I also did it on the fresh installed CentOS 7.4 server and I get the same issues.
If I replace Auth* lines on ‘Require all granted’, the error disapiared and it works well but without privacy.
My RHCE Exam will be 07 March and I worry now =)
Do you have any ideas?
Thank you!
Where does the page move to? Check the log to see where 301 redirect sends it to.
I’ve checked all httpd’s logs again and don’t find any messages related with redirection except as the message above. I didn’t edite the default httpd.conf file and the vhost.conf file does not content any redirection settings. I notice if press Enter in the elinks when the 302 message appears, the line “private-vh1” from the private/index.html is shown there. I’ve checked it out with the Firefox now and it works well, without 302.
On the exam the task maybe defined like “The page should say Hello”. I hope that the rhel checking script will not use the elinks and not consider this point as my error ;)
Thank you for answering!
Good luck with your exam!
Hello,
The brief remark. In the block “User Based Security”, better to use # elinks http:// vhost2.rhce.local:8888/private/, with a forward slash at the end of the line (now it is not there). In other case, may be errors.
Thank you, this is helpful.
Hey dude, excellent content, I am a bit disappointed how Sander went over his RHCE course, but your materials definitely helped, I will take my RHCE shortly, will let you know how it went :) !
Thanks, and good luck with your exam!
Having an issue with a CGI Virtual Host, it only works if I have Selinux in permissive mode. Otherwise I get 500 Internal Server Error and this in my log:
[Fri Jan 11 13:26:25.419842 2019] [cgi:error] [pid 3472] [client 172.28.14.250:56184] AH01215: /bin/bash: /etc/httpd/conf.d/vhosts/rhce3/rhce3.sh: Permission denied
[Fri Jan 11 13:26:25.419865 2019] [cgi:error] [pid 3472] [client 172.28.14.250:56184] End of script output before headers: rhce3.sh
[root@prod conf.d]# cat rhce3.example.com.conf
ServerName rhce3.example.com
ServerAlias ww.rhce3.example.com
DocumentRoot /etc/httpd/conf.d/vhosts/rhce3
DirectoryIndex rhce3.sh
Options ExecCGI
SetHandler cgi-script
[root@prod ~]# ll -Z /etc/httpd/conf.d/vhosts/rhce3/rhce3.sh
-rwxr-xr-x. root root unconfined_u:object_r:httpd_sys_script_exec_t:s0 /etc/httpd/conf.d/vhosts/rhce3/rhce3.sh
[root@prod conf.d]# getsebool -a | grep httpd_enable_cgi
httpd_enable_cgi –> on
Any ideas?
The first thing to do when you hit an SElinux issue is to look at the audit log
/var/log/audit/audit.log
. See what gets blocked, and try to resolve accordingly.My script contained lsblk, which SELinux doesn’t like.
I ran sealert -a /var/log/audit/audit.log:
SELinux is preventing /usr/bin/lsblk from read access on the file
SELinux is preventing /usr/bin/lsblk from getattr access on the file
SELinux is preventing /usr/libexec/colord from getattr access on the file
Unrelated question… I’ve been using elinks in combination with Firefox to test out httpd configurations. The latter is much easier to work with. Can I have access to a graphical browser on the exam?
I’m glad that you managed to resolve it.
I don’t know about a graphical browser, but have you tried
elinks -dump
? It’s great for viewing content.Hi Tomas,
If I want to configure virtual host and still be able to see web server configured in httpd.conf, do I need to reconfigured it to be also as virtual host?
You have this quiestion in sample tes, and I assume, that only solution is configure all web servers ase virtual hosts (if we are talking about named based virtual host, which are needed for RHCE — at least Sander Van Vugt mention that ip based is not objective)
Here guy has similar problem:
https://stackoverflow.com/questions/15103945/apache-vhost-overriding-config
You can configure it as a virtual host.
Hi Tomas,
Im having a small problem. Im Trying to redirect the http traffic to https but it is not redirecting. I have two vhosts vhost1 and vhost2
vhost1 displays “This is Site1”
vhost2 displays “This is Site2”
vhost2 is setup for https, content of vhost2.conf
ServerName vhost2.rhce.local
Redirect / https:// vhost2.rhce.local/
SSLEngine on
SSLProtocol all -SSLv2 -SSLv3
SSLCertificateFile /etc/pki/tls/certs/vhost2.rhce.local.crt
SSLCertificateKeyFile /etc/pki/tls/private/vhost2.rhce.local.key
ServerAdmin admin@localhost
DocumentRoot “/var/www/html/vhost2”
options none
allowoverride none
require all granted
ServerName vhost2.rhce.local
loglevel info
ErrorLog “logs/vhost2_error_log”
CustomLog “logs/vhost2_access_log” common
What error do you get? Anything in the Apache log file?
[Thu Apr 04 10:52:56.231833 2019] [ssl:info] [pid 1410] AH01914: Configuring server vhost2.rhce.local:443 for SSL protocol
[Thu Apr 04 10:52:56.232330 2019] [ssl:debug] [pid 1410] ssl_engine_init.c(331): AH01893: Configuring TLS extension handling
[Thu Apr 04 10:52:56.232343 2019] [ssl:debug] [pid 1410] ssl_engine_init.c(842): AH02232: Configuring RSA server certificate
[Thu Apr 04 10:52:56.232703 2019] [ssl:warn] [pid 1410] AH01906: RSA server certificate is a CA certificate (BasicConstraints: CA == TRUE !?)
[Thu Apr 04 10:52:56.232811 2019] [ssl:debug] [pid 1410] ssl_util_ssl.c(407): AH02412: [vhost2.rhce.local:443] Cert matches for name ‘vhost2.rhce.local’ [subject: CN=vhost2.rhce.local,O=Default Company Ltd,L=Default City,C=SA / issuer: CN=vhost2.rhce.local,O=Default Company Ltd,L=Default City,C=SA / serial: 978F3032E80BEB91 / notbefore: Apr 2 08:44:23 2019 GMT / notafter: Apr 1 08:44:23 2020 GMT]
[Thu Apr 04 10:52:56.232825 2019] [ssl:debug] [pid 1410] ssl_engine_init.c(897): AH02236: Configuring RSA server private key
[Thu Apr 04 10:53:16.555295 2019] [ssl:info] [pid 1410] AH02200: Loading certificate & private key of SSL-aware server ‘vhost2.rhce.local:443’
[Thu Apr 04 10:53:16.555902 2019] [ssl:debug] [pid 1410] ssl_engine_pphrase.c(506): AH02249: unencrypted RSA private key – pass phrase not required
[Thu Apr 04 10:53:16.556925 2019] [ssl:info] [pid 1410] AH01914: Configuring server vhost2.rhce.local:443 for SSL protocol
[Thu Apr 04 10:53:16.559696 2019] [ssl:debug] [pid 1410] ssl_engine_init.c(331): AH01893: Configuring TLS extension handling
[Thu Apr 04 10:53:16.559724 2019] [ssl:debug] [pid 1410] ssl_engine_init.c(842): AH02232: Configuring RSA server certificate
[Thu Apr 04 10:53:16.559908 2019] [ssl:warn] [pid 1410] AH01906: RSA server certificate is a CA certificate (BasicConstraints: CA == TRUE !?)
[Thu Apr 04 10:53:16.560378 2019] [ssl:debug] [pid 1410] ssl_util_ssl.c(407): AH02412: [vhost2.rhce.local:443] Cert matches for name ‘vhost2.rhce.local’ [subject: CN=vhost2.rhce.local,O=Default Company Ltd,L=Default City,C=SA / issuer: CN=vhost2.rhce.local,O=Default Company Ltd,L=Default City,C=SA / serial: 978F3032E80BEB91 / notbefore: Apr 2 08:44:23 2019 GMT / notafter: Apr 1 08:44:23 2020 GMT]
[Thu Apr 04 10:53:16.560400 2019] [ssl:debug] [pid 1410] ssl_engine_init.c(897): AH02236: Configuring RSA server private key
These are the messages in error log, i dont see any problem
These are only SSL logs that you’ve posted, how about others?
When you say it’s not redirecting, what happens exactly?
When i manually type “https://vhost2.rhce.local” it displays “This is Site2” but when i type “http://vhost2.rhce.local” it show “This is site1”
Can you post the output from curl:
Also post the output from Apache:
Tomas actually i restored the snapshot of VM so old settings are gone. But this time same issue happening on serv1.rhce.local vhost(I’m using your provided sample exam)
$ curl -IL serv1.rhce.local
HTTP/1.1 403 Forbidden
Date: Tue, 09 Apr 2019 09:27:36 GMT
Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.1e-fips mod_fcgid/2.3.9
Last-Modified: Tue, 17 Jun 2014 16:00:47 GMT
ETag: “1310-4fc0a3f32a9c0”
Accept-Ranges: bytes
Content-Length: 4880
Content-Type: text/html; charset=UTF-8
# httpd -t -D DUMP_VHOSTS
VirtualHost configuration:
*:443 is a NameVirtualHost
default server serv1.rhce.local (/etc/httpd/conf.d/serv1-vhost.conf:1)
port 443 namevhost serv1.rhce.local (/etc/httpd/conf.d/serv1-vhost.conf:1)
alias serv1
port 443 namevhost serv1.rhce.local (/etc/httpd/conf.d/serv1-vhost.conf:1)
alias serv1
port 443 namevhost serv1.rhce.local (/etc/httpd/conf.d/ssl.conf:56)
port 443 namevhost serv1.rhce.local (/etc/httpd/conf.d/ssl.conf:56)
same issue . I have to manually type the https url everytime
Try mod_rewrite and see if that resolves the problem:
This time it started working without just “Redirect permanent / https:// serv1.rhce.local/”
Well done.
Hi Tomas,
One question can we create multiple Virtual hosts file for each web server or just one Vhost file . e.g i was trying to put two host one running on port 80 other for port 443 . Below is the content of that vhost.conf file
ServerName secsite.rhce.local
serveralias secsite
SSLEngine on
SSLProtocol all -SSLv2
SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5
SSLCertificateFile /etc/pki/tls/certs/secsite.rhce.local.crt
SSLCertificateKeyFile /etc/pki/tls/private/secsite.rhce.local.key
ServerAdmin [email protected]
DocumentRoot “/var/www/html/secsite”
directoryindex index.html
#require all granted
require host rhce.local
loglevel info
ErrorLog “/var/log/httpd/secsite-error_log”
CustomLog “/var/log/httpd/secite-access_log” common
ServerAdmin [email protected]
DocumentRoot “/var/www/html/”
#require all granted
require host rhce.local
ServerName site1.rhce.local
serveralias site1
loglevel info
ErrorLog “/var/log/httpd/site1-error_log”
CustomLog “/var/log/httpd/site1-access_log” common
When i access HTTP using “elinks http:// 10.8.8.50” it shows me “This is Site One” which is correct but when i try to access “curl –insecure “https:// 10.8.8.50” it still shows “This is Site One” although index file has “This is secured site”
httpd -t -D DUMP_VHOSTS
VirtualHost configuration:
*:443 is a NameVirtualHost
default server secsite.rhce.local (/etc/httpd/conf.d/ssl.conf:56)
port 443 namevhost secsite.rhce.local (/etc/httpd/conf.d/ssl.conf:56)
port 443 namevhost secsite.rhce.local (/etc/httpd/conf.d/ssl.conf:56)
port 443 namevhost secsite.rhce.local (/etc/httpd/conf.d/website.conf:2)
alias secsite
port 443 namevhost secsite.rhce.local (/etc/httpd/conf.d/website.conf:2)
alias secsite
*:80 is a NameVirtualHost
default server site1.rhce.local (/etc/httpd/conf.d/website.conf:23)
port 80 namevhost site1.rhce.local (/etc/httpd/conf.d/website.conf:23)
alias site1
port 80 namevhost site1.rhce.local (/etc/httpd/conf.d/website.conf:23)
alias site1
You can have multiple files, that’s how you do webhosting in practice.
When testing websites with SSL/TLS, use SNI and not the IP address.
I read apache documentation and came to know Apache reads the files alphabetically , I used one website.conf file and placed all vhosts in it. and configuration was not working as i want. So i renamed the file ot 00-website.conf and reload the service and everything started working as it should.
That’s correct. You can get a list of all virtualhosts in their order by running the following command:
Tomas, is there a documentation for the Auth User? what if we forget about the syntax?
Apache documentation is provided by
httpd-manual
package.Hi Tomas,
I am trying to restrict portion of my website what i am trying to is to allow only localhost to access /second through Requireall container but some how localhost is also getting forbidden message
Directory “/var/www/html/second”>
AllowOverride None
Require all denied
Require local
but when i do following it works i am confused when to use container and when not
Directory “/var/www/html/second”>
AllowOverride None
Require all denied
Require local
sorry all the config was not properly copied
Working:
AllowOverride None
Require all denied
Require local
Not working:
AllowOverride None
Require all denied
Require local
Hi,
for selinux man pages – there is a shortcut (compared to using sepolicy manpage) ,which I learnt recently:
yum install selinux-policy-doc
In RHEL 7 that package is availabe from the rhel-7-server-optional-rpms repository.