Monday, October 25, 2010

nVidia EDID override and HDMI

I have a media center that is running Debian with XBMC on it, as I am a developer for XBMC I have just receved a new HDMI 1.4 capable AVR. I also have a large monitor that lies about its native resolution, reporting 1280x1024 instead of 1280x720. Normally I have been using a modified EDID file and the CustomEDID option in the nVidia driver to override the one the monitor supplies, which works really well IMHO, but there is a downside it took me 4 hours to track down, if you do this via a HDMI audio capable device, your HDMI audio will not work.

So, I had to find another option, took a few hours to figure out what worked, and I eventually came up with this. If you are allready using a custom/modified EDID keep reading, if not, figure that part out first over here.

To make use of your EDID information without using an EDID file is fairly simple, first you will need to install the package "read-edid", which comes with the "parse-edid" program. This program will generate an x conf "Display" section from the EDID information specifically for your monitor with all the modes and timing information.

Paste this section into your x conf file and add the following two options to the "Device" section to stop your video card from using the EDID frequency and timing information.


"UseEdidFreqs" "false"
Option "ExactModeTimingsDVI" "true"

And thats it, you get your custom resolutions, no more need for the CustomEDID option or file, and your HDMI audio will now work as it is not getting ignored by your video card.

For reference, here is my xorg.conf file, obviously this is specifically for my monitor (which is rather rare, so dont try it on yours).

# xorg.conf (X.Org X Window System server configuration file)
#
# This file was generated by dexconf, the Debian X Configuration tool, using
# values from the debconf database.
#
# Edit this file with caution, and see the xorg.conf manual page.
# (Type "man xorg.conf" at the shell prompt.)
#
# This file is automatically updated on xserver-xorg package upgrades *only*
# if it has not been modified since the last upgrade of the xserver-xorg
# package.
#
# If you have edited this file but would like it to be automatically updated
# again, run the following command:
#   sudo dpkg-reconfigure -phigh xserver-xorg

Section "InputDevice"
        Identifier      "Generic Keyboard"
        Driver          "kbd"
        Option          "XkbRules"      "xorg"
        Option          "XkbModel"      "pc104"
        Option          "XkbLayout"     "us"
EndSection

Section "InputDevice"
        Identifier      "Configured Mouse"
        Driver          "mouse"
EndSection

Section "Device"
        Identifier      "Configured Video Device"
        driver          "nvidia"

        Option          "UseEdidFreqs"          "false"
        Option          "ExactModeTimingsDVI"   "true"
EndSection

Section "Monitor"
        Identifier      "LG"
        VendorName      "GSM"
        ModelName       "LG"
        HorizSync       31-86
        VertRefresh     56-100

        Mode "1280x720"
                DotClock        108.000000
                HTimings        1280 1328 1440 1688
                VTimings        720 721 724 762
                Flags           "-HSync" "-VSync"
        EndMode
EndSection

Section "Screen"
        Identifier      "Default Screen"
        Monitor         "LG"
        SubSection "Display"
                Depth   24
                Modes   "1280x720"
        EndSubSection
EndSection

Monday, May 3, 2010

cPanel secondary master DNS without cPanel

At work I manage a cPanel server for over 200 clients that we needed to setup a secondary DNS server for. Since we wanted to use the machine for more then just backup DNS, and we wanted to run Debian, the cPanel DNS Only solution is no solution for us.

Here is how to slave cPanel to a Bind9 server without breaking cPanel or having cPanel undo the sync changes.

On the slave server I installed bind (apt-get install bind9) and made a directory "/Scripts" where I write two scripts, one is a class to wrap up cPanel API functions, the other is the actual DNS zone sync script. Both were written in PHP since it is my language of choice and is very easy to interface to the cPanel API with.

The class
=================================
<?PHP
        class cPanel {
                private $host;
                private $user;
                private $hash;

                private function __construct($host, $user, $hash) {
                        $this->host = $host;
                        $this->user = $user;
                        $this->hash = preg_replace("/[\t\r\n ]/", "", $hash);
                }

                private static $instance;
                public static function getInstance($host, $user, $hash) {
                        if (!(cPanel::$instance instanceof cPanel))
                                cPanel::$instance = new cPanel($host, $user, $hash);
                        return cPanel::$instance;
                }

                private function getJSON($request) {
                        $query = "https://{$this->host}:2087/json-api/" . $request;
                        $curl = curl_init();
                        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 1);
                        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 1);
                        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
                        $header = array("Authorization: WHM {$this->user}:{$this->hash}");
                        curl_setopt($curl,CURLOPT_HTTPHEADER,$header);
                        curl_setopt($curl, CURLOPT_URL, $query);
                        $result = curl_exec($curl);
                        curl_close($curl);
                        if ($result == false)
                                throw new Exception("curl_exec threw error \"" . curl_error($curl) . "\" for $query");
                        return json_decode($result);
                }

                public function listzones() {
                        $info = $this->getJSON('listzones');
                        $zones = array();
                        foreach($info->zone as $zone)
                                $zones[$zone->domain] = $zone->zonefile;
                        return $zones;
                }
        }
?>

=================================
 

And the script:
=================================
#!/usr/bin/php
<?PHP ob_start(); ?
>
PUT YOUR cPanel ACCESS HASH HERE 
<?PHP
        $hash   = ob_get_clean();
        $master = '123.123.123.123'; //YOUR MASTER SERVER IP
        require('/Scripts/cPanel.php');
        $cpanel = cPanel::getInstance('www.YOUR_HOST.com', 'root', $hash);
        $zones = $cpanel->listzones();
        if (count($zones) == 0)
                throw new Exception('Unable to retrieve the server\'s zone list');

        $fp = fopen('/etc/bind/cpanel.zones', 'w');
        foreach($zones as $zone => $file) {
                $zone =
                        "zone \"{$zone}\" {\n" .
                        "       type slave;\n" .
                        "       file \"{$file}\";\n" .
                        "       masters { {$master}; };\n" .
                        "};\n";

                fwrite($fp, $zone);
        }
        fclose($fp);
        shell_exec('/usr/sbin/rndc reload');
?>

================================= 

I then ran the script to create the zone file, and then created a symlink in /etc/cron.hourly to the sync script, so every hour the zones are fetched from the server, the configuration is re-built and bind is reloaded.

Then I modified /etc/bind/named.conf.options with the following two options, the first for security, the second to accept notify events from the master server to tell us to update our records.

options {
        ........ default options ........

    recursion no;
    allow-notify { 123.123.123.123; };
};

replace 123.123.123.123 with the master server's ip address. Then I just had to make a change to /etc/bind/name.conf.local to include the zone list built from the master server.

include "/etc/bind/cpanel.zones"

And thats it for the slave... now the master needs a minor modification to tell the client to update and to allow zone transfers to the slave. Add the following two lines to the options section in /etc/named.conf

allow-transfer { 123.123.123.123; };
also-notify { 123.123.123.123; };

Again, replacing the 123.123.123.123 with the IP address of the slave server.

Thursday, March 4, 2010

Reduce your server's bandwidth consumption with cPanel

For those that are interested, I manage a server running cPanel with over 200 accounts, on average we are using around 220GiB per month traffic server wide.

Turns out, that cPanel does not enable any form of HTTP compression for general requests, even though the WHM supports it, pretty dumb IMHO.

Anyway, here is how to turn it on... go to "Apache Configuration" and choose "Include Editor"
Select "All Versions" under "Pre Main Include"
Paste the following in:
AddType application/vnd.ms-word.document.macroEnabled.12 .docm
AddType application/vnd.openxmlformats-officedocument.wordprocessingml.document .docx
AddType application/vnd.ms-word.template.macroEnabled.12 .dotm
AddType application/vnd.openxmlformats-officedocument.wordprocessingml.template .dotx
AddType application/vnd.ms-powerpoint.slideshow.macroEnabled.12 .ppsm
AddType application/vnd.openxmlformats-officedocument.presentationml.slideshow .ppsx
AddType application/vnd.ms-powerpoint.presentation.macroEnabled.12 .pptm
AddType application/vnd.openxmlformats-officedocument.presentationml.presentation .pptx
AddType application/vnd.ms-excel.sheet.binary.macroEnabled.12 .xlsb
AddType application/vnd.ms-excel.sheet.macroEnabled.12 .xlsm
AddType application/vnd.openxmlformats-officedocument.spreadsheetml.sheet .xlsx
AddType application/vnd.ms-xpsdocument .xps

DeflateCompressionLevel 9
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript text/vbscript text/x-html text/iuls text/richtext text/scriptlet text/tab-separated-values text/webviewhtml text/x-component text/x-setext text/x-vcard application/x-javascript application/javascript image/bmp

<IfModule mod_expires.c>
ExpiresActive on
ExpiresDefault A600
ExpiresByType image/gif "access plus 1 day"
ExpiresByType image/jpeg "access plus 1 day"
ExpiresByType image/png "access plus 1 day"
ExpiresByType image/x-icon "access plus 1 day"
<FilesMatch "\.(php|php4)$">
ExpiresByType text/html "now"
</FilesMatch>
</IfModule>

This will also add mime type for the Microsoft formats that Apache does not know about by default, and set any image content to expire +1 day, so that they are not refreshed over and over.

This has reduced the servers consumption to around 80GiB per month, less then half.