Using a custom chain to define a list of trusted hosts in iptables 1
A common problem with firewalls is that you want to allow certain ports from a list of trusted hosts. For example, you have 3 locations that you commonly log into your machine from, and you want to allow ssh and mysql from these locations, but not from elsewhere. If you just added rules to the INPUT chain, you would need 3 rules for ssh, and another 3 rules for mysql, and each source address would be specified twice, once for each of these services. This is not very efficient, as adding another source would involve inserting 2 rules. Furthermore, the number of rules multiplies rapidly as additional ports or source addresses are needed.
Here's how to avoid this problem by using custom chains in iptables to allow connections from a range of different sources without having lots of similar rules in the INPUT chain. I'm doing this on Ubuntu, but this can obviously be applied to any distro.
Add the standard rules
First of all lets set up the standard incoming rules. I'm going to allow everything on the loopback interface, any packets with state RELATED or ESTABLISHED, port 80 for my web server, and icmp so people can ping my server:
sudo iptables -I INPUT 1 -i lo -j ACCEPT sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT sudo iptables -A INPUT -p icmp -m icmp --icmp-type any -j ACCEPT
Add a custom chain
Now lets say we want to allow ssh from 3 different trusted subnets. I'll use private RFC1918 addresses for this example, but in reality these would probably be the public addresses of the locations you want to log in from.
First add a "Trusted" chain:
sudo iptables -N Trusted
Then add rules to this chain that just allow anything from your trusted sources:
sudo iptables -A Trusted -s 192.168.0.0/255.255.255.0 -j ACCEPT sudo iptables -A Trusted -s 10.20.0.0/255.255.255.0 -j ACCEPT sudo iptables -A Trusted -s 172.16.0.0/255.255.0.0 -j ACCEPT
Now add a rule to your INPUT chain that hands off ssh connections to your custom chain:
sudo iptables -A INPUT -p tcp --dport 22 -j Trusted
This will check incoming ssh connections against your Trusted chain, which will allow them.
Drop all other connections
At the moment we are still allowing all incoming connections anyway. So finally, add a rule at the end of the INPUT chain to drop everything else:
sudo iptables -A INPUT -j DROP
Now your iptables should look something like this:
$ sudo iptables -L -v
Chain INPUT (policy ACCEPT 778 packets, 85228 bytes)
pkts bytes target prot opt in out source destination
56151 57M ACCEPT 0 -- lo any anywhere anywhere
446K 70M ACCEPT 0 -- any any anywhere anywhere state RELATED,ESTABLISHED
19045 1065K ACCEPT tcp -- any any anywhere anywhere tcp dpt:www
94 8056 ACCEPT icmp -- any any anywhere anywhere icmp any
4943 468K Trusted tcp -- any any anywhere anywhere tcp dpt:ssh
1695 331K DROP 0 -- any any anywhere anywhere
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 441K packets, 701M bytes)
pkts bytes target prot opt in out source destination
Chain Trusted (1 references)
pkts bytes target prot opt in out source destination
0 0 ACCEPT 0 -- any any 192.168.0.0/24 anywhere
0 0 ACCEPT 0 -- any any 10.20.0.0/24 anywhere
0 0 ACCEPT 0 -- any any 172.16.0.0/16 anywhere
And now, you can allow extra ports from your trusted sources without having to repeat your sources in the INPUT chain. For example, we can insert a rule to allow MySQL connections. This needs to be inserted before the DROP rule:
sudo iptables -I INPUT 6 -p tcp --dport 3306 -j Trusted
Saving your iptables rules
Save your rules to a file:
sudo iptables-save > /etc/iptables.rules
Now you can edit your /etc/network/interfaces file to bring up iptables automatically, and save the rules when the interface is brought down:
auto eth0 iface eth0 inet dhcp pre-up iptables-restore < /etc/iptables.rules post-down iptables-save -c > /etc/iptables.rules
For more information, see the Ubuntu iptables howto:
Fixing VMWare Server on Ubuntu Edgy
After upgrading from Dapper to Edgy and re-running vmware-tools-install, I got this error when trying to start the vmware console:
/usr/lib/vmware/bin/vmware: /usr/lib/vmware/lib/libpng12.so.0/libpng12.so.0: no version information available (required by /usr/lib/libcairo.so.2)
I found a thread about it here: http://www.vmware.com/community/thread.jspa?threadID=38856&tstart=0
The fix that actually worked was to remove libdbus-1-2:
apt-get remove libdbus-1-2
Many thanks to PsyDoc on the VMTN forum!
The Ultimate Server - Ruby on Rails with Lighttpd, Apache2 with PHP, MySQL, PostgreSQL on Ubuntu Dapper Server 12
As we all know, in the real world things are rarely simple, and the deployment of Ruby on Rails sites is certainly no exception to this rule. In fact it can sometimes seem that what Rails gives with its ease of development, it takes away when it comes to the quagmire of deployment. First you have to choose your server - Apache with FastCGI? Lighttpd? Apache with Mongrel cluster? The options can seem baffling to the newcomer.
Running first on a Debian platform, I initially deployed my Rails sites using Apache 1.3 with FastCGI. However, this proved so unreliable that eventually I was forced to take all my sites offline in order to protect the health of the rest of the system. Frequently I would notice sluggish performance, and log in to find a zombie ruby process hogging all available CPU. And I'm not alone.
So when I recently rebuilt my server using Ubuntu Dapper Server I decided to try LightTPD - AKA Lighty. The Mongrel cluster approach was out, as this requires Apache2.2, and I wanted to stick to the Ubuntu packages for ease of ongoing maintenance, and avoid compiling anything from source. My server also hosts a number of sites running happily on Apache and using PHP, so the new Lighty solution had to co-exist with these.
Based on my experience, I'm going to show how you too can build the ultimate server (tm) - one that can handle virtual hosting of Apache/PHP sites alongside multiple Rails sites on Lighty, where any site can use MySQL or PostgreSQL as its database, and all this can be made to coexist on one server using nothing more than an installation of RubyGems and the standard Ubuntu packages.
Assumptions and Requirements
Firstly I'm assuming your starting point is a bare install of Ubuntu Server. Don't select the LAMP option (although it might not hurt - I haven't tested it) as the following procedure will install everything you need. Secondly, I'm assuming you have more than one public IP available to your server. If you don't, you will need to run Lighty on a different port and proxy all your Rails sites through from Apache, as described in part 3 of this article, and also in more depth in this article.
Our finishing point is a multi-homed server with Lighty on one IP for Rails, Apache2 on another IP for Apache2/PHP sites, and MySQL and PostgreSQL support in Rails and PHP. I'm not covering things like Subversion and Capistrano here - that's a whole different can of worms. For a good tutorial on deploying onto Lighty using Capistrano, I highly recommend this article.
Part 1: Initial Setup and Package Installation
Pretty much everything that follows requires root priveleges, so to save your fingers some work, acquire a root shell:
james@ubuntu:~$ sudo -i Password: root@ubuntu:~#
To kick off, enable the Universe repositories in /etc/apt/sources.list - this is required for some packages such as irb. Then bring your server up to date and install build-essential, to allow building of mysql and postgres gems later:
apt-get update apt-get upgrade apt-get install build-essential
Next edit /etc/network/interfaces to configure your server with 2 IPs; this article will use 192.168.10.3 for Apache2 and 192.168.10.4 for Lighty. Obviously you should substitute your real, public IPs. Note the auto lines to ensure the interfaces come up on reboot:
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).
# The loopback network interface
auto lo
iface lo inet loopback
# The primary network interface
auto eth0
iface eth0 inet static
address 192.168.10.3
netmask 255.255.255.0
network 192.168.10.0
gateway 192.168.10.1
auto eth0:1
iface eth0:1 inet static
address 192.168.10.4
netmask 255.255.255.0
Now install Ruby:
apt-get install ruby1.8 ruby1.8-dev irb1.8 rdoc1.8
create symlinks:
ln -s /usr/bin/ruby1.8 /usr/bin/ruby ln -s /usr/bin/irb1.8 /usr/bin/irb
Install RubyGems:
wget http://rubyforge.org/frs/download.php/11289/rubygems-0.9.0.tgz tar -xzf rubygems-0.9.0.tgz cd rubygems-0.9.0 ruby setup.rb
Install Rails:
gem install rails --include-dependencies
Install PostgreSQL and postgres gem (ignore compilation errors):
apt-get install postgresql-8.1 postgresql-server-dev-8.1 libpgsql-ruby1.8 gem install postgres
Install MySQL and mysql gem (choose option 2):
apt-get install mysql-server libmysqlclient15-dev libmysql-ruby1.8 gem install mysql
Install fcgi gem (needed to use Rails with Lighty):
apt-get install libfcgi-dev libfcgi-ruby1.8 gem install fcgi
Make sure ruby is happy with everything installed:
root@ubuntu:~/rubygems-0.9.0# irb irb(main):001:0> require 'fcgi' => true irb(main):002:0> require 'mysql' => true irb(main):003:0> require 'postgres' => true
Install web servers:
apt-get install apache2 libapache2-mod-php5 php5-mysqli php5-pgsql php5-gd apt-get install lighttpd
Phew - that's it for package installation.
Part 2: Configuration
First set up your databases - I won't cover how to do that here. Next set up your Apache2 sites - by default Apache2 will greedily bind to all available interfaces, so you will need to edit the configuration to restrict it to only one IP, leaving the other free for Lighty. This is done by editing the /etc/apache2/ports.conf file to look something like this:
Listen 192.168.10.3:80
Then create your Apache2 virtual host configurations. In Ubuntu, vhosts live in /etc/apache2/sites-available and are activated using the command "a2ensite". In this example, I'm creating a site for example.com by creating the file /etc/apache2/sites-available/example.com as follows:
<VirtualHost 192.168.10.3:80> ServerName www.example.com ServerAlias example.com DocumentRoot /home/web/example.com/public_html Alias /webstat /home/web/example.com/stats CustomLog /home/web/example.com/logs/access.log combined ErrorLog /home/web/example.com/logs/error.log </VirtualHost>
Note that the VirtualHost declaration uses the IP explicitly. In order for this to work, you must also edit the file /etc/apache2/sites-available/default which contains the NameVirtualHost directive, so that the first 2 lines read as follows:
NameVirtualHost 192.168.10.3:80 <VirtualHost 192.168.10.3:80>
Then activate your site and restart Apache2:
a2ensite example.com /etc/init.d/apache2 restart
Netstat should now show Apache2 listening only on the desired IP:
root@ubuntu:/# netstat -ltnp | grep apache2 tcp 0 0 192.168.10.3:80 0.0.0.0:* LISTEN 7187/apache2
Now its time to set up your Rails sites using Lighty. Here is a sample /etc/lighttpd/lighttpd.conf file for a couple of Rails sites, rails1.example.com and rails2.example.com. Note the server.bind line to restrict Lighty to its own IP and avoid clashing with Apache2:
server.modules = ("mod_rewrite", "mod_accesslog", "mod_fastcgi", "mod_status")
server.bind = "192.168.10.4"
server.port = 80
server.username = "www-data"
server.groupname = "www-data"
server.pid-file = "/var/run/lighttpd.pid"
accesslog.filename = "/var/log/lighttpd/access.log"
server.errorlog = "/var/log/lighttpd/error.log"
server.indexfiles = ( "index.html" )
server.document-root = "/var/www/"
# assign mime types from /etc/mime.types
include_shell "/usr/share/lighttpd/create-mime.assign.pl"
#### status module
status.status-url = "/server-status"
# first rails site
var.rails1 = "/home/web/rails1.example.com"
$HTTP["host"] == "rails1.example.com" {
server.document-root = var.rails1 + "/public"
url.rewrite = ( "^/$" => "index.html", "^([^.]+)$" => "$1.html" )
server.error-handler-404 = "/dispatch.fcgi"
accesslog.filename = "/home/web/rails1.example.com/log/access.log"
server.errorlog = "/home/web/rails1.example.com/log/error.log"
server.indexfiles = ( "index.html" )
fastcgi.server = ( ".fcgi" =>
( "localhost" =>
( "min-procs" => 1,
"max-procs" => 2,
"socket" => "/tmp/rails1.fcgi.socket",
"bin-path" => var.rails1 + "/public/dispatch.fcgi",
"bin-environment" => ( "RAILS_ENV" => "production" )
)
)
)
}
# second rails site
var.rails2 = "/home/web/rails2.example.com"
$HTTP["host"] == "rails2.example.com" {
server.document-root = var.rails2 + "/public"
url.rewrite = ( "^/$" => "index.html", "^([^.]+)$" => "$1.html" )
server.error-handler-404 = "/dispatch.fcgi"
accesslog.filename = "/home/web/rails2.example.com/log/access.log"
server.errorlog = "/home/web/rails2.example.com/log/error.log"
server.indexfiles = ( "index.html" )
fastcgi.server = ( ".fcgi" =>
( "localhost" =>
( "min-procs" => 1,
"max-procs" => 2,
"socket" => "/tmp/rails2.fcgi.socket",
"bin-path" => var.rails2 + "/public/dispatch.fcgi",
"bin-environment" => ( "RAILS_ENV" => "production" )
)
)
)
}
Having created your config file, fire up Lighty (if you installed Apache2 first, it won't be running already, as port 80 was in use on all interfaces at that point):
/etc/init.d/lighttpd start
Part 3 - Advanced Stuff
So far, so good. By now you should have a server that can host pretty much anything you can throw at it, including multiple Rails sites as well as multiple Apache2/PHP sites, and these sites can use MySQL or PostgreSQL databases.
But what if you have a site that needs both? Supposing you have a PHP-based site running happily on Apache2, and you want to add a typo blog in a subdirectory, say coolsite.example.com/blog. You can't point the domain to both IPs, but what you can do is use Apache2's mod_proxy module to proxy the /blog subdirectory to Lighty. Your Apache2 vhost should look something like this:
<VirtualHost 192.168.10.3:80> ServerName coolsite.example.com DocumentRoot /home/web/coolsite.example.com/public_html Alias /webstat /home/web/coolsite.example.com/stats CustomLog /home/web/coolsite.example.com/logs/access.log combined ErrorLog /home/web/coolsite.example.com/logs/error.log ProxyPass /blog http://coolblog/blog ProxyPassReverse /blog http://coolblog/blog ProxyPreserveHost off </VirtualHost>
You also need to enable mod_proxy:
a2enmod proxy /etc/init.d/apache2 force-reload
This will cause Apache2 to proxy all requests for /blog to http://coolblog/blog. So you need to add an appropriate line to /etc/hosts:
192.168.10.4 coolblog
Then remove the symbolic link /etc/apache2/mods-enabled/proxy.conf, as by default this will deny access:
rm /etc/apache2/mods-enabled/proxy.conf
You can then set up a vhost in Lighty for the blog:
var.coolblog = "/home/web/blog"
$HTTP["host"] == "coolblog" {
server.document-root = var.coolblog + "/public"
url.rewrite = ( "^/$" => "index.html", "^([^.]+)$" => "$1.html" )
server.error-handler-404 = "/dispatch.fcgi"
accesslog.filename = "/dev/null"
fastcgi.server = ( ".fcgi" =>
( "localhost" =>
( "min-procs" => 1,
"max-procs" => 2,
"socket" => "/tmp/coolblog.fcgi.socket",
"bin-path" => var.coolblog + "/public/dispatch.fcgi",
"bin-environment" => ( "RAILS_ENV" => "production" )
)
)
)
}
And finally, add the following line to config/environment.rb in the typo installation:
ActionController::AbstractRequest.relative_url_root = "/blog"
And there you have it. You can now point the domain to the Apache2 IP, and it will proxy the /blog namespace through to Lighty. Note that the Lighty vhost is set to send its access log to /dev/null - this is because all the proxied requests will be logged by Apache2, and in any case, the Lighty logs will only show the requests as coming from Apache2, which doesn't make for very useful logs.
Wrap-up
Feel free to pick and choose bits from this tutorial - everyone's situation is different. But if what I've written here helps you, or you find a bug in my carefully-tested procedure, please leave a comment. In the meantime, happy configuring!
Passed my RHCE! 4
I'm now officially certified!
Dear James:
The results of your RHCE Certification Exam are reported below. The RHCE Certification Exam allows candidates to qualify for the Red Hat Certified Engineer (RHCE) and Red Hat Certified Technician (RHCT) certificates. Please note that the RHCE designation is understood to both include and supersede the RHCT designation.
SECTION I: TROUBLESHOOTING AND SYSTEM MAINTENANCE
RHCE requirements: completion of compulsory items (50 points)
overall section score of 80 or higher
RHCT requirements: completion of compulsory items (50 points)
Compulsory Section I score: 50.0
Non-compulsory Section I score: 50.0
Overall Section I score: 100
SECTION II: INSTALLATION AND CONFIGURATION
RHCE requirements: score of 70 or higher on RHCT components (100 points)
score of 70 or higher on RHCE components (100 points)
RHCT requirement: score of 70 or higher on RHCT components (100 points)
RHCT components score: 90.9
RHCE components score: 78.6
RHCE Certification: PASS
Congratulations -- you are now certified as a Red Hat Certified Engineer!
Switching my Parents to Ubuntu 1
So I was round at my parents house last weekend, when I heard the dreaded words "can you have a look at the computer, it says we've got a virus". Switching on the PC, I was puzzled when some minutes after logging in, lo and behold, a window popped up onto the screen kindly informing me that the PC was infected by some sort of nasty, and inviting me to part with cash to procure an AV product known as "WinAntiVirus". I was not running IE at the time, and the window wasn't a browser window. So there was definitely something nefarious on the PC.
Now at this point, alarm bells started to ring. For one thing, I already had AVG antivirus installed, and it had not detected any viruses. Furthermore, I had never heard of WinAntiVirus before. A quick Google search confirmed that it was in fact spyware, and had numerous links to various instructions for its removal.
My next course of action was to run Ad-Aware, which was already installed on the PC. This completely failed to find the problem, let alone fix it. So I downloaded Spybot Search & Destroy, but this was equally oblivious to WinAntiVirus. Another google search suggested that Spyware Doctor could remove it, so I tried that. After chugging away and reporting that it had found about 146 problems, it then hung on the next step using 100% CPU, so I had to kill it.
At this point, I had to admit defeat. The next step would have to be a complete reinstallation of Windows. However, I started to think - if a PC can be infected with malware simply by clicking something on a website, and then that malware preys on the user's knowledge that "viruses = bad, antivirus = good" then how is the average user supposed to avoid falling victim to this kind of scam?
So I thought about whether this PC needed to be running Windows at all. My parents only use it for web browsing (mostly with Firefox), email, and getting photos from their digital camera. Nothing that Linux can't handle just as easily, if not more so. So I decided to install Ubuntu. Initial reactions were positive, although its too early to say how well they are getting on with it. I'll find out when I go round again tomorrow, so I'll post a follow-up article at a later date.
Ubuntu xinetd configuration for proftpd 5
When you "sudo apt-get install proftpd" on Ubuntu, debconf will tell you that if you're using xinetd then you're on your own. Here is what you need to put in /etc/xinetd.d/proftpd to make it work:
# default: on
# description: ProFTPD FTP server
service ftp
{
flags = REUSE
socket_type = stream
instances = 50
wait = no
user = root
server = /usr/sbin/proftpd
}
Then just do "sudo /etc/init.d/xinetd restart", and you're all set.
VMware Server Beta on Ubuntu 7
Anyone wanting to run virtual machines on Ubuntu will be interested to hear that VMware currently have a beta version of VMware server available for free download. However, installation has a few pitfalls, so here is how to do it.
Dapper Update
I'm still amazed by the popularity of this article. For anyone still struggling with the installation of VMWare Server (now out of beta but still a free download) - you'll be pleased to know that its easier on Dapper as you don't need to worry about the gcc version. As described in the comment from mips below (many thanks mips), you just need to do this:
$ sudo apt-get install build-essential xinetd linux-headers-`uname -r`
$ sudo ./vmware-install.pl
Prepare your host
To run any VMware products on Ubuntu, there are a couple of prerequisites. The installation involves compilation of a kernel module, so you first need to install the kernel headers for your kernel version, for example:
root@ubuntu:~ # uname -a
Linux ubuntu 2.6.12-10-k7 ...
sudo apt-get install linux-headers-2.6.12-10-k7
You will also need gcc-3.4 (edit: only necessary on Ubuntu Breezy):
sudo apt-get install gcc-3.4
Get VMware Server
Next head over to www.vmware.com/products/server/ and download the free VMware Server beta. You will need to register and then you will get a license key by email.
Download the tar.gz version, extract it, and cd to the installation directory:
tar -xzvf VMware-server-e.x.p-22874.tar.gz
cd vmware-server-distrib
Run the installer, making sure you will be using gcc-3.4 (Breezy only):
export CC=/usr/bin/gcc-3.4
./vmware-install.pl
Accept all the defaults, with the possible exception of the directory to store your virtual machines - I chose to put them in a subdirectory of my home directory, as space is limited in my root partition. Note you'll be prompted for your license key during installation - this will be in your email.
Try out the Browser Appliance
To test out your shiny new VMware installation, download the Browser Appliance pre-built virtual machine from the VMware site. You'll be pleased to discover that its actually a pretty standard installation of Ubuntu 5.10!
To run it, fire up VMware Server from your Gnome (or KDE) menu, and choose to open an existing VM. If your host machine is in a NAT network behind a router that gives out addresses with DHCP, then change the eth0 networking type to "bridged". Networking should then work straight away - your guest machine will pick up an IP from your router.
And that's all folks - comments welcome as always!