OK:
Put either IPCop or pfSense on a box that is what actually touches the internet. If you are non-dedi then this will be more problematic. If your customer really wants to do this right, tell him that you will need to do this. It's a fundamental piece of strong security.
Port-forward only 80 and 443 as I've described ... but port forward them to something else like 82 and 445 - which is where you'll listen on the box. Deny everything else at the firewall.
Get yourself either an openVPN (road warrior) or fixed-IP VPN tunnel to the IPCop or pfSense box. This will allow you unrestricted access to everything behind the wall, while still keeping the public face of the wall secure. Use, at the very least, 3DES and a stupidly-non dictionary password. Do not give it out or use it anywhere else.
If you must keep credit cards, then you're still not 100% in PCI compliance. If you're really really paranoid and want to do it right, this is what I did: I put up another fire wall behind my firewall and my CC storage box behind that. The actual web renderers do not store any CC information at all. All CC information is kept in a MySQL database behind the second wall. This information is accessed via port 80 only through a simple get and set Apache/PHP script. There is no access to the box other than that for my web renderers. I have to ssh into the firewall, then ssh into the CC box to get there myself.
Information on the CC Storage box is all encrypted, but the box itself does not contain the capability to decrypt it - it is simply a storage device. All information is stored in a double-salted, double encrypted by the renderers. So if someone physically stole my CC box, they'd still have nothing. If they stole my renderers, they'd have the encryption routines, but not the data. Another step: the actual encryption key is stored in a root-only directory in a root-only file (chmod 400). There is a root-level cron job that opens that file and then uses a special web request to push the encryption key into RAM via apc_store. The point of this, is that if someone managed to gain some kind of access to the box, there's no instance of the key in any of my code: only an apc_fetch command to get it. In other words, you can't even write a script to ask for it, because the memory that holds the key is attached to Apache - you'd have to be another web page to get it (note in the next paragraph how I deny that possibility). Or hack my root password, but good luck with that. The pointers in the database are encrypted as well, so the actual row looks like 128 bytes (2 fields of 64) of hex and nothing else. The get method grabs a pointer from it's own database, encrypts it with salt based on the actual record it wants - it asks for and receives that data from the CC Storage device. Then using that encryped ID as salt, it can decrypt the actual CC information to throw the request at my merchants. This is all done in code and nothing is ever put on the disk.
Do not use telenet but rather SSH to access your boxes, even though they are behind your wall. Use an account OTHER than root just on the off chance that someone was sniffing you, they'd not get your access to the key files.
Precisely permission your MySQL boxes for ONLY local-machine access. This can include phpMyIDE, but have that presented on a port OTHER than 82 or whatever you're serving actual web pages on, so that it cannot be accessed at all from the outside world - only via your tunnel.
Shut off all unnecessary services. You no longer need much of anything running other than system stuff, Apache, FTP (which you might consider SFTP, but since you'd only be able to access it across an encrypted tunnel, this is probably overkill) MySQL and sshd.
Put something like: Include /usr/local/apache2/conf/sitefiles/*.inc
into your httpd.conf. Then lock down the httpd.conf so it is not editable, even by the root (just to keep things consistent). Then in the lower directory, make files for each site you want to have running on the box - make them small, tight and extremely obvious. The benefit here is that we want Apache to do EXACTLY what we have specified and NOTHING ELSE. You should be able to look at your Apache files and know EXACTLY what they're doing. Now, for an extra little bit of coolness, all of my sites mod_rewrite into a single, main.php file (unless they are suffixed as .css, .js, .pdf, .jpeg, .jpg, gif & .png). Then at the top of my main.php, if the inbound URL is not exactly what I expect, it is simply dumped. That's not all however: each URL is actually translated against a table of URLs for what I know that site will do. This is both for SEO and for security. If the URL is not in the table, I simply return the home page. I've had people tell me I could get a duplicate content penalty for this, but they are FOS. The point here is that I want immediate control of every URL that comes at me ... I NEVER want Apache to serve something (a page, at least) without I've had the chance to look it over first.
So:
http://www.mydomain.com/a-keyword-stuffed-dir/a-keyword-stuffed-url.htmlwill be translated to:
/simpleInclude.php?file=contentFile.php&menu=3.2.7&header=blue
Note that this gives me both extraordinary control over what I want the surfer/spider to see, with extraordinarily capable URLs that I'd *NEVER* want the outside world to see. And lastly, if I don't have the exactly inbound URL in the list, nothing happens. Period.
I think that ought to get your gears spinning. Good luck!
/p