Deploy an Application to the Remote Server

With Git prepared on both the local workstation and on the remote server, I can now deploy my application.

Defining a Remote Repository

In order to deploy an application from my development workstation to istarelworkshop.com, I need to configure the application repository on my workstation such that is can communicate with the repository on the production server.

Here is the current configuration for the Istarel Workshop application:

markf$ cd ~/Sites/iw
markf$ cat .git/config
[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
    ignorecase = true

Now I configure this repository with user and path information on the remote Git repository. (Note that the 1158 in the remote declaration is the port, for cases where ssh is not listening to its standard port 22.)

markf$ git remote add istarelworkshop 
       ssh://git@www.istarelworkshop.com:1158/var/git/iw
markf$ cat .git/config

If I look at the configuration for the local repository now, I see the definition for "istarelworkshop".

markf$ cat .git/config
[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
    ignorecase = true
[remote "istarelworkshop"]
    url = ssh://git@www.istarelworkshop.com:1158/var/git/iw
    fetch = +refs/heads/*:refs/remotes/istarelworkshop/*

Cloning a Bare Repository

With the description of the remote repository done, I can now deploy the application.

markf$ git push istarelworkshop master

I am not done yet, though. The repositorities I set up on istarelworkshop.com are bare repositories; that is, they contain all the branches and history but are not a working repository. I need to clone that bare repository to the appropriate location on istarelworkshop.com. In an earlier article, I showed how to set up Apache2 virtual hosts. The first such host has its base directory at /var/www/istarelworkshop.com. I need to take the bare repository and clone it to that location.

markf$ ssh markf@www.istarelworkshop.com
iwuser$ cd /var/www
iwuser$ sudo git clone /var/git/iw istarelworkshop.com
iwuser$ sudo chown -R www-data:www-data istarelworkshop.com

Configure the Remote Application

Back when I set up the local repository, I made sure that certain key configuration files were not part of the repository. This is important because every server is different, and the key paths and identities used on my local workstation are quite different from the Ubuntu VPS I deployed. So, I need to create those configuration files on istarelworkshop.com.

iwuser$ sudo su - www-data
$ bash
www-data$ cd /var/www/istarelworkshop.com
www-data$ mkdir conf && cd conf
www-data$ vi ApplicationConstants.php

Listing: /var/www/istarelworkshop.com/conf/ApplicationConstants.php

<?php

# Fundamental Application Mode
define('IN_PRODUCTION', 1);             # 0 = Development, 1 = Production

# Application Directories
define('APPL_ROOT_DIR', '/');
define('APPL_RSRC_DIR', '/var/www/istarelworkshop.com/rsrc/');

# Istarel Workshop Frameworks Directory
if (! defined('FRAMEWORK_DIR'))
   define('FRAMEWORK_DIR', '/var/www/istarelworkshop.com/fw/');

# Supplemental Directories Required by Application Frameworks Classes
define('APPL_IMG_DIR', APPL_ROOT_DIR . 'img/');
define('APPL_LIB_DIR', APPL_ROOT_DIR . 'lib/');

# Define the Application Database attributes
define('DB_TYPE',       'pgsql');
define('DB_HOST',       'localhost');
define('DB_NAME',       'iw');
define('DB_USERNAME',   'iwdb');
define('DB_PASSWORD',   'secret');

?>

The application framework uses Apache's mod_rewrite system to power the Front Controller. I need to create an .htaccess file at the root of the repository to ensure that proper routing happens.

Listing: /var/www/istarelworkshop.com/.htaccess

RewriteEngine On
RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php

Install and Configure Dovecot

With Postfix installed, I can now install Dovecot, the Mail Delivery Agent that creates a POP3 and IMAP server, which allows users to download their email from the server.

Install and Test Dovecot

iwuser$ apt-get install dovecot-common

I need to configure Dovecot. There is a section that defines the socket to which to listen: That must be uncommented and updated to identify Postfix as the client.

iwuser$ sudo vi /etc/dovecot/dovecot.conf
socket listen {
   client {
      path = /var/spool/postfix/private/auth-client
      mode = 0660
      user = postfix
      group = postfix
   }
}
iwuser$ sudo /etc/init.d/dovecot restart

Before implementing the POP3 and IMAP servers, I want to test the Postfix installation with telnet.

iwuser$ sudo apt-get install telnet
iwuser$ telnet localhost 25
Trying 127.0.0.1...
Connected to istarel.
Escape character is '^]'.
220 istarel ESMTP Postfix (Ubuntu)
ehlo localhost
250-istarel
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
mail from: root@localhost
250 2.1.0 Ok
rcpt to: iwuser@localhost
250 2.1.5 Ok
data
354 End data with .
Subject: Ensuring Postfix is installed correctly

Hi, 
This is the test message...
.
250 2.0.0 Ok: queued as 8BCAE3819C
quit
221 2.0.0 Bye
Connection closed by foreign host.
You have new mail in /var/mail/iwuser

Update Postfix with Mailbox Configuration

Dovecot supports the popular maildir format for client mailboxes. The Postfix configuration file must be prepared with this in mind:

iwuser$ sudo postconf -e 'home_mailbox = Maildir/'
iwuser$ sudo postconf -e 'mailbox_command = '

Secure POP3 and IMAP

Dovecot supports four different protocols: POP3, Secure POP3, IMAP, and Secure IMAP. For Istarel Workshop, I am only considering the two secure protocols. The Dovecot configuration must be modified to show which protocols to support, and must be told where the SSL certificates are located (which I created when describing the Postfix installation and configuration).

iwuser$ sudo apt-get install dovecot-imapd dovecot-pop3d
iwuser$ sudo vi /etc/dovecot/dovecot.conf

protocols = pop3s imaps
ssl_disable = no
ssl_cert_file = /etc/ssl/certs/smtpd.crt
ssl_key_file = /etc/ssl/private/smtpd.key
ssl_key_password = secret
disable_plaintext_auth = no

iwuser$ sudo /etc/init.d/postfix restart
iwuser$ sudo /etc/init.d/dovecot restart

Email clients should now be able to connect via POP3 and IMAP to check and manage email.

There is only one housekeeping task left to perform: Though telnet is a convenient tool to verify a working implementation of Postfix and Dovecot, it is also horribly insecure, so I will remove it from the server.

iwuser$ sudo aptitude remove telnet

Install and Configure Postfix

A working email server has two essential components: a Mail Transfer Agent (MTA) and a Mail Delivery Agent. Postfix is a Mail Transfer Agent: It actually sends email from, and receives email to, the server.

Install Postfix

Installing Postfix is a bit curious. You install Postfix (accepting the default options) and then run a program to configure it (where you make a number of important choices).

iwuser$ sudo apt-get install postfix
iwuser$ sudo dpkg-reconfigure postfix
Mail server configuration type: Internet Site
System mail name: mail.istarelworkshop.com
Root and postmaster mail recipient: webmaster@istarelworkshop.com
Other destinations to accept mail for: mail.istarelworkshop.com, 
    istarelworkshop.com, localhost.localdomain, localhost
Force synchronous updates on mail queue? No
Local networks: 127.0.0.0/8
Mailbox size limit (bytes): 0
Local address extension character: +
Internet protocols to use: all

There are two key questions asked during the reconfiguration: the destinations being accepted for mail, and the local networks. For my server, the local network is a standard "127.0.0.0/8", which really means only 127.0.0.1 (the server itself). For a setup where the server is part of (say) an office network and acts as the mail gateway to the internet, the network parameter might look quite different. The destinations response seems to follow a common pattern: mail.mydomain.com, mydomain.com, localhost.localdomain, localhost.

Authentication Configuration

Those first steps took care of the initial configuration. I now want to define parameters needed by the Mail Delivery Agent (I will be using Dovecot), and prepare Postfix to use authentication. Postfix also provides a command line executable to modify its configuration file: /etc/postfix/main.cf.

iwuser$ sudo postconf -e 'smtpd_sasl_type = dovecot'
iwuser$ sudo postconf -e 'smtpd_sasl_path = private/auth-client'
iwuser$ sudo postconf -e 'smtpd_sasl_local_domain ='
iwuser$ sudo postconf -e 'smtpd_sasl_security_options = noanonymous'
iwuser$ sudo postconf -e 'broken_sasl_auth_clients = yes'
iwuser$ sudo postconf -e 'smtpd_sasl_auth_enable = yes'
iwuser$ sudo postconf -e 'smtpd_recipient_restrictions = permit_sasl_authenticated,
    permit_mynetworks,reject_unauth_destination'
iwuser$ sudo postconf -e 'inet_interfaces = all'

Create Digital Certificates

In order for secure authentication to work, there must be certificates to establish the identity of the mail server. Using openssl, you can create so-called self-signed certificates. For email, this is perfectly acceptable.

iwuser$ sudo openssl genrsa -des3 -rand /etc/hosts -out smtpd.key 1024
Enter pass phrase for smtpd.key: secret
Verifying - Enter pass phrase for smtpd.key: secret

iwuser$ chmod 600 smtpd.key
iwuser$ openssl req -new -key smtpd.key -out smtpd.csr
Enter pass phrase for smtpd.key: secret
Country Name (2 letter code) [AU]: US
State or Province Name (full name) [Some-State]: Georgia
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]: Istarel Workshop LLC
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:
Email Address []:
A challenge password []: another secret
An optional company name []: Istarel Workshop LLC

iwuser$ sudo openssl x509 -req -days 365 -in smtpd.csr 
    -signkey smtpd.key -out smtpd.crt
Enter pass phrase for smtpd.key: secret

iwuser$ openssl rsa -in smtpd.key -out smtpd.key.unencrypted
Enter pass phrase for smtpd.key: secret
Enter PEM pass phrase: secret
Verifying - Enter PEM pass phrase: secret
Country Name (2 letter code) [AU]: US
State or Province Name (full name) [Some-State]: Georgia
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]: Istarel Workshop LLC
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:
Email Address []:

iwuser$ sudo mv smtpd.key /etc/ssl/private/
iwuser$ sudo mv smtpd.crt /etc/ssl/certs/
iwuser$ sudo mv cakey.pem /etc/ssl/private/
iwuser$ sudo mv cacert.pem /etc/ssl/certs/

Configure Postfix with Certificates

Now that the certificates have been created and moved to appropriate locations, I have to ensure Postfix has the information it needs to use TLS encryption for both incoming and outgoing email.


iwuser$ sudo postconf -e 'smtpd_tls_auth_only = no'
iwuser$ sudo postconf -e 'smtp_use_tls = yes'
iwuser$ sudo postconf -e 'smtpd_use_tls = yes'
iwuser$ sudo postconf -e 'smtp_tls_note_starttls_offer = yes'
iwuser$ sudo postconf -e 'smtpd_tls_key_file = /etc/ssl/private/smtpd.key'
iwuser$ sudo postconf -e 'smtpd_tls_cert_file = /etc/ssl/certs/smtpd.crt'
iwuser$ sudo postconf -e 'smtpd_tls_CAfile = /etc/ssl/certs/cacert.pem'
iwuser$ sudo postconf -e 'smtpd_tls_loglevel = 1'
iwuser$ sudo postconf -e 'smtpd_tls_received_header = yes'
iwuser$ sudo postconf -e 'smtpd_tls_session_cache_timeout = 3600s'
iwuser$ sudo postconf -e 'tls_random_source = dev:/dev/urandom'
iwuser$ sudo postconf -e 'myhostname = mail.istarelworkshop.com'

Postfix needs to be restarted for these changes to be recognized.

iwuser$ sudo /etc/init.d/postfix restart