Tips on Apache Web Server...

strace all apache child processes

# ps h --ppid `cat /var/run/httpd.pid` -o pid | awk '{print "-v -ff -tt -T -s 1024 -o /tmp/strace.out -p " $1}' | xargs strace

This will attach strace to each of the apache child processes.

-v verbose
-ff with -o will log the output to "/tmp/strace.out.{pid}" and follow forks.
-tt prints the timestamp of each call.
-T prints the duration of each call.
-s specifies the maximum size of the output string to more than the default 32.

Related links:

group writable web folders with setgid and ACL

Often times, there is need for web-accessible folders to be set up so all web-developers have write access.

Along with setgid option, ACL can be used so anyone in the group "web-developers"
would have write privileges to anything under web-accessible document root.

So unless the acl privileges is revoked specifically, it would just continue to work.

To enable ACL, add "acl" option to /etc/fstab file for the corresponding partition and remount.

Edit /etc/fstab:

/dev/mapper/home /home           ext4    defaults,acl        0       2


# mount -o remount /home

Here is the commands to be used for the setup:

# groupadd developers
# chgrp -R developers /path/to/docroot
# find /path/to/docroot -type d -exec chmod g+s {} \;
# find /path/to/docroot -type d -exec setfacl -m g:developers:rwx,d:g:developers:rwx {} \;
# find /path/to/docroot -type f -exec setfacl -m g:developers:rw {} \;

Now anyone needing write access can be put in the "developers" group.

# usermod -G developers {username}

If you need the webserver to have write access to certain folders, then chown the location to be owned by the webserver, instead of giving write permissions to all.

# chown apache /path/to/docroot/apache

Apache LDAP Authentication and Require ldap-group

I was able to get htauth againt ldap and restricting against groups using:

<Location /protected>
    # Ldap auth access
    AuthType Basic
    AuthName "Restricted"
    AuthBasicProvider ldap
    AuthzLDAPAuthoritative on
    AuthLDAPURL "ldap://ldap.linuxweblog.com/ou=People,dc=linuxweblog,dc=com"
    Require ldap-group cn=web,ou=group,dc=domain,dc=tld
    AuthLDAPGroupAttributeIsDN off
    AuthLDAPGroupAttribute memberUid

Here is what the ldap search entry looks like:

# ldapsearch -x 'cn=web'
# extended LDIF
# LDAPv3
# base <> with scope subtree
# filter: cn=web
# requesting: ALL

# web, group, linuxweblog.com
dn: cn=web,ou=group,dc=linuxweblog,dc=com
objectClass: posixGroup
gidNumber: 10002
cn: web
description: access to web protected folders
memberUid: user1

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1

It is essential to enter "AuthLDAPGroupAttributeIsDN off" and "AuthLDAPGroupAttribute memberUid" for it to get to the member attribute.

Reference: mod_authnz_ldap

Check bots success POSTs in apache access log

Here is a one liner to check for IPs of bots that are misusing your site.

$ awk '$6 ~ /POST/ && $9 ~ /200/ {print $1 " " $7}' /var/log/httpd/access_log | sort | uniq -c | sort -n | tail

This will give you the top 10 IPs and URIs with a hit count.

Consider blocking those rogue IPs with a high hit count via iptables.

Django HTTPS Redirects

This works for both HTTP and HTTPS where any front end web server such as nginx which handles the actual request sets a header when request comes via HTTPS. In Apache configuration you then use mod_setenvif to set the HTTPS variable, which Django then picks up to use for redirection.

With front end nginx server which handles SSL, set header "X-Forwarded-Proto=https" via:

  proxy_set_header X-Forwarded-Proto https;

On Apache, add directive:

  SetEnvIf X-Forwarded-Proto https HTTPS=1

The HTTPS variable is picked up as being special by mod_wsgi and it will fix the wsgi.url_scheme in WSGI environment which Django then uses for redirection.

This way you don't need to customize Django stack.

disable logging of images in access log


SetEnvIfNoCase Request_URI "\.(gif|jpe?g|png|htc|css|js|ico)$" skiplog
CustomLog "/var/log/httpd/access.log" combined env=!skiplog


$HTTP["url"] =~ "\.(gif|jpe?g|png|htc|css|js|ico)$" {
  accesslog.filename = "/dev/null"

Munin stats for apache and lighttpd

Get status of apache (80) and lighttpd (81) on different ports:

This is done at the nodes.

  1. Enable apache server-status in httpd.conf :
    <Location /server-status> 
        SetHandler server-status
        Order deny,allow
        Deny from all
        Allow from
  2. Enable lighttpd server-status in lighttpd.conf :
    $HTTP["remoteip"] == "" {
    status.status-url          = "/server-status"
  3. Create /etc/munin/plugin-conf.d/apache:
    env ports="80 81" 

    * Test with:

    ports="80 83" /etc/munin/plugins/apache_processes

lighttpd idle process will be a straight line as total of busy and idle process is always the same when drawn as STACK, . To change this to LINE1:

At the host, edit "/etc/munin/munin.conf" and add the below line to the corresponding host:

apache_processes.idle81.draw LINE1

unable to include potential exec

Recent upgrade to Apache-2.2.3 secured down on executables not able to be included within a SSI include call and was getting "unable to include potential exec" in the apache error log file.

Apparently .shtml files were being used as includes via SSI. Changing the included files to .html resolved the issue.

Below was the command issued from the document root to quickly rename all the embedded leftmenu.shtml to leftmenu.html:

cp -a leftmenu.shtml leftmenu.html
find -L -name "*.shtml" -type f -printf "\"%p\"\n" | xargs perl -pi -e 's/leftmenu\.shtml/leftmenu\.html/g'

Forcing apache to listen to ipv4

Recently, I've noticed that in ubuntu (6.06) dapper server with apache-2.0.55, apache by default listens to IPv6, thus was causing slow response times. The response times was much improved by having apache listen to IPv4 instead.

Edit /etc/apache2/ports.conf and specify an IPv4 address on all Listen directives:


apache internal dummy connection

I've noticed these in httpd access log starting with Apache2.2:

::1 - - [09/May/2008:14:53:29 -0400] "GET / HTTP/1.0" 200 5043 "-" "Apache (internal dummy connection)"

The apache server occasionally hits localhost to signal its children. See the apache wiki for more info.

"When Apache HTTP Server manages its child processes, it needs a way to wake up processes that are listening for new connections. To do this, it sends a simple HTTP request back to itself...
These requests are perfectly normal and you do not, in general, need to worry about them. They can simply be ignored."

Unfortunately, the homepage I host is a dynamic one and this becomes very costly during busy times. I see a large number of those internal dummy connection requests during an apache graceful restart (SIGUSR1) and at the same time the cpu load on the Apache2.2 server maxes out at nearly 100%. I do not see this cpu load during a graceful restart on apache 2.0 httpd servers.

With the below mod_rewrite rule in place I was able to reduce the load by pointing http request coming from HTTP_USER_AGENT, "internal dummy request" to an empty static html page.

RewriteEngine on
RewriteCond %{HTTP_USER_AGENT} ^.*internal\ dummy\ connection.*$ [NC]
RewriteRule ^/$ /blank.html [L]

Also, removed logging of such requests via:

SetEnvIf Remote_Addr "::1" dontlog
CustomLog /var/log/httpd/access.log combined env=!dontlog

Syndicate content