Nginx Multiple Domains, Postfix Email, and Mailman Mailing Lists

Linux No Comments

See my previous post, Install Ubuntu, LEMP, and WordPress on an Unmanaged VPS, to learn how to set up an unmanaged VPS (virtual private server) with Ubuntu, LEMP, and WordPress. In this post, I will configure Nginx to support multiple domains (aka virtual hosts) on the VPS, get Postfix email send and receive working, and install a Mailman mailing list manager.

Note: Though I’m doing the work on a DigitalOcean VPS running Ubuntu LTS 12.04.3, the instructions may also apply to other VPS providers.

Host Another Domain

To host another domain (say mydomain2.com) on the same VPS, we need to add another Nginx server block (aka virtual host) file. Run the commands below on the server.

Note: You don’t need to input the lines that start with the pound character # below because they are comments.

# Create a new directory for the new domain
sudo mkdir /var/www/mydomain2

# Create a test page.
sudo nano /var/www/mydomain2/index.html
   # Input this content:
   <html><body>
   Welcome to mydomain2.com.
   </body></html>

# Change owner to www-data (which Nginx threads run as) so Nginx can access.
sudo chown -R www-data:www-data /var/www/mydomain2

# Create a new Nginx server block by copying from existing and editing.
sudo cp /etc/nginx/sites-available/wordpress /etc/nginx/sites-available/mydomain2
sudo nano /etc/nginx/sites-available/mydomain2
        # Change document root from "root /var/www/wordpress;" to:
        root /var/www/mydomain2;
        # Change server name from "server_name mydomain.com www.mydomain.com;" to:
        server_name mydomain2.com www.mydomain2.com;

# Activate new server block by create a soft link to it.
sudo ln -s /etc/nginx/sites-available/mydomain2 /etc/nginx/sites-enabled/mydomain2

# Reload the Nginx service so changes take effect.
sudo service nginx restart

The server block files allow Nginx to match the “server_name” domain to the inbound URL and to use the matching “root” directory. When a browser connects to the VPS by IP address (and thus, doesn’t provide a domain for matching), Nginx will use the first virtual host that it loaded from the “/etc/nginx/sites-enabled/” directory (the order of which could change every time you reload Nginx).

To select a specific virtual host to load when accessed by IP address, edit the related server block file under “/etc/nginx/sites-available/” directory and add a “listen 80 default_server” statement to the top like so:

server {
        #listen   80; ## listen for ipv4; this line is default and implied
        #listen   [::]:80 default ipv6only=on; ## listen for ipv6
        listen 80 default_server;

Note: The “listen 80 default_server;” line should only be added to one of the server block files. The behavior may be unpredictable if you add it to more than one block file.

Send Email (using Postfix)

We will install Postfix, a Mail Transfer Agent which works to route and deliver email, on the VPS to support sending and receiving mail. WordPress (and its plugins like Comment Reply Notification) uses Postfix to send emails. While we could use a more simple, send-only mail transfer agent like Sendmail, we will need Postfix later when we install Mailman (a mailing list service) which depends on it. In this section, we will configure Postfix and test the send mail function.

Before we start, we need to talk about Postfix. Postfix is very sophicated and can be configured in many different ways to receive mail. I want to suggest one way which I believe works well for many domains on a VPS. The setup I’m suggesting is to have one default local delivery domain (mydomain.com) and many virtual alias domains (mydomain2.com, etc). A local delivery domain is an endpoint domain, meaning that when mail arrives there, it is placed into the local Linux user’s mailbox. A virtual alias domain is used to route mail sent to it to a local delivery domain.

For example, if you send an email to “susan@mydomain2.com” (virtual alias domain), Postfix will route the email to “susan@mydomain.com” (local delivery domain), and then delivered the mail to the local Linux “susan” user’s inbox.

Keep the above in mind as we configure Postfix and hopefully everything will be understandable. We will go step by step and build upon our understanding. We will get the local delivery domain working first and then later, add the virtual alias domain into the mix.

Install Postfix by running these commands on the server:

# Install Postfix package and dependencies.
sudo apt-get install postfix
   # Select "Internet Site" and input our local delivery domain (mydomain.com).

# Configure Postfix to use local delivery domain.
sudo nano /etc/postfix/main.cf
   # Update "myhostname = example.com" to:
   myhostname = mydomain.com
   # Double-check that "mydestination" includes local delivery domain:
   mydestination = mydomain.com, localhost, localhost.localdomain

# Reload Postfix so changes will take effect.
sudo service postfix reload

Note: I had trouble inputting the domain name when installing Postfix and ended up with a combination of the default “localhost” and my domain name, specifically “lomydomain.com”. To fix this, I had to modify the “mydestination” value in “/etc/postfix/main.cf” and in the content of “/etc/mailname” file to be the correct domain name. The “myorigin” value in “/etc/postfix/main.cf” file references the “/etc/mailname” file.

The Postfix service should be started already and it is configured to start on boot by default. To send a test email, use the Sendmail command line (Sendmail was installed as dependency of the Postfix installation) on the server:

sendmail emailto@domain.com

To: emailto@domain.com
Subject: PostFix Test Email

This is the subject of a test email sent after configuring Postfix.

# Press CTRL-D key combo to end

Note: The From email address is constructed based upon the currently logged-in Linux username and the “myorigin” value in “/etc/postfix/main.cf” (which in turn, points at the “/etc/mailname” file that contains the local delivery domain name). Thus, the From address should be “mynewuser@domain.com”).

To test the PHP send mail feature, run the following commands on the server:

# Install the PHP command line package.
sudo apt-get install php-cli

# Enable logging of PHP-CLI errors to a file
sudo nano /etc/php5/cli/php.ini
   # Add this line:
   error_log = /tmp/php5-cli.log
   # You must use a writeable directory like /tmp.

# Open the PHP interpretive shell and call the mail() function
php -a
php > mail('emailto@domain.com', 'Subject here', 'Message body here');
php > quit

If the PHP mail function works, then most likely WordPress and its plugins should be able to send emails. To be absolutely sure, you can install the Check Email plugin to test sending an email from within WordPress.

Receive Mail (to Local Delivery Domain)

By default, Postfix is configured to deliver emails sent to “postmaster@mydomain” to the local Linux “root” user’s inbox. You can tell this from the following Postfix settings:

cat /etc/postfix/main.cf
   ...
   alias_maps = hash:/etc/aliases
   mydestination = mydomain.com, localhost, localhost.localdomain
   ...

cat /etc/aliases
   ...
   postmaster: root

In the Postfix’s “main.cf” file, the “alias_maps” value points to an email-to-local-user mapping file for the local delivery domain, and the “mydestination” value contains the default local delivery domain “mydomain.com” (ignore the localhost entries).

In the “alias_maps” file “/etc/aliases”, the “postmaster” email username is mapped to the root user’s inbox. Putting it together, any email sent to “postmaster@mydomain.com” will be delivered to the root user’s inbox.

Note: Mail can be delivered to any of the local Linux users by using their exact usernames, even though they are not listed in “alias_maps”. For example, emails sent to “root@mydomain.com” will be delivered to the local root user and emails sent to “mynewuser@mydomain.com” will be delivered to the local mynewuser user.

To receive external emails sent to the VPS, we need to open up the SMTP (Simple Mail Transfer Protocal) port in the firewall and create a DNS MX (Mail exchange) record. (Port 25 is the default SMTP port use for receiving emails.)

To open up the SMTP port, run the following commands on the server:

# Allow SMTP port 25.
sudo ufw allow smtp

# Double-check by looking at the firewall status.
sudo ufw status

I used DigitalOcean’s DNS management web interface to add a MX record pointing at “@” (which is the A record that resolves to mydomain.com) and priority 10 for mydomain.com. The priority allows us to add more than one MX record and determines the order of mail servers to submit the emails to. Rather than using the highest priority 0, using priority 10 will allow me to easily add a mail server before or after this one in the future.

Note: Most websites will suggest creating a CNAME record (redirecting “mail” to “@”) for mail.mydomain.com and then configuring the MX record to point at mail.mydomain.com. This is not necessary. The most simple configuration is to just point the MX record to the A record “@” as I did above.

To see if the DNS was updated with the MX record, I ran the following test command on the server (or any Linux machine):

dig mydomain.com MX @ns1.digitalocean.com

# technical details are returned, the most important is the ANSWER SECTION.
;; ANSWER SECTION:
mydomain.com.         1797    IN      MX      10 mydomain.com.

In the above example “ANSWER SECTION”, we can see that the MX record for mydomain.com points at mydomain.com (as the mail receiving server) with priority 10 (as configured). The 1797 value is the TTL (Time to Live) setting in seconds (1797 seconds is about 29.95 minutes) which indicates how long this MX record is valid for. DNS servers which honor this TTL setting will refresh at that rate; however, some DNS servers may ignore the TTL value in favor of much longer refresh times. (The A and CNAME records also have TTL values. DigitalOcean does not allow me to customize the TTL values for any DNS record.)

If the “ANSWER SECTION” is missing from the output, then your VPS provider may not have updated its DNS servers yet. (DigitalOcean DNS servers took 20 minutes to update the MX record.) Similar to the mydomain.com’s A and CNAME record changes, you may need to wait for the MX record to propagate across the internet (most DNS servers will be updated in minutes, while some may take hours).

Also, you can use the intoDNS website to check your MX record details. Input your domain name, click on the Report button, and look for the “MX Records” section. If your domain’s MX record shows up there, you can be reasonably certain that it has propagated far enough for you to start sending emails to your domain.

Test by sending an email to “postmaster@mydomain.com” from your local mail client (or Google Mail or Yahoo Mail). To see if the mail was received, do the following on your server:

# View the root user's received mail store for the email you sent.
sudo more /var/spool/mail/root

# Alternatively, install the mail client to view and delete received emails.
sudo apt-get install mailutils
# Read mail sent to the local root user.
sudo mail
   # type "head" to see a list of all mail subject lines.
   # type a number (ex: 1) to see the mail content.
   # type "del 1" to delete that mail.
   # type "quit" to exit mail client.

Note: If you want to check a non-root user’s inbox, log in as that non-root user and just run “mail”, instead of “sudo mail”.

Note: According to Internet standards, all mail-capable servers should be able to receive emails sent to their “postmaster” address. While it may be overkill, I decided to create MX records and postmaster aliases for all the domains that I host on the VPS.

Receive Mail (to other Virtual Alias Domains)

Now that we know that the server can receive emails, we want to configure Postfix to support emails sent to the multiple domains hosted on the VPS. (If you want more local users than “root” and “mynewuser”, use the “adduser” command per the previous post to create new users.)

Recall our earlier discussion about how a virtual alias domain will route mail to the local delivery domain (“mydomain.com”), which will finally deliver the mail to the local user’s inbox. We will configure the additional domains like “mydomain2.com” to be virtual alias domains.

First, we need to create a mapping file that will map from the virtual alias domain to the local delivery domain. Run this command on the server to create that file:

sudo nano /etc/postfix/virtual

In the “virtual” mapping file, input the following lines:

mydomain2.com IGNORE # Declare virtual alias domain
postmaster@mydomain2.com postmaster

In the first line, we are using a newer feature of Postfix to declare a virtual alias domain “mydomain2.com” by starting the line with it. (The previous, alternative method was put the virtual alias domain declarations into a “virtual_alias_domains” property in the “/etc/postfix/main.cf” file.) The rest of the first line, “IGNORE …”, is ignored. The second line indicates that mail sent to “postmaster@mydomain2.com” should be routed to “postmaster” at the local delivery domain; that is, “postmaster@mydomain.com”.

Configure Postfix to use the new virtual alias domain mapping file:

sudo nano /etc/postfix/main.cf
   # Add a new virtual_alias_maps line:
   virtual_alias_maps = hash:/etc/postfix/virtual

# Update the hash db version of /etc/postfix/virtual that Postfix uses.
sudo postmap /etc/postfix/virtual

# Reload Postfix so changes take effect.
sudo service postfix reload

Test by sending an email to the email address configured in the virtual alias mapping file; in this case, “postmaster@domain2.com”. Per the previous instruction, check the root user’s inbox by using the “sudo mail” command.

Install Mailing List Service (Mailman)

Besides supporting mailing lists, Mailman (GNU Mailing List Manager) allows mailing list administration by web interface or by sending email messages (like subscribe or unsubscribe messages).

Update: Recently (latter half of 2016), emails sent to my mailing list were not delivered to Google Mail recipients. I found the following error from Google in the ‘/var/log/mail.log’ file: “Our system has detected an unusual rate of 421-4.7.0 unsolicited mail originating from your IP address. To protect our 421-4.7.0 users from spam, mail sent from your IP address has been temporarily 421-4.7.0 rate limited.” The issue is not spam because my mailing list gets only a few emails per week. This support page suggests that Google now requires SPF+DKIM for mail relays. I decided to migrate the mailing list to Google Groups for now.

To install Mailman, run the following commands on the server:

# Install Mailman
sudo apt-get install mailman

# Create a mandatory site list named mailman
sudo newlist mailman

The “newlist” command will request the following:

To finish creating your mailing list, you must edit your /etc/aliases (or
equivalent) file by adding the following lines, and possibly running the
`newaliases' program:

## mailman mailing list
mailman:              "|/var/lib/mailman/mail/mailman post mailman"
mailman-admin:        "|/var/lib/mailman/mail/mailman admin mailman"
...

Ignore that instruction. You don’t need to manually edit the Postfix “/etc/aliases” file. Later on, we will configure Mailman to automatically generate its own aliases file, which Postfix will read from.

Once the site wide “mailman” list is created, we can start the Mailman service by running this command:

sudo service mailman start

Mailman is configured to start on boot by default. (Running “sudo service mailman status” won’t output anything useable; to see if Mailman is running, list its processes using “ps -aef | grep -i mailman” instead.)

To get Mailman’s web interface working, we will need to install FcgiWrap (Simple CGI support) so that Nginx can integrate with Mailman. FcgiWrap works similarly to how PHP-FPM (FastCGI Process Manager for PHP) was used by Nginx to pass the processing of PHP files to the PHP platform. FcgiWrap will be used by Nginx to pass the Mailman-related interface calls to Mailman.

To install FcgiWrap, run the following command on the server:

sudo apt-get install fcgiwrap

FcgiWrap will be started automatically after installation. By default, FcgiWrap is configured to start at boot time. FcgiWrap uses a unix socket file “/var/run/fcgiwrap.socket” (similar to how PHP-FPM uses “/var/run/php5-fpm.sock”) to communicate with Mailman. (Similar to Mailman, running “service fcgiwrap status” won’t output anything useable; to see if FcgiWrap is running, list its processes using “ps -aef | grep -i fcgiwrap” instead.)

Edit the Nginx server block file belonging to the domain that you want to make the Mailman web interface accessible under. For example, run this command on the server:

sudo nano /etc/nginx/sites-available/mydomain2

In the mydomain2 server block file, add the following lines to the end of the “service” section:

service {
        ...

        location /cgi-bin/mailman {
               root /usr/lib/;
               fastcgi_split_path_info (^/cgi-bin/mailman/[^/]*)(.*)$;
               fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
               include /etc/nginx/fastcgi_params;
               fastcgi_param PATH_INFO $fastcgi_path_info;
               #fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
               fastcgi_intercept_errors on;
               fastcgi_pass unix:/var/run/fcgiwrap.socket;
        }
        location /images/mailman {
               alias /usr/share/images/mailman;
        }
        location /pipermail {
               alias /var/lib/mailman/archives/public;
               autoindex on;
        }
}

Note: I did two things above differently from what most websites would say to do:

  • I put the “fastcgi_param SCRIPT_FILENAME …” line before “include /etc/nginx/fastcgi_params;” to avoid it getting overwritten by “fastcgi_params”; otherwise, the call to Mailman would fail with a 403 Forbidden Access error message.
  • I commented out “fastcgi_param PATH_TRANSLATED …” because it is not necessary.

Reload Nginx to make the changes take effect:

sudo service nginx reload

You can now browse to the following Mailman administrative pages:

  • http://mydomain2.com/cgi-bin/mailman/admin/mylistname – manage the “mylistname” list.
  • http://mydomain2.com/cgi-bin/mailman/listinfo/mylistname – info about the “mylistname” list.
  • http://mydomain2.com/pipermail – view the mailing list archives.

We still need to integrate Mailman with Postfix so that emails sent to mailing lists, especially those belonging to virtual alias domains, will be routed to Mailman by Postfix.

Edit the Mailman configuration by running this command on the server:

sudo nano /etc/mailman/mm_cfg.py

In the “mm_cfg.py” file, add or uncomment and modify these lines like so:

MTA = 'Postfix'
POSTFIX_STYLE_VIRTUAL_DOMAINS = ['mydomain2.com']

Mailman has the capability of generating aliases for Postfix. We will use that capability. Run these commands on the server:

# Create Mailman's aliases and virtual-mailman files.
sudo /usr/lib/mailman/bin/genaliases

# Make the generated files group-writeable.
sudo chmod g+w /var/lib/mailman/data/aliases*
sudo chmod g+w /var/lib/mailman/data/virtual-mailman*

Note: The “genaliases” command will generate “aliases”, “aliases.db”, “virtual-mailman”, and “virtual-mailman.db” files in the “/var/lib/mailman/data” directory.

We then add the generated Mailman aliases and virtual aliases files to the Postfix “alias_maps” and “virtual_alias_maps” properties.

To edit Postfix, run this command on the server:

sudo nano /etc/postfix/main.cf

In the Postfix “main.cf” file, add to the end of the “alias_maps” and “virtual_alias_maps” lines like so:

alias_maps = hash:/etc/aliases, hash:/var/lib/mailman/data/aliases
virtual_alias_maps = hash:/etc/postfix/virtual, hash:/var/lib/mailman/data/virtual-mailman

Note: The changes above will configure Postfix to read and process Mailman’s generated aliases files, in addition to its own aliases files.

Reload Postfix to have the changes take effect:

sudo service postfix reload

Recall earlier, I said to ignore the instructions by “newlist” to add Mailman aliases to the Postfix “/etc/aliases” file because we would do it automatically later. That is just what we did above.

Look at the Mailman’s generated “aliases” file by running this command on the server:

sudo cat /var/lib/mailman/data/aliases

# STANZA START: mailman
# CREATED: Tue Mar 25 05:53:44 2014
mailman:             "|/var/lib/mailman/mail/mailman post mailman"
mailman-admin:       "|/var/lib/mailman/mail/mailman admin mailman"
...
# STANZA END: mailman

It should look exactly like the aliases outputted by the “newlist” command. Mailman’s generated “aliases” file is included in Postfix’s “alias_maps” and thus is processed by Postfix along with the contents of the original “/etc/aliases” file.

To test a mailing list belonging to a virtual alias domain, run these commands on the server:

# Create a test mailing list.
sudo newlist test@mydomain2.com

# Reload Postfix to make changes take effect.
sudo service postfix reload

The “newlist” command will automatically update Mailman’s “aliases” and “virtual-mailman” aliases file with entries for “test@mydomain2.com”. However, we still need to manually reload Postfix so that Postfix will pick up the changes. (Reloading Postfix requires sudo/root access, so Mailman can’t do it automatically).

Let’s look at Mailman’s updated “aliases” and “virtual-mailman” files to see what was added (the pre-existing, generated “mailman” list aliases are omitted below):

sudo cat /var/lib/mailman/data/aliases

# STANZA START: test
# CREATED: Tue Mar 25 05:56:47 2014
test:             "|/var/lib/mailman/mail/mailman post test"
test-admin:       "|/var/lib/mailman/mail/mailman admin test"
...
# STANZA END: test

sudo cat /var/lib/mailman/data/virtual-mailman

# STANZA START: test
# CREATED: Tue Mar 25 05:56:47 2014
test@mydomain2.com              test
test-admin@mydomain2.com        test-admin
...
# STANZA END: test

Recall that a virtual alias domain routes to a local delivery domain, which then delivers to an endpoint (inbox or in the case above, a program called Mailman). For example, when a mail is sent to the “test@mydomain2.com” mailing list, it is routed to “test@mydomain.com” (local delivery domain), and then passed to the “mailman post test” program, which then forwards a copy to each member of the “test” mailing list.

Note: Because all mailing lists also exist under the local delivery domain, the mailing list name must be unique across all the domains hosted on the machine.

To test, access the Mailman web interface at “http://mydomain2.com/cgi-bin/mailman/admin/test” to add members to the “test@mydomain2.com” mailing list. Then send an email to that mailing list and its members should each receive a copy.

Once, you are done testing, you can delete the list by running this command on the server:

# Remove list test@mydomain2.com (don't include @mydomain2.com part below).
sudo /usr/lib/mailman/bin/rmlist -a test

# Reload Postfix to make changes take effect.
sudo service postfix reload

Debugging Mail

Both Postfix and Mailman will output error messages and debug logs to:

/var/log/mail.err
/var/log/mail.log

At this point, my VPS is hosting several domains, I can send and receive emails, and I have mailing lists working. See my followup post, Nginx HTTPS SSL and Password-Protecting Directory, to learn how to configure Nginx to enable HTTPS SSL access and to password-protect a directory.

Most info above derived from:

No Comments

Install Ubuntu, LEMP, and WordPress on an Unmanaged VPS

Linux 4 Comments

Before this post, I was hosting my website using a shared web hosting provider. Shared web hosting is convenient because the provider takes care of the software platform and its security updates (though I am still responsible to update a PHP application like WordPress). And if there is a problem with the platform, the provider is responsible to fix it. Unfortunately, shared web hosting may have performance and scalability issues (resulting from overcrowded websites on the single shared server and strict restrictions on CPU and memory usage) and disallows non-PHP software installation such as a Subversion server.

With the above in mind, I decided to look into unmanaged VPS (virtual private server) hosting as an alternative to shared web hosting. A virtual server is cheaper than a physical server and an unmanaged server is cheaper than a managed server. A managed VPS provider would install the software stack for me and provide support for about $30 or more per month. An unmanaged VPS depends on me to install the software and only costs $5 per month with DigitalOcean. The downside to unmanaged VPS is that if anything goes wrong with the software, I am responsible to fix it.

Note: If you decide to, please use this referral link to signup for a DigitalOcean account and get $10 in credit. Once you spend $25, I will get a $25 credit. It’s a win-win for both of us.

In this post, I will outline the steps I took to install WordPress on an unmanaged VPS hosted by DigitalOcean. Most of these instructions may be applicable to other VPS providers.

Create VPS

When creating a VPS, the most important choice is the operating system. I recommend getting the latest Ubuntu Server LTS (long-term support) version, currently 12.04.4. All up-to-date software packages should support the LTS version of Ubuntu so it is a safe choice to make. Unfortunately, DigitalOcean only offered the LTS version 12.04.3 so I chose that. Because it will be a long time, if ever, before I would need a VPS with more than 4GB memory, I decided to choose the 32bit version to keep memory usage as minimal as possible.

You should have an IP address and root password for your VPS before proceeding.

Secure VPS

Remote access to the VPS is accomplished by SSH (Secure Shell). (If you know telnet, think of SSH as an encrypted version of telnet.) By default, servers are setup to use SSH with port 22 and user root. Unsophisticated hackers would attempt to gain access to a server using those settings and a brute force password generator. While a very hard to guess root password would make the server more secure, it is even better to change the SSH port number and use a non-root user.

Note: While Mac OS X comes with a built-in SSH client, Windows does not. I recommend downloading the free DeltaCopy SSH client “ssh.exe” for Windows. Alternatively, you can download the free PuTTY SSH client “putty.exe” if you want a GUI client, instead of a command line client.

Note: Lines below that start with the pound character # are comments and you don’t need to input them.

Run these commands:

# Connect to your server.
ssh root@mydomain.com

# Change the root password.
passwd

# Create a new non-root user.
adduser mynewuser

We will configure the new user to execute commands with root privileges by using the sudo (super user) tool. Sudo involves pre-pending all commands with the word “sudo”. Sudo will prompt for the root password. (You can also configure sudo to log all commands issued using it.) We will grant all sudo privileges to the new user by adding to “/etc/sudoers” under the “User privilege specification” section like so:

# visudo opens /etc/sudoers using vi or nano editor, whichever is the configured text editor.
# It is equivalent to "sudo vi /etc/sudoers" or "sudo nano /etc/sudoers" but includes validation.
visudo
   # Add mynewuser to the "User privilege specification" section
   root       ALL=(ALL:ALL) ALL
   mynewuser  ALL=(ALL:ALL) ALL

To disallow SSH root login and to change the SSH port number (say from 22 to 3333), edit the SSH configuration “sshd_config” file and make the following changes:

sudo nano /etc/ssh/sshd_config
   # Change the default listen "Port 22" to the custom port:
   Port 3333

   # Do not permit root user login by changing "PermitRootLogin yes" to:
   PermitRootLogin no

   # Allow only mynewuser to connect using SSH
   AllowUsers mynewuser

   # Optionally, disable useDNS as it provides no real security benefit
   UseDNS no

Reload the SSH service so the changes can take effect:

sudo reload ssh

Test the new settings by opening up a command window on your client and running the following commands:

ssh -p 3333 root@mydomain.com
ssh -p 3333 mynewuser@mydomain.com

The attempt to SSH using the root user should fail. The attempt using the new user should succeed. If you cannot SSH into the server with the new user, double-check the changes using your original SSH window (which should still be connected to your server). If you don’t have that original SSH window still connected, your VPS provider should provide console access (like having a virtual keyboard and monitor connected directly to the VPS) through their website for recovery scenarios such as this.

Tip: You can log into the root account after you SSH into the mynewuser account by running the “su -” superuser command. You will be prompted for the root password.

The UFW (Uncomplicated Firewall) tool allows us to easily configure the iptables firewall service, which is built into the Ubuntu kernel. Run these commands on the server:

# Allow access to custom SSH port and HTTP port 80.
sudo ufw allow 3333/tcp
sudo ufw allow http

# Enable the firewall and view its status.
sudo ufw enable
sudo ufw status

The above steps configure a basic level of security for the VPS.

Install LEMP

WordPress requires an HTTP server, PHP, and MySQL. The LEMP (Linux, Nginx, MySQL, PHP) software stack matches those requirements. (Nginx is pronounced “engine-ex” which explains where the “E” acronym came from.) You may be more familiar with the LAMP stack, which uses Apache instead of Nginx as the HTTP server. Nginx is a high-performance HTTP server which uses significantly less CPU and memory than Apache would under high load situations. By using Nginx, we allow for the capability of handling greater numbers of page requests than usual.

On the server, run these commands:

# Update installed software packages.
sudo apt-get update

# Install MySQL.
sudo apt-get install mysql-server php5-mysql
sudo mysql_install_db

# Secure MySQL.
sudo /usr/bin/mysql_secure_installation

# Do a test connect to MySQL service.
mysql -u root -p
mysql> show databases;
mysql> quit

When installing MySQL, you will be prompted to input a MySQL root password. If you leave it blank, you will have another opportunity to change it when running the “mysql_secure_installation” script. You will want to answer yes to all the prompts from the “mysql_secure_installation” script to remove anonymous MySQL users, disallow remote MySQL root login, and remove the test database.

MySQL is not configured to start on boot by default. To start MySQL at boot time, run only the first command below:

# Start MySQL at boot time.
sudo update-rc.d mysql defaults

# FYI, undo start MySQL at boot time.
sudo update-rc.d -f mysql remove

If you have issues connecting to MySQL, you can start MySQL in an unsecured safe mode (which bypasses the password requirement) to perform a recovery action such as resetting the MySQL root password like so:

# Stop normal MySQL service and start MySQL in safe mode.
sudo service mysql stop
sudo mysqld_safe --skip-grant-tables &

# Connect to MySQL, change root password, and exit.
mysql -u root
mysql> use mysql;
mysql> update user set password=PASSWORD("newrootpassword") where User='root';
mysql> flush privileges;
mysql> quit

# Stop MySQL safe mode and start normal MySQL service.
sudo mysqladmin -u root -p shutdown
sudo service mysql start

Install and start Nginx by running these commands on the server:

sudo apt-get install nginx
sudo service nginx start

Browse to your server’s IP address and you should see a “Welcome to nginx!” page.

To make it possible for Nginx to serve PHP scripts, we need to install the PHP platform and the PHP-FPM (FastCGI Process Manager for PHP) service. PHP-FPM enables Nginx to call the PHP platform to interpret PHP scripts. PHP-FPM should be already installed as dependencies of the “php5-mysql” package (part of the MySQL installation instructions above). We can make sure that PHP-FPM (and its dependency, the PHP platform) is installed by trying to re-install it again (trying to install an already installed package doesn’t do any harm).

# List the installed packages and grep for php name matches:
dpkg --get-selections | grep -i php

# Install PHP-FPM package.
sudo apt-get install php-fpm

# Test the install by displaying the version of PHP-FPM.
php5-fpm -v

Secure and optimize the PHP-FPM service by running these commands on the server:

# Fix security hole by forcing the PHP interpreter to only process the exact file path.
sudo nano /etc/php5/fpm/php.ini
   # Change the "cgi.fix_pathinfo=1" value to:
   cgi.fix_pathinfo=0

# Configure PHP to use a Unix socket for communication, which is faster than default TCP socket.
sudo nano /etc/php5/fpm/pool.d/www.conf
   # Change the "listen = 127.0.0.1:9000" value to:
   listen = /var/run/php5-fpm.sock

# Restart the PHP-FPM service to make the changes effective.
sudo service php5-fpm restart

Nginx defines the site host (and each virtual host) in a server block file. The server block file links the domain name to a directory where the domain’s web files (HTML, PHP, images, etc.) are located. When you browse to the VPS, Nginx will serve files from the directory that corresponds to the domain name given by your browser. That is simple explanation of how Nginx can support hosting more than one domain on a single VPS.

Edit the default server block file to support PHP scripts:

sudo nano /etc/nginx/sites-available/default

In the “default” server block file, change the following:

server {
        # Add index.php to front of "index" to execute it first by default (if it exists)
        index index.php index.html index.htm;
        # Optionally, WordPress sites only need the index.php value like so:
        #index index.php

        # Change "server_name localhost;" to:
        server_name mydomain.com www.mydomain.com;

        # Use these directives if URL is matched to root / location.
        location / {
                # try_files will try a directory if file does not exist, and then
                # if directory does not exist, will try a default like index.html.
                # For WordPress site, we need to change "try_files $uri $uri/ /index.html;" to:
                try_files $uri $uri/ /index.php?$args;
                # The $args is necessary to support the Wordpress post preview function.
                # If you don't change this, then non-default permalink URLs will fail with 500 error.
        }

        # Uncomment the whole "location ~ \.php$" block except for the "fast_cgi_pass 127.0.0.1:9000;" line.
        # "location ~\.php$" means to match against any files ending in .php.
        # Leave the default "fastcgi_pass unix:/var/run/php5-fpm.sock" line
        # (it already matches what is in /etc/php5/fpm/pool.d/www.conf above).
        location ~ \.php$ {
                fastcgi_split_path_info ^(.+\.php)(/.+)$;

                # With php5-cgi alone:
                #fastcgi_pass 127.0.0.1:9000;
                # With php5-fpm:
                fastcgi_pass unix:/var/run/php5-fpm.sock;
                fastcgi_index index.php;
                include fastcgi_params;
        }

Restart the Nginx service to have the changes take effect:

sudo service nginx restart

Create a PHP test script by running this edit command:

sudo nano /usr/share/nginx/www/info.php

In “info.php” file, input the following text:

<?php
phpinfo();
?>

Browse to “http://mydomain.com/info.php” and you should see a page containing information about the PHP installation.

Both PHP-FPM (php5-fpm) and Nginx are configured to start at boot time by default. You can double-check by running the chkconfig utility to list the services and their runlevel configurations:

# Install chkconfig package.
sudo apt-get install chkconfig

# List all services and their runlevels configurations.
chkconfig --list

Note: You won’t be able to use chkconfig to change the runlevels because it is not compatible with the new Upstart runlevel configuration used by Ubuntu. Instead, use update-rc.d or sysv-rc-conf to make runlevel changes.

Debugging LEMP

To debug issues with LEMP, look at these log files:

MySQL: /var/log/mysql/error.log
Nginx: /var/log/nginx/error.log
PHP: /var/log/php5-fpm.log

For performance reasons, the debug logs from the PHP-FPM worker threads are discarded by default. If you wish to see error logs from your PHP applications, you will need to enable logging from worker threads.

Run the following commands on the server:

# Edit the PHP-FPM worker pool config file to enable logging.
sudo nano /etc/php5/fpm/pool.d/www.conf
   # Uncomment this line:
   catch_workers_output = yes

# Reload the PHP-FPM service to make the changes take effect.
sudo service php5-fpm reload

You should now see error logs from the PHP worker threads outputted to the “/var/log/php5-fpm.log” file.

Install WordPress

Install WordPress by running the following commands on the server:

# Get the latest WordPress version.
cd /tmp
wget http://wordpress.org/latest.tar.gz

# Uncompress the WordPress archive file.
tar zxvf latest.tar.gz

# Create a wp-config.php configuration file by copying from the sample.
cd wordpress
cp wp-config-sample.php wp-config.php

# Move the WordPress files to the Nginx root document directory.
sudo mv wordpress/* /usr/share/nginx/www/

# Change ownership to www-data user (which Nginx worker threads are configured to run under).
sudo chown -R www-data:www-data /usr/share/nginx/www/*

Note: If WordPress detects its configuration file “wp-config.php” is missing, it will offer to run a web-based wizard to create it. However, the wizard won’t work because our MySQL root user requires a password. Besides, using the wizard would not be very secure because the WordPress database’s MySQL user password would be sent in the clear over HTTP. Instead, we manually created the “wp-config.php” file in the above steps and will modify it below.

Create a MySQL database and user for WordPress by running these commands on the server:

# Open a MySQL interactive command shell.
mysql -u root -p

# Create a MySQL WordPress database.
mysql> create database wordpress;

# Create a MySQL user and password.
mysql> create user wordpress@localhost;
mysql> set password for wordpress@localhost = PASSWORD('mypassword');

# Grant the MySQL user full privileges on the WordPress database.
mysql> grant all privileges on wordpress.* to wordpress@localhost identified by 'mypassword';

# Make the privilege changes effective.
mysql> flush privileges;

# Double-check by showing the privileges for the user.
mysql> show grants for wordpress@localhost;

# Exit the MySQL interactive shell.
mysql> quit

Update the WordPress configuration file by running this command:

sudo nano /usr/share/nginx/www/wp-config.php

In the “wp-config.php” file, input the newly-created MySQL database, user, and password like so:

define('DB_NAME', 'wordpress');
define('DB_USER', 'wordpress');
define('DB_PASSWORD', 'mypassword');

Browse to your server’s IP address and follow the WordPress instructions to complete the installation.

Change WordPress Document Root

This section is optional. If you wish to store the WordPress installation into an alternative directory path, say “/var/www/wordpress”, instead of “/usr/share/nginx/www”, follow the steps below. (I suggest “/var/www/wordpress” instead of “/var/www” so that later, when you host additional domains, the WordPress installation will be in its own separate directory.)

To move WordPress to a new directory, run these commands on the server:

# Move WordPress files to new directory.
sudo mkdir -p /var/www/wordpress
sudo mv /usr/share/nginx/www/* /var/www/wordpress/

# Rename the existing Nginx server block file.
sudo mv /etc/nginx/sites-available/default /etc/nginx/sites-available/wordpress

# Update the Nginx server block file with new location.
sudo nano /etc/nginx/sites-available/wordpress
   # Change document root from "root /usr/share/nginx/www;" to "root /var/www/wordpress;".

# Enable the renamed Nginx server block by creating soft link.
sudo ln -s /etc/nginx/sites-available/wordpress /etc/nginx/sites-enabled/wordpress

# Remove the old Nginx server block soft link (which points at a non-existing file).
sudo rm /etc/nginx/sites-enabled/default

# Reload the Nginx service so the changes can take effect.
sudo service nginx reload

Test this change by browsing to your server’s IP address. You should see the WordPress website.

Migrate WordPress

When migrating an existing WordPress site to your new VPS, I suggest doing the following steps:

  1. On your old WordPress server, update WordPress and all plugins to the latest versions.
  2. On the new WordPress server, browse to “http://mydomain.com/wp-admin/” to install the same theme and plugins as exist on the old server. Activate the theme. Leave all the plugins inactive. When we do the WordPress database restore, the plugins will be configured and activated to match what was in the old server.
  3. Copy the old image uploads directory to the new server. Supposing that the WordPress on the old server is located at “/home/username/public_html/wordpress”, run the following commands on the new server:
    sudo scp -r username@oldserver:/home/username/public_html/wordpress/wp-content/uploads /var/www/wordpress/wp-content/
    sudo chown -R www-data:www-data /var/www/wordpress/wp-content/uploads

    Note: If the old server uses a custom SSH port number, scp will require the custom port number as a “-P” input parameter; for example, “sudo scp -r -P 2222 username@oldserver…”.

  4. Export the WordPress database from the old server using the recommended phpMyAdmin interface (which generates a more human-friendly SQL output than mysqldump) or by running the following command on the old server:
    mysqldump -u oldusername -p olddatabasename > wordpress.sql
  5. Before importing the WordPress database into the new server, we will need to change references to the image uploads directory (and other directories) in the exported SQL file. If you don’t make this change, then images may not be visible in the WordPress postings. Following the example above, replace any occurance of “/home/username/public_html/wordpress/” with “/var/www/wordpress/” in the exported database SQL file.
  6. Copy the exported SQL file to the new server, say to the “/tmp” directory.
  7. On the new server, run these commands:
    # Open up MySQL command shell.
    mysql -u root -p

    # Empty the existing WordPress database.
    mysql> drop database wordpress;
    mysql> create database wordpress;

    # Exit the MySQL command shell.
    mysql> quit

    # Import the exported SQL file.
    mysql -u root -p wordpress < /tmp/wordpress.sql

    Note: Dropping and re-creating the WordPress database does not affect the WordPress database user and its privileges.

Browse to your new server’s IP address and you should see your WordPress website. Unfortunately, we cannot verify that the images are loading correctly on the new server because the image URLs use the domain name which points at the old server (the images are loaded from the old server, not the new server). We now need to point the domain at our new server.

Migrate Domain

I used DigitalOcean’s DNS (Domain Name System) “Add Domain” tool to create an A (Address) record (“@” => “server_ip_address”) linking mydomain.com to the new server’s IP address. I also added a CNAME (Canonical name) record (“www” => “@”) to have www.mydomain.com point at mydomain.com. I tested whether DigitalOcean’s DNS servers were updated or not by repeatedly running one of these two commands on the server (or any Linux machine):

nslookup mydomain.com ns1.digitalocean.com
nslookup www.mydomain.com ns1.digitalocean.com

Note: DigitalOcean’s DNS servers took about 20 minutes to update.

Once DigitalOcean’s DNS servers had lookup entries for my domain name, I went to my domain registrar and updated my domain’s name servers to point at DigitalOcean’s DNS servers. To test whether DigitalOcean’s DNS servers were being used or not, I occasionally ran the following commands on my client machine to check the IP address returned:

nslookup mydomain.com
ping mydomain.com

Once the new IP address was returned consistently (it took 24 hours before my internet provider’s DNS servers were updated), I then browsed to mydomain.com and checked that the images were loading correctly.

You can empty the DNS caches on your machine and browser by using any of these commands:

# On Windows:
ipconfig /flushdns

# On Mac OS X:
sudo dscacheutil -flushcache

# On Chrome, browse to URL below and click on the "clear host cache" button.
chrome://net-internals/#dns

If you want to check the DNS change propagation across the whole world, try the What’s My DNS? website. It will make calls to DNS name servers located all over the planet.

At this point, I have a working VPS that is reasonably secured and successfully hosting my migrated WordPress website. Some rough page load tests resulted in 0.5-1 second load times, as opposed to the 2-4 seconds on the old server (which was shared web hosting with a LAMP stack). I hope that this guide will help you should you decide to move your WordPress website to an unmanaged VPS.

See my followup post, Nginx Multiple Domains, Postfix Email, and Mailman Mailing Lists, to configure Nginx to support multiple domains, get Postfix email flowing, and get Mailman mailing lists working.

Most info above is derived from the following sources:

4 Comments

Subversion Over SSH With HostGator Shared Web Hosting

Linux 1 Comment

Even more surprising, I was able to get Subversion over SSH working with my HostGator shared web hosting account. I had been searching for a private Subversion repository that I could use for my own projects. Something very simple for one developer doing infrequent source control file check-ins. I didn’t want to use the free and/or public Subversion hosting companies because I didn’t want to expose my code; I wanted to strictly control code ownership. So, using Subversion with my shared web hosting account was the perfect answer to my needs.

BasselopeDisclaimer: Please don’t abuse this info by setting up a Subversion repository on your shared HostGator web hosting account for a bunch of active developers. Because it is shared hosting, such an action would probably cause issues for other customers and Hostgator may decide to prevent this usage. Use this as a private, one developer Subversion repository (equivalent to having a local repository and rsync’ing it to/from your web host, though a lot more convenient).

Before you start, you must have SSH public key authentication working. On Mac OS X, you also must create the “%HOME%/.ssh/config” file to use port 2222 by default. See my previous post, SSH and SSL With HostGator Shared Web Hosting, for instructions.

Create Subversion Repository

Create a Subversion repository on the server by issuing the following commands:

ssh -p 2222 myusername@mydomainname.com
cd mydirectory
mkdir myrepos
svnadmin create myrepos

Test Subversion Client Connection

On Mac OS X, test your connection to the Subversion repository by running the following:

svn list svn+ssh://myusername@mydomainname.com/myhome/myusername/mydirectory/myrepos

If successfully, this should output an empty line (because you don’t have anything in the repository yet) instead of a connection error message.

On Windows, we need to configure Subversion to use a SSH tunnel with port 2222 by default. Modify the “%APPDATA%\Subversion\config” file by adding a custom line below the “[tunnels]” section:

[tunnels]
ssh = ssh -p 2222

We can then test the Subversion client’s connectivity on Windows by running the same command as on Mac OS X:

svn list svn+ssh://myusername@mydomainname.com/myhome/myusername/mydirectory/myrepos

The change to “%APPDATA%\Subversion\config” will cause all svn+ssh calls to use port 2222. This will break connectivity to servers which do not use 2222 for the SSH port. One can accommodate this scenario by creating a custom tunnel name like so:

[tunnels]
ssh2222 = ssh -p 2222

Then, to use it, the Subversion client command to run would look like this:

svn list svn+ssh2222://myusername@mydomainname.com/myhome/myusername/mydirectory/myrepos

To avoid duplication, we will use “svn+ssh” for both Mac OS X and Windows in the instructions below. Please adjust accordingly if you decide to use a custom tunnel name.

Add Project To Repository

Add or import a project into the Subversion repository using the following command on the Mac OS X or Windows client:

svn import ./myproject svn+ssh://myusername@mydomainname.com/myhome/myusername/mydirectory/myrepos/myproject -m "Initial import"

Run the previous “svn list” test command to see the imported project listed in the subversion repository.

Checkout the Project

On the client, checkout or export the project to another local directory:

svn co svn+ssh://myusername@mydomainname.com/myhome/myusername/mydirectory/myrepos/myproject ./myproject2

Once the checkout is complete, you can issue subversion commands in the local, checked out project directory without having to specify the “svn+ssh” URL like so:

cd ./myproject2
svn update
...
svn diff
svn ci -m "first commit"

The subversion commands will use the “svn+ssh” URL stored locally in the checked out project’s “.svn” configuration directory.

The purpose of the subversion commands above and others are explained in a previous blog, Add Subversion to the XAMPP Apache Server.

Secure File Permissions

The Subversion server may write files which include read access for the group and others. To close this security hole, I suggest manually restricting the file permissions in the Subversion repository after importing a project or adding assets.

These commands will set read-write access for only the user on all folders and files under the Subversion repository:

find ~/mydirectory/myrepos -type f -print0 | xargs -0 chmod 600
find ~/mydirectory/myrepos -type d -print0 | xargs -0 chmod 700

Information concerning the custom SSH tunnel gotten from How to configure SVN/SSH with SSH on non standard port?.

1 Comment

SSH and SSL With HostGator Shared Web Hosting

Linux No Comments

Surprisingly, I found that a Hostgator shared web hosting account supports secure shell (SSH) access and a shared secure sockets layer (SSL) certificate. For those who might not be familiar with them, SSH provides interactive terminal access to your account and SSL supports secure HTTPS browsing to your website.

Note: Most instructions below are not specific to a Hostgator shared web hosting account. They may work with your shared web hosting account also.

Enable SSH Access

To enable SSH access for your Hostgator shared web hosting account, do the following:

  1. Browse to Hostgator’s Billing/Support System page.
  2. Log in using your billing/support email address and password (this may be different from your cPanel administrative password).
  3. Click on the “View Hosting Packages” link under “Hosting Packages”.
  4. Click on the “Enable Shell Access” link near the top of the middle content pane.

Note: Hostgator SSH uses port 2222, instead of the standard SSH port 22. So when running the SSH client, make sure to use port 2222.

SSH Into Your Hostgator Account

Mac OS X comes with a built-in SSH client. To connect to Hostgator, launch the Terminal application and run ssh with port 2222 with this command:

ssh -p 2222 myusername@mydomainname.com

Windows does not come with a built-in SSH client, so I recommend using the free Putty SSH client. Browse to the PuTTY Download Page and download the “putty.exe” file. Run it and input the following:
putty_2222

  1. Under Session (selected by default under the Category panel on the left), input the “Host Name” and the Port 2222.
  2. Under Connection and then Data, input your username in the “Auto-login username” field.
  3. Optional: To avoid having to re-input these values the next time you run Putty, go back to Session, input a name in the “Saved Sessions” field, and click the Save button. The next time, just select the session you saved and click Load to automatically re-populate the fields.
  4. Click on the Open button to make the SSH connection.

Your website files are located under the “~/www” directory which is soft-linked to the “~/public_html” directory.

SSH With Public Key Authentication

If you SSH into Hostgator often, it may be worthwhile to use public key authentication to avoid having to input your password. Public key authentication consists of two steps: (a) generate a public and private key pair on the client and (b) copy the public key to the server into a trusted location. After those steps, instead of asking for a password, the server will authenticate the SSH connection by matching its trusted copy of the client’s public key against the client’s private key.

Before we start, SSH into your Hostgator account and make sure that the “~/.ssh” directory exists on the server by running these commands:

mkdir -p ~/.ssh
chmod 700 ~/.ssh

The mkdir command above will create the “~/.ssh” directory if it does not already exist. The “~/.ssh” directory is the server’s default location for trusted public and private key files. The chmod command sets the permission on the “~/.ssh” directory to only allow access for the user and no one else. We will copy the client’s public key to this “~/.ssh” directory on the server.

SSH Public Key Authentication on Mac OS X

Mac OS X comes with the built-in “ssh-keygen” and “scp” (secure copy) utilities which we can use to generate a public and private key pair, and to copy the public key to the server.

ssh-keygen -t rsa
scp -P 2222 ~/.ssh/id_rsa.pub myusername@mydomainname.com:~/.ssh/authorized_keys
ssh -p 2222 myusername@mydomainname.com 'chmod 600 ~/.ssh/authorized_keys'

The ssh-keygen command above will generate a public and private key pair using RSA protocol 2 with 1024 bits. It will prompt you to input a passphrase (to protect access to the private key) which I recommend you leave blank; otherwise, you will be prompted for the passphrase each time you connect, which would defeat the purpose of avoiding password input. The private and public key files are created in the client’s “~/.ssh” directory as “id_rsa” and “id_rsa.pub” respectively. The scp command copies the public key to the server as “~/.ssh/authorized_keys”, which is the server’s default trusted public key file. The chmod command sets permission on the “~/.ssh/authorized_keys” file to only allow access for the user and no one else.

To test, run the SSH command and you should automatically be authenticated using the public key. You should not be prompted to input the password.

ssh -p 2222 myusername@mydomainname.com

If you are tired of having to input the port 2222, you can set it as the default by creating the “~/.ssh/config” file with the following content:

Host mydomainname.com
  Port 2222
  PreferredAuthentications publickey,password

When connecting to your hosting server, the SSH client will use port 2222 by default and either public key authentication (publickey) or password authentication (password).

Once the file above is created, you should be able to SSH without having to input the port 2222:

ssh myusername@mydomainname.com

SSH Public Key Authentication on Windows

Because Windows does not have the built-in “ssh-keygen” and “scp” utilities, you will need to download the following files from PuTTY Download Page: “puttygen.exe” (ssh-keygen), “pscp.exe” (scp), and “plink.exe” (SSH command line).

Then, launch “puttygen.exe” to generate the public and private key pair:

    puttygen_1024

  1. RSA Protocol 2, “SSH-2 RSA”, should be selected by default.
  2. Leave the “Number of bits in a generated key” as 2048 or change it to 1024. (I used 1024 bits which is adequate for my purpose.)
  3. Click the Generate button.
  4. Move the mouse inside the dialog window until the key pair is generated.
  5. I recommend that you leave the “Key passphrase” blank; otherwise, you will be prompted for the passphrase every time you connect.
  6. Copy the contents of the “Public key for pasting into OpenSSH authorized_keys file” textfield to a file named “id_rsa.pub”.
  7. Click the “Save private key” button and name the private key file “id_rsa.ppk”.
  8. Click the “Save public key” button and name the public key file “id_rsa.publickey”. Note that the contents of this public key file is different from that of the “Public key for pasting into OpenSSH authorized_keys file”.

Finally, copy the the “Public key for pasting into OpenSSH authorized_keys file” to the server using the Window’s Command Prompt shell and the Putty versions of scp and SSH command line utilities:

pscp -scp -P 2222 id_rsa.pub myusername@mydomainname.com:~/.ssh/authorized_keys
plink -P 2222 myusername@mydomainname.com chmod 600 ~/.ssh/authorized_keys

Configure the Putty SSH client to use public key authentication:

  1. Per the previous Putty instructions, input the server’s hostname, port 2222, and your username. Or if you have a saved session, under Session, select your session name, and click the Load button.
  2. Under Connection, SSH, and Auth, click on the “Browse…” button at the bottom and locate the private key file “id_rsa.ppk”.
  3. Optional: You can update your saved session by going to Session, selecting your named session, and clicking the Save button.
  4. Click the Open button to connect to your server by SSH. You should not be prompted to input the password.

Troubleshoot SSH Public Key Authentication

If the above does not work (you are still prompted for the password), then it may be that the server has its own generated public and private key pair installed. For my Hostgator account, I found that the public key authentication failed because my server had its own public and private key files in the “~/.ssh” directory.

To fix this issue, SSH into your Hostgator account and delete all files under the “~/.ssh” directory except the “authorized_keys” file. Try to SSH from your client again and hopefully you won’t need to input the password.

Using Shared SSL Certificate

SSL certificates are used to encrypt the web traffic between your browser and the server. On your browser, the URL will start with “https” (instead of the unsecured “http”), with perhaps a lock icon visible, when SSL is in use. Normally, you would buy a SSL certificate that is linked directly to your domain name; if the domain name doesn’t match the name in the SSL certificate, the browser would display a warning. Purchasing a SSL certificate can be expensive because you must renew it every year; for example, a SSL certificate costs $69/year from GoDaddy.

Hostgator provides a free shared SSL certificate for your use. It is less secure than your own personal SSL certificate because it is shared by all accounts hosted on the same Hostgator server. (Conceivably, another account holder on the same Hostgator server could decrypt the encrypted web traffic to your server, but that requires a lot of know-how and a ton of trouble.)

Because the shared SSL certificate is tied to the Hostgator server’s hostname, you cannot use it when browsing to your domain name. Instead, you would browse to the Hostgator server’s hostname with a relative path to your username, which corresponds to your primary domain website directory.

https://secureXXXX.hostgator.com/~myusername/

To find the hostname of the Hostgator server which your account is hosted on, do the following:

  1. Browse to Hostgator’s cPanel interface using “http://mydomainname/cpanel”.
  2. Log in using your Hostgator administrative username and password.
  3. Look for the “Account Information” panel in the bottom-left corner.
  4. The “Server Name” field contains your hosted server’s hostname (ex: “gator3141”). To get the secured hostname, replace “gator” with “secure” (ex: “secure3141.hostgator.com”).

Instead of using the cryptic secured URL above, you can create a more friendly redirect from your website. You could browse to your domain name and automatically be redirected to the secured URL. I don’t recommend redirecting from your website’s root address (unless that is what you want); instead, I suggest creating a directory called “secure” under the website’s root directory, which will hosts the content to be accessed by SSL.

To create the redirect, SSH into your Hostgator account and create a file with this path and name, “~/www/secure/.htaccess”, and the following content:

RewriteEngine On
RewriteCond %{SERVER_PORT} 80
RewriteCond %{REQUEST_URI} register
RewriteRule ^(.*)$ https://secureXXXX.hostgator.com/~myusername/secure/$1 [R,L]

Please make sure that the “.htaccess” file has 644 permission. When you browse to any file under “http://mydomainname/secure/”, you will be redirected to “https://secureXXXX.hostgator.com/~myusername/secure/”.

If you wish to use SSL with an add-on or sub domain, just append the add-on or sub domain name to the end of the secured URL:

https://secureXXXX.hostgator.com/~myusername/mysubdomainname.com/

Some info above derived from How can I force users to access my page over HTTPS instead of HTTP?.

No Comments

Holy Cow, Batman! My Linux Server Got Hacked!

Linux 3 Comments

It was quiet, peaceful Tuesday night when I attempted to log into my Ubuntu Linux server as the root user. Permission denied, I got back. I tried it again. And again. Access denied. What the heck? I’m sure it was the correct password. I then tried all the passwords that it could be, from past to present. No luck. I got a sinking feeling. My root password was easy to remember and thus, easy to guess. I think my Linux server has been hacked!

No problem, I thought, I just have to reboot and log into single user mode… uh, unfortunately, my Linux server was sitting somewhere in cyberspace and I couldn’t do any of that. So I called up the service provider and they said, we didn’t touch your server and we don’t know who did. However, for $25, they can reset the root password. Having no choice, I accepted. Hours passed and finally I got an email with the new password.

I logged in, viewed the “/etc/passwd” file, and noticed two new users. Bad news, my server definitely got hacked. Good news, the hackers weren’t too sophisticated and had left a huge clue. I immediately copy the users’ info down and deleted them. Then it was off to google for what to do after a server hack. After looking at several websites, the most relevant one I found was How to restore a hacked Linux server.

What I got from the research was that once your Linux server is compromised, the best solution is to re-install the operating system. I did not want to do that because it would cost (a) money to ask the service provider to reinstall Ubuntu and (b) time for me to reinstall the applications. So I decided to play detective, find any damages, and fix them. Below are the steps I took.

1. Are there any unidentified users?

Run the following to list the users and groups:

more /etc/passwd
more /etc/group

Make a copy of the unknown users’ info, especially their usernames and ids, and delete them using the “userdel <unknown_username>” command. You should also check for and delete their home directories, located at “/home/username”.

2. Are there any strange processes running?

Run the following to list all the active processes started by the root or by the unidentified users:

ps -aef | grep root
ps -aef | grep <unknown_username>

Look for processes with weird names like “AkjwetSAG”; these are usually suspect. You can then run “lsof -p <process_id>” to get more info.

On my Ubuntu server, I found two processes, “avahi-daemon: chroot helper” and “/usr/sbin/console-kit-daemon –no-daemon”, that looked weird; but it turned out they were valid processes. After some quick online searches, I found that Avahi was used to detect network devices (not necessary for a server so it can be disabled or deleted) and console-kit was used for GUI related functions.

3. Are there any tracks left by the perpetrators?

Run the following to find any commands to change a password in the system:

cd /var/log
grep -R -i passwd *

This command returned several entries in the “auth.log” which included password changes for the unidentified user accounts. Strangely, there was no reference to a password change for the root user. By luck, there were two “Invalid user passwd from <ip_address>” messages containing the IP addresses of the perpetrators.

I then did a search on each of those two IP addresses:

grep -R -i <ip_address> *

I got back a ton of entries in “auth.log” which show numerous failed attempts using different usernames from these two IP addresses. I guess they kept trying until they got lucky. And they got lucky about five days ago.

Just for curiosity’s sake, I installed traceroute (it isn’t installed on Ubuntu by default) to see where the perpetrators came from:

apt-get install traceroute
traceroute <ip_address>

One of the IP address came from “CHINA-NETCO.edge3.SanJose1.Level3.net” and the other from “DC-PT-01-te1-2.ip4.012.net.il”. China and Israel. But there was no guarantee that those were the origins because the perpetrators could have hacked some machines there and then used those machines to hack into my server.

4. Are there any surprises left behind?

To be on the safer side, I installed and ran two rootkit scanners recommended by the website I found:

apt-get install rkhunter
rkhunter --check

apt-get install chkrootkit
chkrootkit

Both reported a clean bill of health. There were one or two false positives which I investigated and cleared. Finally, some good news! It looks like the hackers didn’t do anything damaging (cross my fingers).

5. Any strange new files?

One of the recommended actions was to look for new files that were created since the break-in. But I didn’t find this useful at all; it was like looking for a needle in a haystack. (Funny, in real life, robbers take stuff. In cyberspace, they leave stuff… malicious stuff.)

On Ubuntu, I couldn’t find a way to search for newly created files since 5 days ago. So I did the next best thing, which was to search for files last modified in the past 5 days.

find / -mtime -5

Unfortunately, the service provider had rebooted the machine as part of the password reset. So I got a ton of results back. Too much info to process.

6. What can I do to prepare for the next assault?

First, secure the root access. I changed the root password to an incomprehensible, random string of numbers, letters (lower and upper case), and special symbols. Try guessing that! And I will only share this root password with one other person as a backup.

Second, enable auditing of the server so we will have a record of every command issued by any user. This will make it easier to figure out what actions any user, legitimate or not, does on the server. I installed the Process Accounting (psacct or acct) service which this website recommended.

apt-get install acct
service acct start

By default, the service is configured to start on bootup. To double-check, I tried using the “update-rc.d acct defaults” command but got back a strange warning “update-rc.d: warning: acct stop runlevel arguments (0 1 6) do not match LSB Default-Stop values (1)”. I didn’t know what it meant so decided to use an alternative check:

apt-get install chkconfig
chkconfig acct

This command returned “acct on”, meaning that the Process Accounting service was configured to start on bootup.

Hopefully the above info will help you should you ever encounter the same misfortune. And maybe, the last section might help you to be better prepared.

3 Comments

Install MySQL, Apache, PHP, Java, Subversion, TWiki on Ubuntu 10.04 64bit

Linux No Comments

ubuntuWe decided to migrate from a virtual OpenSuSE Linux server running on my desktop to a dedicated server hosting company. Unfortunately, I missed the OpenSuSE selection as an operating system choice and ended up choosing Ubuntu 64bit. Below are the initial steps I took to setup our development environment on Ubuntu.

(You can skip this section if you wish to.) For those interested, we picked CalPOP – California Point of Presence as our dedicated server hosting company for three reasons:

  • They were located locally in Los Angeles, CA.
  • They offered the best bang for the buck: a Dual Core Server with 4GB memory for just $69/month.
  • After calling and talking to their sales and support (to ask some technical questions), I found them responsive and friendly. They seem to really care about getting our business.

Install MySQL 5

  1. Run the following commands as root user:
    apt-get install mysql-server
    update-rc.d mysql defaults
    service mysql status
    mysql --version
  2. “apt-get” stands for Advanced Packaging Tool and is Ubuntu’s RPM package manager.
  3. The “update-rc.d” command above will configure the MySQL Server to start on bootup.

Install Apache HTTP Server

  1. Run the following commands as root user:
    apt-get install apache2
    update-rc.d apache2 defaults
    service apache2 status
  2. Some Apache related directories:
    • Configuration Directory: /etc/apache2
    • Debug Log Directory: /var/log/apache2
    • Default Document Root Directory: /var/www

Install PHP 5

  1. Run the following commands as root user:
    apt-get install php5
    apt-get install libapache2-mod-php5
    apt-get install php5-mysql
    apt-get install php5-cli
    php -version
    service apache2 restart
  2. The PHP configuration files are located under the “/etc/php5” directory.
  3. When you restart Apache, you might see this warning: “Could not reliably determine the server’s fully qualified domain name”. To resolve this warning, edit the “/etc/apache2/httpd.conf” file (strangely, it is an empty file), add a new line containing “ServerName replace_with_your_hostname”, save and restart Apache.

Install Sun Java JDK 6

  1. Edit “/etc/apt/sources.list”.
  2. Uncomment the two lines referring to the partner repository:
    deb http://archive.canonical.com/ubuntu lucid partner
    deb-src http://archive.canonical.com/ubuntu lucid partner
  3. Run the following commands as root user:
    apt-get update
    apt-get install sun-java6-jdk
  4. Double-check that the sun jdk is configured properly by running:
    java -version
    javac -version
  5. If you have multiple JRE/JDKs installed, you can configured which one to use by running this command and selecting the default java installation to use:
    update-alternatives --configure java
  6. Some useful directories to know:
    • Configuration Directory: /etc/java-6-sun
    • Installation Parent Directory: /usr/lib/jvm

Install Subversion

  1. Run the following commands as root user:
    apt-get install subversion libapache2-svn
    svn --version
  2. Create the repository directory:
    mkdir -p /var/svn/repos
    svnadmin create /var/svn/repos
    chown -R www-data:www-data /var/svn/repos
    chmod -R g+w /var/svn/repos
  3. Optionally, if you are moving a subversion repository from an old server, do the following:
    (On old server)
    svnadmin dump /srv/svn/repos > backup.svn
    (Suggest that you gzip the result, copy it to the new server, and gunzip it there.)
    (On new server)
    svnadmin load /var/svn/repos < backup.svn
    chown -R www-data:www-data /var/svn/repos
    chmod -R g+w /var/svn/repos

Enable Apache HTTPS/SSL

  1. Create a vhost config for SSL:
    cp /etc/apache2/sites-available/default-ssl /etc/apache2/sites-enabled/
  2. Edit the “/etc/apache2/sites-enabled/default-ssl” file and modify so the SSL uses a different directory than “/var/www” and a different error log file:
    DocumentRoot /var/www-ssl
    <Directory /var/www-ssl>

    ErrorLog /var/log/apache2/ssl_error.log
  3. Enable the SSL module and restart apache:
    a2enmod ssl
    service apache2 restart

    The “a2enmod ssl” command just adds the “ssl.conf” and “ssl.load” files to the “/etc/apache/modes-enabled” directory so that the ssl module will be loaded by Apache on startup.

  4. Browse to your server using the secured “https://localhost/” URL.

Install Subversion for Apache SSL

  1. Enable the apache subversion modules:
    a2enmod dav
    a2enmod dav_svn
  2. Edit the “/etc/apache2/mods-enabled/dav_svn.conf”, uncomment the lines below, and also add the “SSLRequireSSL” keyword to force only SSL access.
    <Location /repos>
      DAV svn
      SVNPath /var/svn/repos/

      SSLRequireSSL

      AuthType Basic
      AuthName "Subversion Repository"
      AuthUserFile /var/svn/dav_svn.passwd

      Require valid-user
    </Location>

    “Require valid-user” causes Apache to require the user to login to do any action including viewing the repository.

  3. To create subversion users, use this command to generate the “var/svn/dav_svn.passwd” file:
    (For first user only)
    htpasswd -mc /var/svn/dav_svn.passwd <i>username1</i>
    (For subsequent users)
    htpasswd -m /var/svn/dav_svn.passwd <i>username2</i>

    You will be prompted to input the password for the user. Be careful to only use the “-c” create flag the first time because it will overwrite any existing password file.

  4. Restart the apache server with “service apache2 restart”.
  5. Browse to your subversion repository using the secured “https://localhost/repos/” URL.

Install TWiki

  1. TWiki requires the Perl RCS library. Also, we want to enable the Apache Rewrite module. Run the following as the root user:
    apt-get install librcs-perl
    a2enmod rewrite
  2. You can setup a secured TWiki using information from my previous post, Install TWiki on the OpenSUSE Linux Development Server.
  3. Alternatively, to migrate the TWiki from the old OpenSuSE server to the new Ubuntu server, I did the following:
    (On old server, under /srv/www/htdocs-ssl)
    tar czvf twiki.tar.gz twiki
    (Copy the twiki.tar.gz to the new server.)
    (On new server, under /var/www/htdocs-ssl)
    tar xzvf twiki-files.tar.gz

    chown -R www-data:www-data /var/www/htdocs-ssl/twiki
    chmod -R u+rw /var/www/htdocs-ssl/twiki
    chmod -R g+rw /var/www/htdocs-ssl/twiki

    I also migrated the twiki.conf:

    • Copied it to “/etc/apache2/twiki.conf”.
    • Updated the paths in it from “/srv/www/htdocs-ssl/twiki” to “/var/www/htdocs-ssl/twiki”.
    • To allow running the TWiki configure script remotely, be sure to comment out the restriction below. When you are done, you can uncomment it back.
      #<FilesMatch "^(configure)$">
      #    SetHandler cgi-script
      #    Order Deny,Allow
      #    Deny from all
      #    Allow from localhost
      #</FilesMatch>
    • Added the following line to “/etc/apache2/sites-enabled/default-ssl”, inside the “VirtualHost” section: “Include /etc/apache2/twiki.conf”.
    • And restarted Apache with “service apache2 restart”.

    Finally, I had to run “https://localhost/twiki/bin/configure” in order to adjust the paths as follows:

    • Under “General path settings”, update {PubDir}, {TemplateDir}, {DataDir}, {LocalesDir}, and {WorkingDir}.
    • Under “Log files”, update {ConfigurationLogName}, {DebugFileName}, {WarningFileName} and {LogFileName}.

    If you encounter problems (like the TWiki not rendering your content), you can refer to the TWiki Upgrade Guide for alternative methods to migrate your TWiki. In the end, I downloaded the latest TWiki version, installed it, configured it, and then merged my “twiki/data” and “twiki/pub” content from the old to the new TWiki.

The info above is consolidated from the following sources:

No Comments

Install Mysql, Apache, and PHP on CentOS 5.6 Linux

Linux 1 Comment

centosRecently, I had to setup a LAMP environment on a temporary CentOS 5.6 Linux server. (CentOS is the open source equivalent to the Red Hat Linux operating system.) Pleasantly, using Yum (Yellow dog Update, Modified), which is the CentOS and Red Hat RPM package manager, makes the task super simple. I did the following tasks while logged into a SSH shell as the root user.

Note: CentOS does not officially support the Sun Java SDK due to a licensing issue (I think). You will need to go through some hoops to get Sun Java SDK working on the CentOS. I attempted to install the latest JDK by downloading and executing the .bin, but it failed with dependency errors. I found this alternative approach, Installing Java (Sun JDK 1.6.0) on CentOS 5, but couldn’t complete it because my CentOS server started throwing segmentation faults and freezing (probably due to OS corruption or a hardware issue).

Change Hostname (Optional)

Run the command line tool “system-config-network” to change the hostname entry. This tool will update “/etc/sysconfig/network” and “/proc/sys/kernel/hostname”. You can run the “hostname” command to double-check.

Install Mysql

Run the following commands:

yum install mysql-server
yum install mysql
yum install mysql-devel

service mysqld start
chkconfig mysqld on

The last two commands will start the MySQL server and configure it to run on boot.

Install Apache

Run the following commands:

yum install httpd mod_ssl

service httpd start
chkconfig httpd on

The Apache Server will have HTTPS/SSL access enabled by default. However, it will use the same htdocs directory “/var/www/html” as the HTTP. To change the HTTPS to use a different document root directory, edit the “/etc/httpd/conf.d/ssl.conf” and add the following:

DocumentRoot "/var/www/html-ssl"
<Directory "/var/www/html-ssl">
   Options Indexes FollowSymLinks
   AllowOverride None
   Order allow,deny
   Allow from all
</Directory>

To have the change take effect, restart the Apache Server by running “service httpd restart”. Check the “/var/log/httpd/ssl_error_log” for errors specific to the HTTPS service.

Install PHP

Run the following commands:

yum install php-common php-gd php-mcrypt php-pear php-pecl-memcache
yum install php-mhash php-mysql php-xml

(You can combine the above packaged into one line if you wish to.)

If you need json_encode and json_decode methods, you will need to install the PHP JSON package. Unfortunately, the CentOS 5.6 Yum installs PHP 5.1 so you cannot run “yum install php-json” because it requires PHP 5.3. To install the JSON package onto PHP 5.1, run the following:

pear install pecl/json
echo "extension=json.so" > /etc/php.d/json.ini
service httpd restart

Good luck and have fun!

The info above is consolidated from:

1 Comment

Install TWiki on the OpenSUSE Linux Development Server

Linux No Comments

opensuseWhen you’re working in a small engineering team, one of the best tools for collaboration is a wiki. After looking at TikiWiki, MediaWiki, and TWiki, I decided to use TWiki. TWiki had the most sophisticated syntax for formatting a page. TWiki’s syntax trumped the downsides of using Perl and files, instead of PHP and MySQL which are used by TikiWiki and MediaWiki.

Below are notes I took when installing and securing TWiki on our OpenSUSE Linux development server.

  1. Perl 5.12 comes pre-installed with OpenSUSE 11.3. Double-check that it is installed properly by running:
    perl -version
  2. Browse to http://twiki.org/. Click on the “Download TWiki-5.0.1” button to the right. Input the info requested in the download form on the right half and click on the Download button. You will download a zip archive named “TWiki-5.0.1.zip”.
  3. Put the archive file onto your Linux server. As root user, unzip it to a “twiki” directory under the secure web rot directory “htdocs-ssl” and adjust the permissions so the Apache user can access it:
    unzip TWiki-5.0.1.zip -d /srv/www/htdocs-ssl/twiki
    chown -R wwwrun:www /srv/www/htdocs-ssl/twiki
  4. Start configuring TWiki by creating a “LocalLib.cfg” file:
    cd /srv/www/htdocs-ssl/twiki/bin
    cp LocalLib.cfg.txt LocalLib.cfg

    Edit the resulting “LocalLib.cfg” file and update the variable “$twikiLibPath” to be the correct path:

    $twikiLibPath = "/srv/www/htdocs-ssl/twiki/lib"
  5. Configure Apache by creating a “/etc/apache2/twiki.conf” file with the content below. I generated it using TWiki:TWiki.ApacheConfigGenerator and cleaned it up. (For security reasons, we are putting twiki.conf under “/etc/apache2” instead of “/etc/apache2/conf” to prevent the TWiki Directory directives from being applicable to non-secure HTTP access.)
    # Prevent TWiki from including its own topics as URLs (used by DOS attacks).
    BrowserMatchNoCase ^$ blockAccess

    # ScriptAlias defines bin as a directory where CGI scripts are allowed.
    ScriptAlias /twiki/bin "/srv/www/htdocs-ssl/twiki/bin"

    # Alias defines pub directory as the root of file attachments.
    Alias /twiki/pub "/srv/www/htdocs-ssl/twiki/pub"

    # Secure file attachments by using viewfile which enforces permission
    RewriteEngine on
    RewriteCond %{REQUEST_URI} !^/+twiki/+pub/+(TWiki|Sandbox)/+.+
    RewriteRule ^/+twiki/+pub/+(.*)$  /twiki/bin/viewfile/$1 [L,PT]

    # Block access to typical spam related attachments
    SetEnvIf Request_URI "twiki/pub/.*\.[hH][tT][mM][lL]?$" blockAccess
    SetEnvIf Request_URI "twiki/pub/TWiki/.*\.[hH][tT][mM][lL]?$" !blockAccess

    # Allow everyone to run perl scripts from the bin directory.
    <Directory "/srv/www/htdocs-ssl/twiki/bin">
      AllowOverride None
      Order Allow,Deny
      Allow from all
      Deny from env=blockAccess

      Options ExecCGI FollowSymLinks
      SetHandler cgi-script

      # Password file for TWiki users
      AuthUserFile /srv/www/htdocs-ssl/twiki/data/.htpasswd
      AuthName 'Enter your login name:'
      AuthType Basic

      # File to return on access control error (e.g. wrong password)
      ErrorDocument 401 /twiki/bin/view/TWiki/TWikiRegistration

      # Limit access to configure script to localhost since it contains sensitive info.
      <FilesMatch "^(configure)$">
         SetHandler cgi-script
         Order Deny,Allow
         Deny from all
         Allow from localhost
      </FilesMatch>
    </Directory>

    # Allow access to the pub directory for attachments, CSS stylesheets and icons.
    <Directory "/srv/www/htdocs-ssl/twiki/pub">
      Options None
      AllowOverride None
      Order Allow,Deny
      Allow from all
      Deny from env=blockAccess

      # Disable execusion of PHP scripts
      php_admin_flag engine off

      # This line will redefine the mime type for the most common types of scripts
      AddType text/plain .shtml .php .php3 .phtml .phtm .pl .py .cgi
    </Directory>

    # With exception of bin and pub directories, prevent access to everything else.
    <Directory "/srv/www/htdocs-ssl/twiki/">
      Deny from all
    </Directory>

    # Either of this will redirect root / to twiki/bin/view
    #RewriteRule ^/$ /twiki/bin/view
    #RedirectMatch ^/$ /twiki/bin/view

    If you can’t run a browser under localhost, then make sure to comment out the “<FilesMatch “^(configure)$”>” block above so you can run the configure script remotely. If you want to redirect from the root URL to TWiki, just uncomment either “RewriteRule” or “RedirectMatch” at the end; don’t uncomment both because I’m not sure what would happen.

  6. To allow access to the TWiki only from SSL/HTTPS, we will include the twiki.conf into the SSL virtual host configuration. Edit the “/etc/apache2/vhost.d/your_vhost-ssl.conf” file (which you created in this post) and add the following Include directive anywhere inside the “<VirtualHost>” block:
    <VirtualHost _default_:443>
         ...
         Include /etc/apache2/twiki.conf
         ...
    </VirtualHost>
  7. The twiki.conf uses the mod_redirect module which we will need to configure Apache to load on startup. Good thing we have to restart Apache for the Twiki.conf to take effect also.
    a2enmod redirect
    rcapache2 restart
  8. Run the Twiki configure script by browsing to “https://localhost/twiki/bin/configure” or equivalent. Ignore the warning about the missing “/srv/www/htdocs-ssl/twiki/lib/LocalSite.cfg” configuration file. You will create it by running the configure script this first time.
    • Input your new administrative password and click Configure button.
    • Click on “General path settings” to expand it:
      • Change the “{DefaultUrlHost}” to match your website’s domain URL.
      • Input “https://localhost” into “{PermittedRedirectHostUrls}” so you can access Twiki from a local browser.
      • Verify that the rest are correct (they should be) and click on Next.
      • Click on Save button, click on “Return to configuration” link, and enter your admin password again.
    • You will see three sections with warnings. We’ll address a couple of those warnings below, but not all. It’s okay to run TWiki with some warnings.
    • Click on “Security setup”.
      • Check “{Register}{AllowLoginName}” if you wish to allow the use of a login ID instead of WikiName.
      • I left the “{Register}{NeedVerification}” unchecked because I haven’t set up SMTP yet. This is okay because once we complete securing the TWiki, only logged-in users will be able to register new users.
      • You might want to increase the “{MinPasswordLength}” to 4 from the default 1 character.
      • You will definitely want to uncheck the “{CryptToken}{Enable}” option because it will cause a browser back action to prevent all Edits and Previews from succeeding in that session. While, I applaud the intent, this feature is flawed. When you preview a page, to re-edit it, you have to hit the Back browser button, and then if you attempt to save, CryptToken will prevent you from doing so. And once this happens, any page you attempt to edit and save will fail. (If you plan never to use Preview or use the browser back button, then you can leave this option on.)
    • Click on “Mail and Proxies”.
      • Uncheck the “{EnableEmail}” option since SMTP wouldn’t work anyhow.
      • Click Next and Save.
  9. Browse to the main TWiki page at https://localhost/twiki/bin/view. You will see a nice congratulations message.
  10. Click on the Registration link under “Main Web Utilities” to register a new user.
    • Just fill in the required info. Once you click Submit, your user will be created and logged into Twiki automatically.
    • Click on the TwikiUsers link on the resulting page.
    • If you want to create another user, click on the TWikiRegistration link and repeat as necessary.
    • Once you are done and back on the TWikiUsers page, log out by clicking on the “Account” menu to the top-right and selecting “Log out”.
  11. For the following, you will need to log in as the administrator.
    • Go to the “Account” menu and select “Log in”. Input “admin” as the username and your administrative password.
    • Click on TWikiUsers and then TWikiGroups after “Related topics”.
    • Creating a new non-admin user group by inputting “TWikiUserGroup” into the “New Group” field and clicking on Add button. Add the WikiNames for non-administrative users to the “Set GROUP =” property. Click on the Save button.
    • Go back to TWikiGroups and click on TWikiAdminGroup to add your user as an administrator. Edit, add your WikiName to “Set GROUP =”, and Save.
    • At the bottom of the resulting page, click on TWikiAdminGroup to add your new user to the administrator group.
    • Now that we have groups and users configured, let’s restrict access to the TWiki.
      • Click on the TWikiAccessControl at the bottom.
      • Scroll down to the “Permissions settings of the webs on this TWiki site” section.
      • Click on the wrench icon before “Main” to edit the Main page permissions.
      • Edit the page and set the following to restrict access to the admin group and our user group.
        Set ALLOWWEBVIEW = %USERSWEB%.TWikiAdminGroup, %USERSWEB%.TWikiUserGroup
        Set ALLOWWEBCHANGE = %USERSWEB%.TWikiAdminGroup, %USERSWEB%.TWikiUserGroup,
                             TWikiRegistrationAgent
        Set ALLOWWEBRENAME = %USERSWEB%.TWikiAdminGroup, %USERSWEB%.TWikiUserGroup

        Note: TWikiRegistrationAgent belongs on the same line as %USERSWEB%.TWikiUserGroup.

        It is necessary to allow the TWikiRegistrationAgent to change Main.TWikiUsers to enable new user registration.

      • Save the page.
      • Go back to TWikiAccessControl (link at bottom) and repeat the above access restrictions (without TWikiRegistrationAgent) by clicking on the wrench icon before the “TWiki” link right under “Main” and changing the following:
        Set ALLOWWEBVIEW =  %USERSWEB%.TWikiAdminGroup, %USERSWEB%.TWikiUserGroup
        Set ALLOWWEBCHANGE =  %USERSWEB%.TWikiAdminGroup, %USERSWEB%.TWikiUserGroup
        Set ALLOWWEBRENAME =  %USERSWEB%.TWikiAdminGroup, %USERSWEB%.TWikiUserGroup
      • I disable the “SandBox” instead of setting permissions on it. You can do otherwise.
        Set SITEMAPLIST = off
    • Log out.
  12. Browse to the main TWiki page. You will see a mandatory login form.
  13. Because email was not set up, none of the users have gotten an email containing their randomly generated passwords. To fix this, do the following:
    • Edit the “/srv/www/htdocs-ssl/twiki/data/.htpasswd” file.
      • For each user line, blank out the password by deleting the random character string (encrypted password) between the first colon and second colon.
      • Save the file. Users that you have modified above will now have blank passwords.
    • Ask the users to log in with blank passwords and set their new passwords by doing the following:
      • Click on their name under the top-right Accounts menu.
      • Click on the ChangePassword link at the bottom to set their passwords.
  14. That’s it. Hope that you were able to get it working.

Ease of Use Items:

  • I don’t like the automatic CamelCase or WikiWord linking that TWiki has enabled by default. If I want a link, I will specify so using the square brackets. If you feel the same way, here is how you can disable this feature:
    1. Log into TWiki as a user with administrative privileges or as the default “admin” user.
    2. Click on the “Web Preferences” link on the right navigation table or at the bottom.
    3. Edit the “Web Preferences” page and add the following under “Web settings” section:
      * Set NOAUTOLINK = on
      * Set HIDE_NON_WIKI_WORD_WARNINGS = on
  • The default way to go back to the parent page in TWiki is to hit the browser back button (which breaks CryptToken) or by clicking on the “Backlinks” link at the bottom (too many clicks). I love breadcrumbs and we can add a plugin to TWiki to support this function:
    1. Run the TWiki configure script (https://localhost/twiki/bin/configure). Enter your admin password.
    2. Click on “Extensions” and “Find More Extensions”. Enter your admin password.
    3. Find BreadCrumbsPlugin and click on its “Install” link to the far right. Enter your admin password.
    4. On my system, I got a weird Perl error. If you got the same, we have to install manually by doing the following:
      1. SSH into the linux server.
      2. Change directory to the TWiki installation root directory: “cd /srv/www/htdocs-ssl/twiki”
      3. There should be a script named “BreadCrumbsPlugin_installer” there. Execute it by running “Perl BreadCrumbsPlugin_installer”.
      4. Answer Yes to the re-install module prompt. The installation should complete successfully.
    5. Re-run the TWiki configure script (https://localhost/twiki/bin/configure). Enter your admin password.
    6. Go to “Plugins” and check the “{Plugins}{BreadcrumbsPlugin}{Enabled}” box. Save the change.
    7. Log into the TWiki and edit the “Web Preferences” page to add the following under “Web settings” section:
      * Set BREADCRUMBSPLUGIN_RECORDTRAIL = on
    8. In your wiki pages, add the following “%BREADCRUMBS%” variable at the top and when you view the page, it will be rendered as breadcrumb links.

Some info above derived from:

No Comments

Add Tomcat to the OpenSUSE LAMP Development Server

Linux No Comments

tomcatSome developers needed Java JSP and Servlet support added to our LAMP development server on OpenSUSE 11.3. To do so, we decided to use Tomcat. Follow the instructions below to install Tomcat and the Apache JK Module to integrate Apache with Tomcat.

Install Tomcat 6

  1. As root user, run YaST –> Software –> Software Management. Click on the Search tab.
    • Let’s double-check that the Java SDK is installed already by inputting “jdk” into the search box and clicking on the Search button. You should see that “java-1_6_0-openjdk” and “java-1_6_0-openjdk-plugin” are already checked.
    • Input “tomcat” into the search box and click on the Search button.
    • Check “tomcat” and a bunch of the other entries will get automatically checked as dependencies.
    • Check “tomcat6-webapps” to install the tomcat webapp examples which we will use for testing below.
    • Click on the Accept button at the bottom-right to commit the changes made. YaST will exit once the installation completes.
  2. Strangely, the Tomcat installation might not set some needed permissions on a few tomcat-related directories. Run the following commands to set the missing permissions:
    chmod g+w /var/log/tomcat6
    chgrp tomcat /etc/tomcat6/Catalina/localhost
    chmod g+w /etc/tomcat6/Catalina/localhost
    chmod -R g+w /var/cache/tomcat6

    Double-check that the resulting directories above have “tomcat” as group and that the group write permission is set:

    ls -l /var/log | grep tomcat6
    ls -l /etc/tomcat6/Catalina | grep localhost
    ls -l /var/cache | grep tomcat6

    If you have this issue and don’t run the above commands, you will see “Permission Denied” errors in the “/var/log/tomcat6/catalina.out” log file later.

  3. Some useful info and commands for Tomcat:
    • Service Commands: rctomcat6 start/stop/restart
    • Configuration Location: /etc/tomcat6
    • Logs Location: /var/log/tomcat6
    • Webapps Location: /srv/tomcat6/webapps/
    • Workspace Cache Location: /var/cache/tomcat6
  4. Configure Tomcat to start on bootup by running this command:
    insserv tomcat6
  5. To test the installation, run Tomcat with “rctomcat6 start” and browse to http://localhost:8080/.

Install Apache JK Module

  1. Download a pre-built Apache JK Module for OpenSUSE 11.3. Click on the “Select Mirror” link in the middle and then click on the “binary package” link at the bottom of the page.
  2. Install the downloaded “apache2-mod_jk-1.2.26-6.2.x86_64.rpm” file:
    rpm -ivh apache2-mod_jk-1.2.26-6.2.x86_64.rpm

    This will install to the “/usr/share/doc/packages/apache2-mod_jk” directory and place “mod_jk.so” into Apache’s installation directory at “/usr/lib64/apache2”.

  3. Create an “/etc/tomcat6/worker.properties” file for Apache to define a worker process to connect to Tomcat’s ajp13 handler port (which is enabled by default in “/etc/tomcat6/server.xml” and uses port 8009). I don’t recommend copying from the “/usr/share/doc/packages/apache2-mod_jk/worker.properties” example because it is very out-of-date. Instead, create a “/etc/tomcat6/worker.properties” file with the content below:
    # An ajp13 worker that connects to localhost:8009
    worker.list=ajp13

    # ajp13 worker definition
    worker.ajp13.port=8009
    worker.ajp13.host=localhost
    worker.ajp13.type=ajp13
  4. Create an “/etc/apache2/conf.d/jk.conf” file to configure the Apache JK Module. I suggest copying the “/usr/share/doc/packages/apache2-mod_jk/jk.conf” example to “/etc/apache2/conf.d/jk.conf” and editing the content to match the below:
    # simple configuration for apache (for AJP connector, modul mod_jk.so)
    <IfModule mod_jk.c>
       JkShmFile /var/log/apache2/jk-runtime-status
       JkWorkersFile /etc/tomcat6/workers.properties
       JkLogFile /var/log/apache2/mod_jk.log

       # Log level to be used by mod_jk
       JkLogLevel error

       # The following line makes apache aware of the location of the /examples context
       Alias /examples "/srv/tomcat6/webapps/examples"
       <Directory "/srv/tomcat6/webapps/examples">
           Options Indexes FollowSymLinks
           allow from all
       </Directory>

       # The mounts all JSP files and /servlet/ uri under /examples to be handled by ajp13 tomcat
       JkMount /examples/* ajp13

       # The following line prohibits users from directly accessing WEB-INF
       <Location "/examples/WEB-INF/">
           deny from all
       </Location>
    </IfModule>
  5. Configure Apache to load the JK module:
    a2enmod jk
    a2enmod -l

    The “a2enmod jk” command will add the “jk” module to the list of Apache’s APACHE_MODULES configuration parameter. (This configuration parameter can also be set using YaST –> System –> /etc/sysconfig Editor –> Network –> WWW –> Apache2 –> APACHE_MODULES.)

  6. Restart Tomcat and Apache:
    rctomcat6 restart
    rcapache2 restart
  7. To test the installation, browse to http://localhost/examples/. Try executing the servlets and JSP examples. (Strangely, I was unable to execute two JSP examples, “Basic Arithmetic” and “Functions”, without errors.)
  8. If you encounter errors, check out the “/var/log/tomcat6/catalina.out”, “var/log/apache2/error_log”, and “/var/log/apache2/mod_jk.log” log files. You can increase the amount of info written to “/var/log/apache2/mod_jk.log” by editing “/etc/apache2/conf.d/jk.conf” to set “JkLogLevel info” and restarting Apache.

Some info above derived from Apache2.2 / Tomcat6 / mod_jk / Suse 11.1.

No Comments

Setup a Secured OpenSUSE Linux LAMP Development Server

Linux No Comments

opensusesecuredRecently, I had to setup a small development server for a team of 4-5 developers. The server needed to be accessible from the Internet and thus, needed to be secured. The server would use only free software. The server needed to provide the following development services: MySQL, Apache HTTP/HTTPS, PHP, Subversion, and SSH. For security, we will enable HTTPS/SSL on Apache and require that subversion be accessed through HTTPS.

The following are notes that I took when setting up such a server. They are not 100% comprehensive; hopefully the parts I missed are very obvious or set to acceptable defaults. I’ve indicated the specific versions of the software that I downloaded; it should be okay if you get newer versions.

Download OpenSUSE 11.3

There are many flavors of Linux out there. I just chose OpenSUSE because I am most familiar with the commercial SUSE Linux product at work. If you decide to use a different flavor such as Ubuntu or Red Hat, the Linux commands in this blog may need to be adjusted. In particular, the OpenSUSE installation program, YaST, is probably not available on other flavors.

Download the OpenSUSE distribution as an ISO image file (ex: “openSUSE-11.3-DVD-x86_64.iso”). I chose 64bit because my machine is 64bit capable. Most modern desktops and servers will support 64bit and it is recommended that you go with 64bit so your server can use more memory than 4GB.

If you are not using VMware, burn the OpenSUSE ISO image file to a DVD. Stick that DVD into your dedicated server machine and boot it up to install OpenSUSE.

Install VMware Player 3.1.3

Note: If you have a dedicated server or desktop to run OpenSUSE, you can skip this section.

Because I don’t have a dedicated machine for the Linux server, I will be using VMware Player to host it on my Windows 7 64bit machine. There are two free flavors of VMware virtual software, VMware Player and VMware Server. VMware Server is optimized for input/output (good for servers), will install as a Windows service, and thus appears to be the best choice for a Linux server. Unfortunately, from what I could find on the net, VMware Server will be end-of-life’d as of this year. So I decided to go with VMware Player.

  1. Download and install the VMware Player. You will need to create a free account with VMware to do the download.
  2. Run the VMware Player and click on “Create a New Virtual Machine”.
  3. Select “Installer disc image file (iso)” and browse to the OpenSUSE ISO image file you downloaded above. Click Next.
  4. Input a default username and password. Note that the password will also be used as the root user password. Click Next.
  5. Name your virtual machine and keep the default location or change it. Click Next.
  6. Take the default of 20GB or increase it. Leave the “Store virtual disk as a single file” selected. Click Next. (Note: It is very difficult to increase the size of this virtual disk later!)
  7. Click on “Customize Hardware”. I recommend increasing Memory to at least 1GB. Because the server will be accessible externally, I set the Network Adapter to be “Bridged: Connected directly to the physical network”. Leave the “Replicate physical network connection state” unchecked. Click Ok.
  8. Double-check the settings. Click Finish.
  9. VMWare will create the virtual machine, start it, and boot from the OpenSUSE ISO image.

Install OpenSUSE 11.3

There isn’t much to say about this. The OpenSUSE installation was totally hands-free. (Kudos to the OpenSUSE development team!) The installer will reboot into OpenSUSE when the installation is complete. You should see a nice green login screen.

Use YaST to Install Apache and PHP

YaST makes finding and installing software very easy. Even better, YaST will take care of software package dependencies and will configure installed packages to work with each other. However, you do give up some control in order to use YaST. At first, I was uneasy because I didn’t know where YaST installed everything. As I got more familiar with YaST, I started liking how it embedded binaries into the OS (/usr/bin or /usr/sbin) and consolidated configuration files (/etc). And I didn’t have to edit as many configuration files as when I had installed without YaST.

  1. Log into OpenSUSE as the root user.
  2. Click on the green OpenSUSE icon on the bottom-left, input “yast” into the Search box, and click on the found YaST program to run it.
  3. The “Software” category is pre-selected. On the right, click on “Software Management”.
  4. Click on the Search tab.
    • Search for “apache”. Check “apache2” (Apache HTTP/S Server), “apache2-mod_php5” (Apache PHP5 Module), and “subversion-server” (Apache Subversion Module) in the search results. YaST will automatically check the must-have dependencies.
    • Search for “php” and you will noticed that YaST has pre-selected “php5” and other items as a dependency of “apache2-mod_php5”. In addition, check “php5-mcrypt” (required for apps like PhpMyAdmin), “php5-mysql” (PHP MySQL library), and “php5-pear” (very useful for installing PHP extensions).
    • OpenSUSE pre-installs MySQL, Subversion, and SSH. To double-check, you can search for “mysql”, “subversion”, and “ssh” to see that the related “mysql-community-server”, “subversion”, and “openssh” packages are already installed (green check with black background) along with their dependencies.
  5. Click on the Accept button and then the Continue button to start the installation.
  6. You may prompted to insert the OpenSUSE DVD.
    • If you are using a dedicated machine and still have the OpenSUSE DVD in the DVD drive, you shouldn’t get this prompt. Otherwise, just insert the OpenSUSE DVD.
    • If you are using VMware, you will need to re-mount the OpenSUSE ISO image by clicking on the active CD icon at the botom of the VMware window, selecting Settings, selecting “Use ISO image file”, browsing to the OpenSUSE ISO image file, and clicking on OK.
    • Click on the Retry button to have YaST retry the DVD access.
  7. The Software Management dialog will close once everything is installed.
  8. Exit the YaST program.

Here is a quick reference for the programs installed on OpenSUSE that we are interested in:

  1. MySQL
    • Service: rcmysql start/restart/stop/status (alternatively, “service mysql start/…”);
    • Binary: /usr/bin/mysql, /usr/bin/mysqld, /usr/bin/mysql_safe, …
    • Config: /etc/my.cnf, /etc/mysqlaccess.conf
    • Logs: /var/log/mysql
  2. Apache HTTP/S Server
    • Service: rcapache2 start/startssl/restart/stop/status (alternatively, “service apache2 start/…”)
    • Binary: /usr/sbin/httpd2-prefork
    • Config: /etc/apache2/httpd.conf, /etc/sysconfig/apache2
    • Logs: /var/log/apache
    • Document Root: /srv/www/htdocs
  3. PHP
    • Binary: /usr/bin/php
    • Config: /etc/php5/apache, /etc/php5/cli
    • Apache Config: /etc/apache2/conf.d/php5.conf
  4. Subversion
    • Binary: /usr/bin/svn
    • Apache Config: /etc/apache2/conf.d/subversion.conf
    • Note: /usr/bin/svnserve is a small, standalone Subversion server. There is no need to run svnserve as subversion access will be provided through Apache.
  5. SSH
    • Service: rcsshd start/restart/stop (alternatively, “service sshd start/…”)
    • Binary: /usr/bin/ssh, usr/sbin/sshd
    • Config: /etc/ssh_config, /etc/sshd_config

Test the Installation (HTTP and PHP)

Let’s run some test to ensure that everything is installed correctly. Log in as root, run Terminal, and input the following commands:

  • Test MySQL:
    rcmysql status
    rcmysql start
    mysql -u root -p
    mysql> show databases;
    mysql> use mysql;
    mysql> show tables;
    mysql> quit
  • Test Apache:
    rcapache2 status
    rcapache2 start
  • Create index.html and phpinfo.php:
    echo "<html><body><h3>Hello</h3></body></html>" > /srv/www/htdocs/index.html
    cat > /srv/www/htdocs/phpinfo.php << EOL
    > <?php phpinfo(); ?>
    > EOL
  • Browse to http://localhost/ to test HTTP and http://host/phpinfo.php to test PHP.

Configure Subversion on Apache

  1. Install apache modules to enable subversion (svn) by running these commands as the root user:
    a2enmod dav
    a2enmod dav_svn
    a2enmod -l

    The last command “a2enmod -l” will list the configured apache modules to run and you should see “dav” and “dav_svn” listed. Later on, after you restart Apache, you can run “httpd2 -M” to see the actual modules loaded by Apache.

  2. Edit “/etc/apache2/conf.d/subversion.conf” and add the following right after “<IfModule mod_dav_svn.c>” and before “</IfModule>”:
    <Location /repos>
      DAV svn
      SVNPath /srv/svn/repos/

      # Limit write permission to list of valid users.
      <LimitExcept GET PROPFIND OPTIONS REPORT>
        # Require SSL connection for password protection.
        # SSLRequireSSL

        AuthType Basic
        AuthName "Authorization Realm"
        # path to password file
        AuthUserFile /srv/svn/user_access/passwd
        Require valid-user
      </LimitExcept>
    </Location>

    (Note: Use SVNParentPath instead of SVNPath if you want to have multiple repositories under “/srv/svn/repos/” without having to modify the subversion.conf file for each.)

  3. Create the repository at “/srv/svn/repos” directory to match what is in subversion.conf:
    mkdir -p /srv/svn/repos
    svnadmin create /srv/svn/repos
    chown -R wwwrun:www /srv/svn/repos

    The reason to run the last “chown” command is so that the Apache user (“wwwrun”) can access the repository directory and its contents. Otherwise, you will get permission denied errors when running Subversion commands against the repository.

  4. Create a Subversion password file “/srv/svn/user_access/passwd” (to match what is in subversion.conf) and add the first user:
    mkdir -p /srv/svn/user_access
    htpasswd2 -mc /srv/svn/user_access/passwd <username>

    Replace “<username>” with the username of your first Subversion user. You will be prompted to input a password for that user. To create additional users at any time, run this command:

    htpasswd2 -m /srv/svn/user_access/passwd <username2>

    Note: The “htpasswd2” command for adding subsequent users does not include the “-c” flag. Be careful because the “-c” flag will re-create the password file and you will lose all pre-existing Subversion users!

  5. Restart Apache so that all the changes will take effect.
    rcapache2 restart
  6. Test Subversion by browsing to http://localhost/repos/.
  7. You can import an existing project directory into Subversion and then check it back out by running the following commands:
    svn import ./project http://localhost/repos/project --username <username>
    svn co http://localhost/repos/project ./project_test

    You will need to specify your “<username>” in the first Subversion command. Once you do so, Subversion will remember the username and you will not need to include it in subsequent Subversion commands.

Configure SSL on Apache

To get SSL (aka HTTPS) working on the Apache HTTP/S Server, we will need to install a certificate for our server. Instead of paying for an official certificate from companies like VeriSign, I decided to generate a self-signed root CA (Certifcate Authority) certifcate and server certificate (signed by that root CA).

  1. Create the certificates using the provided OpenSUSE “mkcert.sh” script. Note that you must run the “mkcert.sh” script from its directory in order for everything to work properly.
    cd /usr/share/doc/packages/apache2
    ./mkcert.sh make --no-print-directory /usr/bin/openssl /usr/sbin/ custom

    The script will prompt you with a bunch of selections:

    • Note: If you want to leave a field blank below, just input “.”. Unless otherwise stated, just take the default selection.
    • For section “STEP 2: Generating X.509 certificate signing request for CA [ca.csr]”:
      • Enter “US” (United States) for “Country Name”.
      • Enter the full state name for “State or Province Name” (ex: “California”).
      • Enter the full city name for “Locality Name” (ex: “Los Angeles”).
      • Enter the full company name for “Organization Name” (ex: “Snake Oil Company”).
      • Take the default “Certificate Authority” for “Organization Unit Name”.
      • Enter the full company name with “CA” (for Certificate Authority) at the end for “Common Name” (ex: “Snake Oil Company CA”).
      • Enter an email address (ex: “admin@snakeoil.com”).
    • For section “STEP 5: Generating X.509 certificate signing request for SERVER [server.csr]”:
      • Except for “Common Name”, repeat the inputs from STEP 2 for “Country Name”, “Start or Province Name”, etc.,
      • For “Common Name”, input the fully-qualified domain name for your server (ex: “www.snakeoil.com”).
    • For section “STEP 7: Enrypting RSA private key of CA with a pass phrase for security [ca.key]”:
      • Answer Y for yes and input a password.
      • Note: We want a password because we will be distributing the root CA certificate so users can manually install it into the browser as a trusted root CA certificate (which is used to automatically trust websites signed by it).
    • For section “STEP 8: Enrypting RSA private key of SERVER with a pass phrase for security [server.key]”:
      • Answer N to avoid inputting a password.
      • Note: If you input a password for the server key, you will need to input this password every time you start Apache. There is really no need for a password because we will not be distributing this key.
    • You should get a success message. Ignore the text about where the certificates are stored. The certificates are actually stored in the following locations where Apache can make use of them:
      /etc/apache2/ssl.key/ca.key (CA RSA Private Key 1024bit; encrypted with password)
      /etc/apache2/ssl.crt/ca.crt (CA X.509 Certificate Signed by itself)        
      /etc/apache2/ssl.key/server.key (Server RSA Private key 1024bit, not encrypted with password)
      /etc/apache2/ssl.crt/server.crt (Server X.509 Certifcate Signed by CA)

      (These certificates are valid for one year.)

  2. Copy the root CA certificate (“ca.crt”) to the non-SSL document root so that users can download and add it as a trusted root CA certifcate to their browser.
    cp /etc/apache2/ssl.crt/ca.crt /srv/www/htdocs/ca.crt
  3. We need to create a virtual host for the HTTPS port 443:
    • Make a copy of “/etc/apache2/vhosts.d/vhost-ssl.template” in the same directory and name it something like “your_vhost-ssl.conf” (ex: “snakeoil-ssl.conf”). You can name the file to whatever you want; you just need to keep the “.conf” extension.
    • Edit “/etc/apache2/vhosts.d/your_vhost-ssl.conf” to make the following changes.
    • Uncomment the “ServerName” and “ServerAdmin” entries. Please replace the “www.snakeoil.com” and “admin@snakeoil.com” entries below with your server’s hostname (this should match what you inputted as the “Common Name” in the server certificate) and email address.
      DocumentRoot "/srv/www/htdocs-ssl"
      ServerName www.yourhostname.com
      ServerAdmin admin@yourhostname.com
      ErrorLog /var/log/apache2/ssl_error_log
      TransferLog /var/log/apache2/ssl_access_log
    • Uncomment “#SSLCertificateChainFile /etc/apache2/ssl.crt/ca.crt” by removing the “#” pound character. Add the following line: “SSLCACertificateFile /etc/apache2/ssl.crt/ca.crt”. Also, make sure “SSLCertificateFile” and “SSLCertificateKeyFile” are set. You should end up with the following:
      SSLCertificateChainFile /etc/apache2/ssl.crt/ca.crt
      SSLCACertificateFile /etc/apache2/ssl.crt/ca.crt
      SSLCertificateFile /etc/apache2/ssl.crt/server.crt
      SSLCertificateKeyFile /etc/apache2/ssl.key/server.key

      The first line will add our self-signed root CA certifcate into the server certificate’s authorization chain. The second line will identify our self-signed root CA certificate as the server certificate’s root CA. The third and four line identifies the server certificate that Apache HTTPS should use.

    • Because we are not re-using the “/srv/www/htdocs” directory as a parent for our vhost directory, we need to define the access options for the “/src/www/htdocs-ssl” directory. Add the following near the bottom of the “<VirtualHost>” definition before “</VirtualHost>”. Look for the existing “<Directory “/src/www/cgi-bin”> … </Directory>” section and add the following right after it:
      <Directory "/srv/www/htdocs-ssl">
        Options None
        AllowOverride None
        Order allow,deny
        Allow from all
      </Directory>
  4. The apache “ssl” module should already be installed. Run the “a2enmod -l” command and check that “ssl” is listed.
  5. Create the vhost document root directory and add some test files to it:
    mkdir -p /srv/www/htdocs-ssl
    echo "<html><body><h3>Encrypted</h3></body></html>" > /srv/www/htdocs-ssl/index.html
    cp /srv/www/htdocs/phpinfo.php /srv/www/htdocs-ssl/phpinfo.php
  6. Restart Apache to have the SSL changes take effect. Unfortunately, if you restart using “rcapache2 restart”, SSL won’t work!
    • The problem is that to enable SSL, you need to run Apache with the SSL flag set. The way to do that is to stop Apache with “rcapache2 stop” and then start Apache with the special “rcapache2 startssl” command.
    • To configure “rcapache2 start/restart” to run with the SSL flag (like with “rcapache2 startssl”), run the following command:
      a2enflag SSL

      This will modify the “/etc/sysconfig/apache2” file to add “SSL” to the “APACHE_SERVER_FLAGS” variable to be:

      APACHE_SERVER_FLAGS="SSL"

      After you make this change, just run “rcapache2 restart” like normal. (Alternatively, you can run YaST to set “SSL” in System –> /etc/sysconfig Editor –> Network –> WWW –> Apache2 –> APACHE_SERVER_FLAGS.)

  7. Test the Apache SSL support:
    • Browse to “http://www.yourhostname.com/ca.crt” (replace “yourhostname” with your server’s hostname) to download the root CA certificate. On Firefox, select the “Trust this CA to identify web sites” option and click the OK button.
    • Browse to “https://www.yourhostname.com/” to make sure HTML works under SSL.
    • Browse to “https://www.yourhostname.com/phpinfo.php” to make sure PHP works under SSL.
    • Browse to “https://www.yourhostname.com/repos/” to make sure Subversion works under SSL.
  8. If you run into trouble, here are some troubleshooting tools:
    • To view the open ports, run “netstat -vatn”. You should see port 443 (the default HTTPS port) listed.
    • To view the virtual host configuration, run “httpd2 -D SSL -S”.
    • To test using an SSL client, run “openssl s_client -connect localhost:443”.

Secure Subversion

Now that we know subversion works under SSL, let’s secure Subversion so it will only work under HTTPS/SSL. This is very simple to do. Edit “/etc/apache2/conf.d/subversion.conf” and uncomment the “#SSLRequireSSL” option. In addition, comment out or delete the “<LimitExcept>” and “</LimitExcept>” lines (just the two lines, not the content between them) to force the Subversion user to provide the password for all actions including viewing the repository. The result should look like:

<Location /repos>
  DAV svn
  SVNPath /srv/svn/repos/

  # Limit write permission to list of valid users.
  #<LimitExcept GET PROPFIND OPTIONS REPORT>
    # Require SSL connection for password protection.
    SSLRequireSSL

    AuthType Basic
    AuthName "Authorization Realm"
    # path to password file
    AuthUserFile /srv/svn/user_access/passwd
    Require valid-user
  #</LimitExcept>
</Location>

Configure SSH

Surprise! You don’t need to configure anything to get SSH working. You just need to start the SSH server with this command.

rcsshd start

Configure MySQL, Apache, and SSH to Start On Bootup

To configure MySQL and Apache to start at bootup, log in as root, run Terminal, and input the following commands:

insserv mysql
insserv apache2
insserv sshd

Alternatively, run YaST, go to System, and run “System Services (Runlevel)”. Select “apache2” and click on the Enable button. Do the same for “mysql” and “sshd”.

Miscellaneous

If Firefox on OpenSUSE can’t browse to certain sites, the issue might be caused by IPv6 being enabled by default. To disable IPv6:

  1. Browse to “about:config”.
  2. Input “IPv6” into the “filter” to search.
  3. Click on “network.dns.disableIPv6” once to enable; the Value should turn to “true”.

If the DNS resolution doesn’t seem work in every situation, you may need to manually configure the DNS servers. For example, you can “ping google.com” but you can’t run “telnet google.com 80” (or SSH and scp) without getting a “Could not resolve hostname” error. To set the DNS servers to use Google’s DNS servers:

  1. Run YaST –> Network Devices –> Network Settings –> Hostname/DNS tab.
  2. Input 8.8.8.8 into the “Name Server1” field and 8.8.4.4 into the “Name Server2” field.
  3. Click Ok to apply the changes.

To secure the MySQL database, you can run the provided “/usr/bin/mysql_secure_installation” script (I haven’t tried this yet). This script will perform tasks like setting the MySQL root password and disabling the remote root login.

Some info above derived from the following websites:

No Comments

« Previous Entries Next Entries »