Archive for the ‘Primary’ category

Adding Google Sitemap CPanel Firewall Exception

August 5th, 2014

If you’ve had any experience with installing Google Sitemap Generator on a Cpanel/WHM based server then you may have run into an issue where port 8181 is not accessible. Even if you modify iptables rules, it seems to go back to blocked after a while.

If your WHM setup is utilizing CSF, then you may need to add the exception via WHM.

Locate the CSF configuration section, and then click on Firewall Configuration.

CSF 1st Step

Then find the IP4 (and IPv6 settings if needed) settings, and add 8181 to the list of ports allowed in for TCP Inbound.

CSF Step 2

Once done, you can save and restart CSF. From then on, you should be able to access your Google Sitemap control panel on port 8181.

If you still cannot, due to not utilizing an SSL certificate, and still wish to connect without installing a certificate, you can do so with the following command as root:

/usr/local/google-sitemap-generator/bin/sitemap-daemon remote_admin enable

Selective Elevation of PHP in Nginx+WordPress

November 20th, 2012

For the purpose of this write up, I am demonstrating the configuration as they are on a FreeBSD 9.0 server. The ‘www’ user and group are often referred to as ‘www-data’ on most linux hosts. For saftey Nginx and PHP-FPM are run as www:www, with ownership of the web files belonging to an unprivileged user and permissions set accordingly.

On most of my servers my web files are owned by an unprivileged user that belongs to the www group, and I tend to run nginx and php as www:www. Running PHP as said user:www can be quite risky since most files have read/write/execute permission set on the owner bit. (in octal permissions it’s UGO – User/Owner-Group-Other, such as 750 = owner(read/write/excute) + group (read/execute) + other (none))

In this write up I am simply going to show you the configuration of second a second smaller PHP-FPM pool to act as an ‘elevated’ process running as the folder’s owner, thus allowing far more control over the files and folders such as upgrading wordpress or it’s plugins, but not allow any other files not matching the pattern to do the same.

First thing we need to do is add a second pool to the php-fpm.conf, on FreeBSD installed from ports it will be located at /usr/local/etc/php-fpm.conf, on other systems such as debian or ubuntu, it may be located as /etc/php5/fpm/pool.d/default or similar (look for the config with the [www] pool in it).

This configuration has been stripped down quite a bit with some commented options shown for example purposes.

pid = run/
user = www
group = www
listen = /tmp/php.sock
listen.owner = www = www
listen.mode = 0666
;listen is not required with sockets
;listen.allowed_clients =
pm = static 
pm.max_children = 4
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
pm.max_requests = 1024 
;chroot = 
;chdir = /var/www
;catch_workers_output = yes
;security.limit_extensions = .php .php3 .php4 .php5
;env[PATH] = /usr/local/bin:/usr/bin:/bin
;env[TMP] = /tmp
;env[TMPDIR] = /tmp
;env[TEMP] = /tmp
;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f
;php_flag[display_errors] = off
;php_admin_value[error_log] = /var/log/fpm-php.www.log
;php_admin_flag[log_errors] = on
;php_admin_value[memory_limit] = 32M
user = kbeezie
group = www
listen = /tmp/php-elevated.sock
listen.owner = www = www
listen.mode = 0666
;listen.allowed_clients =
pm = static 
pm.max_children = 2
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
pm.max_requests = 1024

In the above I have two pools set up, the first one being a typical 4-process (with static, min/max_*servers values are ignored) running as www:www, followed by a second pool named elevated running with 2 processes with the user/group of kbeezie:www (the web files are owned by kbeezie:www).

You’ll notice from some of the commented values above, that you can tweak specific configurations for each pools as needed, such as needing more memory or being locked into a specific folder.

Now in a very simple server block on Nginx for wordpress we need to add a couple location blocks using a regular expression location (this way it overrides the usual php location block when placed ahead of it).

	server { 
		listen 80;
		root /home/kbeezie/www/;
		location / {
			try_files $uri $uri/ /index.php;
		# matches for update.php or update-core.php in /wp-admin/
		location ~ ^/wp-admin/(?:update|update-core)\.php$ {
			include php-elevated.conf;
		include php.conf;
		include drop.conf;

I tend to use config files for my PHP inclusion. For example here are both the php.conf and php-elevated.conf located in the same folder as nginx.conf:

location ~ \.php$ {
        try_files $uri =404;
        fastcgi_param  QUERY_STRING       $query_string;
        fastcgi_param  REQUEST_METHOD     $request_method;
        fastcgi_param  CONTENT_TYPE       $content_type;
        fastcgi_param  CONTENT_LENGTH     $content_length;
        fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
        fastcgi_param  SCRIPT_FILENAME    $request_filename;
        fastcgi_param  REQUEST_URI        $request_uri;
        fastcgi_param  DOCUMENT_URI       $document_uri;
        fastcgi_param  DOCUMENT_ROOT      $document_root;
        fastcgi_param  SERVER_PROTOCOL    $server_protocol;
        fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
        fastcgi_param  SERVER_SOFTWARE    nginx;
        fastcgi_param  REMOTE_ADDR        $remote_addr;
        fastcgi_param  REMOTE_PORT        $remote_port;
        fastcgi_param  SERVER_ADDR        $server_addr;
        fastcgi_param  SERVER_PORT        $server_port;
        fastcgi_param  SERVER_NAME        $server_name;
	fastcgi_pass unix:/tmp/php.sock;
location ~ \.php$ {
        try_files $uri =404;
        fastcgi_param  QUERY_STRING       $query_string;
        fastcgi_param  REQUEST_METHOD     $request_method;
        fastcgi_param  CONTENT_TYPE       $content_type;
        fastcgi_param  CONTENT_LENGTH     $content_length;
        fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
        fastcgi_param  SCRIPT_FILENAME    $request_filename;
        fastcgi_param  REQUEST_URI        $request_uri;
        fastcgi_param  DOCUMENT_URI       $document_uri;
        fastcgi_param  DOCUMENT_ROOT      $document_root;
        fastcgi_param  SERVER_PROTOCOL    $server_protocol;
        fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
        fastcgi_param  SERVER_SOFTWARE    nginx;
        fastcgi_param  REMOTE_ADDR        $remote_addr;
        fastcgi_param  REMOTE_PORT        $remote_port;
        fastcgi_param  SERVER_ADDR        $server_addr;
        fastcgi_param  SERVER_PORT        $server_port;
        fastcgi_param  SERVER_NAME        $server_name;
	fastcgi_pass unix:/tmp/php-elevated.sock;

The only difference you’ll notice is that php-elevated.conf connects to the elevated socket rather than the usual one.

Now once we’ve restarted Nginx and PHP-FPM with the new configuration, when you attempt to update wordpress or one of it’s plugins, the script will have an elevated permission due to running as the files/folder’s owner, while any other scripts (as called by the browser) will run with unprivileged www:www status.

The drop.conf is simply a number of locations that should normally be dropped from public requests, I paste it here for reference:

	# the first line can normally be omitted for wordpress, as robots.txt is normally dynamic
	location = /robots.txt  { access_log off; log_not_found off; }
	location = /favicon.ico { access_log off; log_not_found off; }	
	location ~ /\.          { access_log off; log_not_found off; deny all; }
	location ~ ~$           { access_log off; log_not_found off; deny all; }


Bear in mind the above configuration are for example purposes, there are quite a few smaller things to keep in mind such as hardening your configuration for more security concerns or optimizing it for performance. For some examples of typical Nginx configurations see : Nginx Configuration Examples

FreeBSD Jail with Single IP

November 11th, 2012

This guide assumes you already have a jail installed, I personally use ezjail-admin. Here are three guides regarding the installation of ezjail-admin., [creator of ezjail-admin],

The Scenario

You have a FreeBSD VPS with a single IP and you wish to create a FreeBSD jail for additional security and/or isolation. For this write up I’ll illustrate how you can use a single VPS with a jail create on an internal IP with both NAT access and port-forwarding to the jail for specific ports (web, ssh, etc).

Creating the local interface

In your rc.conf we’ll clone the loopback interface to lo1 so that we can use the 192.168.*, 10.*, or 172.16.* for our private jail network.


The above will create a lo1 loopback device with thru created on that interface. From here we’ll create a jail with Then we’ll configure PF to allow outbound traffic (NAT) from those local addresses as well as pass web (80) and SSH port to a specific jail IP.

Make sure to change the external interface if it is not em0, but rather something like re0.

IP_PUB="Your Public IP Address Here"
scrub in all
nat pass on em0 from $NET_JAIL to any -> $IP_PUB
rdr pass on em0 proto tcp from any to $IP_PUB port $PORT_WWW -> $IP_JAIL

Any Jail tied to the 192.168.* IP range will have outbound connectivity (needed for installing ports, updates or other packages), but for a specific jail such as your webserver we’ll pass inbound traffic on port 80/443 for the webserver, and 2020 for SSH. You will need to make sure to configure /etc/ssh/sshd_config to listen on, Port 2020 or a port of your choosing.

This way you can use the same IP to connect both to the main VPS on one SSH port, but connect to the jail directly on another port.

Once the above are saved in /etc/pf.conf, we need to test it and then start up pf (or restart).

pfctl -nf /etc/pf.conf
service pf start

We can verify the rules with the following command:

# pfctl -sn
nat pass on em0 inet from to any -> YOUR_PUBLIC_IP
rdr pass on em0 inet proto tcp from any to YOUR_PUBLIC_IP port = http ->
rdr pass on em0 inet proto tcp from any to YOUR_PUBLIC_IP port = https ->
rdr pass on em0 inet proto tcp from any to YOUR_PUBLIC_IP port = 2264 ->

If you need to perform specific tasks from inside the jail such as ping, traceroute, sockstat and so forth, add the following to the main node’s /etc/sysctl.conf


There you have it, once those rules are set up, all the private jails will have outbound traffic allowing you to install ports and download files from other servers, but will also allow specific ports to be forwarded to specific jails (such as forwarding 3306 to a separate database jail from outside of the VPS).

You can for all intents and purposes, forgo the port forwarding above in the pf.conf section, and simply create for example an IPv6-only Jail that still has the ability to to install packages and ports via the outbound NAT traffic thru the single IPv4 address, as not all ports provide an IPv6 compatible download link.

A space saving tip

If you would rather not have to update the ezjail port tree every time there’s an update, you can instead clone a read-only copy of the ports tree from your master node to each of your jails.

First we must shutdown the jail, and remove the symlinked ports folder from the jail, then create a blank folder to be mounted upon.

# cd /usr/jails/
# rm -Rf ./ports
# mkdir ports

Then we’ll edit the jails’ fstab to include the master port tree located at /etc/fstab.myjail_com

/usr/jails/basejail /usr/jails/ nullfs ro 0 0
/usr/ports /usr/jails/ nullfs ro 0 0

Now to make sure that the jail will be able to download distfiles and create a working directory, we need to start up the jail, log into it, and then edit the /etc/make.conf

WRKDIRPREFIX=		/var/ports
DISTDIR=		/var/ports/distfiles
PACKAGES=		/var/ports/packages
INDEXDIR=		/var/ports

Make sure the /var/ports directory exists if it does not already. Once you have those placed in the /etc/make.conf you’ll be able to:

1) Update your ports tree from a single location (the master node)
2) Run ports updates and installation from within the jail without having to restart the jail, or to re-run ezjail-admin update -p.

FreeBSD Update Annoyances [pkg-config-0.25_1]

August 11th, 2012

So today I got around to running portmaster again to update to the latest packages.

===>  pkgconf-0.8.5 conflicts with installed package(s): 
      They install files into the same place.
      Please remove them first with pkg_delete(1).
*** Error code 1
Stop in /usr/ports/devel/pkgconf.

You may have seen the above before with other updates in the past. Unfortunately not all the package maintainers have set up the packages to be smart enough to make the transition from one old package to a new one so smooth.

You might have even tried to do this:

# pkg_delete pkg-config-0.25_1
pkg_delete: package 'pkg-config-0.25_1' is required by these other packages
and may not be deinstalled:

To no avail. (or you didn’t know the package name, pkg_info | grep pkg would help)

To fix you simply have to perform the following:

pkg_delete -f pkg-config-0.25_1
cd /usr/ports/devel/pkgconf
make install clean

If you are not logged in as root you may need to `su` into root privileges or use sudo.

From there you can run portmaster again to proceed with the upgrades/updates as needed. If you run accross this problem again with another package just repeat the same kind of steps, forcefully removing the old one and reinstalling the new one from ports yourself.

Debian/Ubuntu Nginx init Script (opt)

February 28th, 2011

Normally if you install Nginx from a repository this init script would already be included. However if you installed from source, or did not use the standard paths, you may need this.

If you find that stop/restart and such do not work, your pid file location may be incorrect. You can either set it in the nginx.conf or you can change the init script here to point to the correct pid location. If you’re ever in a pinch stopping and restarting an nginx process that’s already running you can use the following:

nginx -s quit (or reload)

Quit will terminate the existing processes, reload will keep nginx running but will simply reload the configuration. But if your init script is setup properly you should be able to use that instead.

The below init script was for a configuration where /opt was the provided configuration prefix.

#! /bin/sh
# Provides:          nginx
# Required-Start:    $all
# Required-Stop:     $all
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: starts the nginx web server
# Description:       starts nginx using start-stop-daemon
test -x $DAEMON || exit 0
# Include nginx defaults if available
if [ -f /etc/default/nginx ] ; then
        . /etc/default/nginx
set -e
case "$1" in
        echo -n "Starting $DESC: "
        start-stop-daemon --start --quiet --pidfile /var/run/ \
                --exec $DAEMON -- $DAEMON_OPTS
        echo "$NAME."
        echo -n "Stopping $DESC: "
        start-stop-daemon --stop --quiet --pidfile /var/run/ \
                --exec $DAEMON
        echo "$NAME."
        echo -n "Restarting $DESC: "
        start-stop-daemon --stop --quiet --pidfile \
                /var/run/ --exec $DAEMON
        sleep 1
        start-stop-daemon --start --quiet --pidfile \
                /var/run/ --exec $DAEMON -- $DAEMON_OPTS
        echo "$NAME."
      echo -n "Reloading $DESC configuration: "
      start-stop-daemon --stop --signal HUP --quiet --pidfile /var/run/ \
          --exec $DAEMON
      echo "$NAME."
        echo "Usage: $N {start|stop|restart|force-reload}" >&2
        exit 1
exit 0

Apache to Nginx Migration Tips

April 11th, 2010

For a simple beginning example configuration to start with please view my example configuration

Nginx currently holds shy of 6.5% of the known webserver market, which is just roughly shy of 13 million servers. This little lightweight webserver created by a sole Russian developer has been gaining a great deal of popularity over the last few years and is used by sites such as WordPress, Texts from Last Night and Hulu.

This guide will show you common examples in Nginx to make migration from Apache a bit easier.

HTTP Basic Authentication or htpasswd support

If you have been playing with nginx for a the first time you may have noticed that there is no .htaccess support. However Nginx can still utilize HTTP Basic Authenication with existing htpasswd files using the HTTP Auth Basic Module. The module is compiled by default.

If you still have Apache installed (but perhaps turned off or on a different port) you can still use htpasswd to generate a password file. But in the event that you don’t have or don’t want to install Apache you can use Perl or Ruby to generate at least the encrypted passwords. The .htpasswd files should be in the following format.


To generate a password with Ruby in irb:


Likewise to generate with perl from the terminal:

perl -le 'print crypt("your-password", "salt-hash")'

The two commands above will utilize a 56-bit DES encryption which can be used in the htpasswd file.

Once you have your password file saved, store it outside of the web-accessible location like you would have when using Apache (likewise you can ensure that web access to hidden files are denied, more on that later).

Lets say you have a subfolder on your server called ‘admin’ and you wish to protect it. Here is an example configuration:

location  /admin  {
  auth_basic            "Admin Access";
  auth_basic_user_file  conf/;

If the above did not work, check your error logs as sometimes it will notify you if the path to the password file could not be found.

Ignoring robots.txt, favicon.ico and hidden files

Sometimes you may wish to omit commonly accessed files from being recorded in the access log as well as block access to hidden files (filenames beginning with a period such as .htpasswd and .htaccess). Even though nginx doesn’t support htaccess, you may still wish to secure files left behind from the migration. You can easily do this by adding a couple location blocks to your domain’s server block.

location = /favicon.ico { access_log off; log_not_found off; }	
location = /robots.txt { access_log off; log_not_found off; }
location ~ /\. { deny  all; access_log off; log_not_found off; }

The above will not record access to the favicon.ico or robots.txt in the root of your site, as well as ignore the file-not-found error if you do not have either file present. Also the last line will deny access to any file beginning with a period anywhere within the root path. You can actually save the above into a file such as /conf/drop.conf, and include it at the bottom of each of your server blocks like so.

include drop.conf;

Extremely Easy WordPress Migration

Most people now days take advantage of WordPress’ permalink feature which normally requires mod_rewrite enabled in the .htaccess file. However as of Nginx 0.7.26 and above this can be taken care of very easily with a single directive.

location / { 
   try_files $uri $uri/ index.php;

The above will attempt to try the requested URI first as a file, then as a folder, and if both of those come back negative it will fall back to index.php. WordPress can simply parse the request URI sent by the webserver so there is no need to manually add arguments onto index.php. If you instead need to do something further you can change the fallback from index.php to @fallback like so:

location / {
   try_files $uri $uri/ @wordpress;
location @wordpress {
     # Additional rewrite rules or such you need here.

For Nginx versions older than 0.7.26 you can use the older method shown below (however its strongly advised to have 0.7.26 or newer).

location / { 
        if (-f $request_filename) {
            expires 30d;
        #Ultimately 'if' should only be used in the context of rewrite/return :
         if (!-e $request_filename) {
            rewrite ^(.+)$ /index.php?q=$1 last;

The two if blocks replace the common RewriteCond used by wordpress to test if the requested filename is an existing file or folder.

On the next page: Utilizing WP Super Cache, rewrite examples and more.

How to Steal an Android Market App

April 10th, 2010

One of the biggest fear plaguing any freelance application developer is piracy. All their hours and hours of work to bring you the next useful little app that they hope you’ll enjoy. So why shouldn’t they be compensated for their hard work. Sometimes however this fear can hurt a new platform more than it can help. That is why in this article I will show you how easy it is to steal even a protected android market app.

Step One – Rooting your phone

Rooting your android device is similar to jailbreaking your iPod Touch or iPhone. Basically gives you the ability to perform tasks normally reserved only for the ‘root’ user of the device. The method of rooting vary greatly depending on the device. I personally own a T-Mobile MyTouch 3G Limited Edition (fender) which is identical to the new T-Mobile MyTouch 3G v1.2 with the headphone jack on top, the only difference is design, and the size of the miniSDHC card that comes with it. I rooted my phone by following the instructions found in this XDA Developer forum thread. If you have one of the older MyTouches you can easily find how-to guides on the same forum corresponding to the Magic 32A and 32B.

Warning: Like most things in gadget life, performing an action such as above not only has the possibility of voiding your warranty, but can also brick your device, that is to say it’ll be no better than a brick that won’t even turn on. So proceed at caution. It is very important to not only carefully read any instructions (such as provided by the link above) but also to verify that your device actually matches the instruction’s requirements. Most people who do this tend to have no problems, but those who fail to actually follow instructions have a very good chance at flashing the wrong recovery or radio image.

Once you are rooted, you can download the Android Software Developer’s Kit, or find the ConnectBot App in the market place. Sometimes protected applications (like the free Paypal app) may not show up after rooting, usually installing the Market Enabler fixes this.

Step Two – Purchase

For this demonstration to work we need to make a purchase. For this article I’ve decided to purchase Retro Defense by Larva Labs. I’ve always enjoyed the games from Larva Labs.

Ok, so we have purchased the game, now what?

Step Three – Back it up

With your rooted phone you can now either open up ConnectBot, or in your terminal run “adb shell” (from the SDK).

Once you are in the terminal as root (you may have to type su if you see $ instead of # to elevate yourself as the root user), you can then follow the following commands, to make a directory and copy the game to that directory.

# cd /sdcard
# mkdir /backapk
# cd /data/app
# ls (you'll see a screen showing you the file content, find the file you want)
# cp com.larvalabs.retrodefense.apk /sdcard/backapk

You may be prompted by SUuser application to allow Connectbot root access (if you used adb shell instead you won’t see this prompt)

At this point all you have done was make a backup of your app/game onto the SD card. Protected application usually exist in /data/app-private as an apk (leaving a small .zip in the /app location)

Migrating Cpanel to DirectAdmin

March 28th, 2010

One of the most frustrating thing someone can do involving their websites is moving them from one hosting provider to another. It’s increasingly more difficult if your hosting was based on a control panel such as Cpanel, and try to migrate to a different kind of control panel or none at all.

Step One – Package your account

If you have root access to the server via SSH (such as if you have a VPS) you can do this quite simply by performing the following command.

/scripts/pkgacct username

The above command will place the cpmove-username.tar.gz file into the /home directory where you can download it via FTP/SCP.

For those who only have user-level cpanel access, you will need to log into your cpanel account. From there under the file section you will see a Backup Wizard icon.

Cpanel Files Section

When you click on that, you’ll be prompted to 1) Backup. 2) Full Backup 3) Provide email.

When the backup packaging is complete you will receive an email notification, and the generated file will be placed in your home directory. (usually the default root of your FTP client when you log in). You will want to download this .tar.gz file onto your desktop.

Step Two – Preparing to upload

For those of you who are windows users, you will need to download something such as 7-Zip in order to unpack the tar.gz file. Create a folder to place the file in and unpack it. The resulting files will be all the data from your Cpanel account (including your mail in MailDir format). Find the homedir.tar and pull it out of the folder and extract it.

Once extracted you’ll see various folders that was in your home directory. In /tmp you may even find some of your statistics such as webalizer which can be opened right from your desktop. The files you want to concentrare are in /public_html.

If you use any add-on domains, move them from the public_html folder. Once you’ve done that you can then compress the public_html folder content as a .zip file. Do the same for each one of the add-on domains. Don’t delete the uncompressed copies just yet.

Releasing IP Addresses in WHM/Cpanel

December 28th, 2009

If you are hosted with a WHM/Cpanel based server or VPS, you may have had some difficulties trying to get an alternate webserver such as Nginx or Lighttpd installed especially if you wanted to use the default port 80. This article shows you how you can release extra IP addresses to be used by those services without conflicting with Apache.

There are two areas wee need to address, Apache, and then WHM/Cpanel.


By default Apache listens to every interface coming into the machine by listening to Normally you could edit the httpd.conf file directly in order to change the listen line, however that may cause problems with Cpanel’s automation.

To acheive this more safely, log into Webhost Manager (typically and find Service Configuration followed by Apache Configuration. Then click on Reserved IPs Editor.

Here you will need to check the boxes of the IP addresses you do NOT wish for Apache to use. Once you save your selections, a new configuration file will be configured to listen on all the other IPs that were not checked. This will allow other services such as alternate webbrowsers to listen on those IP addresses without conflicting with Apache.

Webhost Manager

We freed some IP addresses from Apache, but now we have to make sure that WHM/Cpanel doesn’t attempt to use those same IP addresses for other services.

Navigate to IP Functions, followed by Show/Edit Reserved IPs. Here you should check the same IPs that were selected in the Apache Reserve list above. Once this is done WHM/Cpanel will avoid using those IP address when setting up new accounts and services.

Configuring Nginx
Assuming Nginx is already configured you will need to make a minor adjustment to the server blocks in order to start it up.

server {
	listen an-ip-address:80;

Normally you would just have the port number identified, but if you tried to start it as just that, it would conflict with Apache if already running (otherwise vice-versa). So we need to make sure to bind each server block to an available IP address.

While I personally prefer to run Nginx standalone on it’s own server such as the one is running off of. Some may wish to use the benefits of Nginx for certain projects while still having the ease of use of Cpanel for other sites.

On a side note, if PHP is setup as a Fast-CGI executable in WHM you can share the same PHP instance with Nginx or Lighttpd, otherwise you’ll need to make sure to either compile a separate instance of PHP, or launch the fast-cgi daemon manually for the existing installation (spawn-fcgi, php-fpm, etc).

Handling wildcard subdomains with PHP

November 5th, 2009

Subdomains can be a very handy way to make your urls more friendly looking. They can also be incredibly useful for membership driven websites to allow members to have their own custom subdomain. But how do make manage dynamic subdomains with PHP?

There is two parts to making dynamic subdomains work in this case. The first is updating your DNS and webserver to expect wildcard requests. On the DNS side its a simple matter of adding * as an ‘A’ record, or cname pointing to the primary domain or IP. In most cases if you are using shared hosting, you’ll need to contact your hosting provider to enable wildcard DNS on your account. Otherwise if you are on a dedicated server or virtual private server, this can be most likely handled by yourself, such as editing the DNS zone in WHM.

Once you have enabled wildcard DNS, you’ll need to configure your webserver to expect a * request. Otherwise it will ignore all requests other than the base domain and pre-defined subdomains.

In Nginx simply modify the server_name directive:

server_name *;

In Apache you would add a ServerAlias directive to the appropriate virtual host entry.

ServerAlias *

On most Cpanel driven servers the http.conf file for Apache can be found in /usr/local/apache/conf.

Once you have configured both the name server and web server for wildcard requests you can now use php to not only detect the provide subdomain, but also generate them. The code below will obtain the subdomain being visited.

$sub = str_replace("", "", $_SERVER["HTTP_HOST"]);

The above will simply take the hostname stored in the HTTP_HOST enviroment variable, and attempt to replace the base domain with nothing (if no subdomain was provided all that remains is the base domain).

Once the subdomain is determined, you can filter out requests either with an if/then block or in a switch/case statement. In the event of using memeber names as subdomains you can use a switch statement to make sure that the subdomain doesn’t match the homepage (www / or a reserved page name such as and assume anything else must be a member name. With that information you can pull the members information from a file or database.

Using PHP to handle the subdomain is certainly easier for most novice as opposed to modifying an htaccess to do rewrite rules passing the subdomain off as a query (which takes more resources than str_replace) or having to modify the webservers configuration file, especially if you do not have direct access to the webserver’s configuration file or do not have override permission.

If your current hosting provider does not support wildcard subdomain, and you are running a memeber based site, consider upgrading to a Virtual Private Server or use a shared hosting provider such as HostGator that allows you to turn on such capability via a support ticket.