Thursday, December 12, 2013

Objective C, JSON APIs and a few details worth noting...

Types that can be returned by JSON API:

  • string
  • number
  • boolean
  • null

When parsing JSON with Objective C's NSJSONSerialization class we get the following conversions:

  • string (NSString)
  • number (NSNumber)
  • boolean (NSNumber*)
  • null (NSNull*)

*Note that boolean to NSNumber will NSLog itself as __NSCFBoolean. What?! We just noted above that booleans get parsed as NSNumbers!! Okay, settle, it all does make sense with a little further explanation; __NSCFBoolean is a private class that is used in the NSNumber class cluster. Don't concern yourself with it. Understand that JSON response fields containing a boolean will get parsed as an NSNumber and that to check the parsed value for its meaning (i.e. true/false) you can NOT do if (myBoolean) or if (!myBoolean). Instead, you need to check if ([myBoolean boolValue]) or if (![myBoolean boolValue]) respectively.

*Note that null to NSNull is different than what you might hope for (null to nil). If you send a message to NSNull that it doesn't understand (this is easy to do if you're working with an optional string field), NSNull will crash your app (as opposed to just returning nil). Yikes!

So, how does it all add up? Well, from my experience as a PHP programmer, API developer, and iOS client creator... I'd break it down like this:

Strings, numbers, booleans, and nulls all serve a purpose on the server (both the backend database and API application layer (PHP)). For example, null means a value that hasn't yet been defined. We write queries using null, do special application logic based on it (i.e. send an email where we otherwise wouldn't, etc). It's true that in some cases the null value might even be important to the client, and if so, could be passed on through. However, from my experience, it rarely is. With Objective C being a strongly typed language and the risk of crashing being very real, I've found that I like writing APIs that simplify their output to just strings. 99% of the time, even when receiving a number from the API, I am getting it so I can display it in the UI (i.e. I need it as a string). Therefore the simplicity of working with an all strings API is wonderful and also helps avoid app crashes. I even like to switch my boolean values to strings and just use yes or no. I like the way it reads and keeps the entire API as strings only.

It's all about style. For me, I've found simplifying my API output makes for an easier to use JSON API for my iOS apps.

Saturday, September 7, 2013

How can I get certain domain names to resolve locally using Mac OS X?

By default, all domain names will be looked up via online DNS servers. To resolve locally, we need to override this behavior. We do this by editing our /etc/hosts file. Open it (you'll be prompted for your password). In order to get a certain domain name, say example.com, to resolve locally, add a line that looks like this:
127.0.0.1 examplesite.com
The 127.0.0.1 means localhost. examplesite.com should be replaced with your domain name. Upon saving the document, changes will be made live immediately. There is no need to flush cache or anything of that sort. Happy coding locally!

Monday, May 6, 2013

How do I determine the version of Apache installed on a Debian based Linux machine?

Run the following command:
sudo apachectl -V
Which will print something similar to:
Server version: Apache/2.2.16 (Debian)
Server built:   Mar  3 2013 12:09:44
Server's Module Magic Number: 20051115:24
Server loaded:  APR 1.4.2, APR-Util 1.3.9
Compiled using: APR 1.4.2, APR-Util 1.3.9
Architecture:   64-bit
Server MPM:     Prefork
  threaded:     no
    forked:     yes (variable process count)
Server compiled with....
 -D APACHE_MPM_DIR="server/mpm/prefork"
 -D APR_HAS_SENDFILE
 -D APR_HAS_MMAP
 -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled)
 -D APR_USE_SYSVSEM_SERIALIZE
 -D APR_USE_PTHREAD_SERIALIZE
 -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT
 -D APR_HAS_OTHER_CHILD
 -D AP_HAVE_RELIABLE_PIPED_LOGS
 -D DYNAMIC_MODULE_LIMIT=128
 -D HTTPD_ROOT="/etc/apache2"
 -D SUEXEC_BIN="/usr/lib/apache2/suexec"
 -D DEFAULT_PIDLOG="/var/run/apache2.pid"
 -D DEFAULT_SCOREBOARD="logs/apache_runtime_status"
 -D DEFAULT_LOCKFILE="/var/run/apache2/accept.lock"
 -D DEFAULT_ERRORLOG="logs/error_log"
 -D AP_TYPES_CONFIG_FILE="mime.types"
 -D SERVER_CONFIG_FILE="apache2.conf"

Wednesday, May 1, 2013

How do I create a Facebook web app using CodeIgniter?

First things first, this tutorial assumes you have the following setup:
Okay, first we need to create a Facebook app. Go here: https://developers.facebook.com/apps?ref=bookmarks&count=0&fb_source=bookmark_apps&fb_bmpos=6_0 (and for the record, yes, I think that's a totally weird looking URL). Then, click the "Create New App" button as shown in the following screenshot:
Next, name your app and then click the "Continue" button:
Next, pass through the security check:
Great. Now fill out the rest of your application's profile as shown in this screenshot:
After clicking "Save Change" you'll see the following success message:

Okay, now download the latest version of CodeIgniter:
Then unzip your download:
Then add your own web root dir named "www" and rename your CI parent folder to your app's domain name:
Move the folder to your home directory:

Okay, now spin up a new web server:


Next, config your DNS:
Now open up Terminal and cd into your project directory.
cd ~/fbciexample.abovemarket.com
Now run the following command:
git init
You'll see the following output:
Initialized empty Git repository in /Users/johnerck/fbciexample.abovemarket.com/.git/
Next, add clitools for release management. If you don't already have clitools on your local machine, run the following command to git clone it to your home directory:
git clone git@bitbucket.org:abovemarket/clitools.org.git ~/clitools.org
You'll see the following output:
Cloning into '/Users/johnerck/clitools.org'...
remote: Counting objects: 132, done.
remote: Compressing objects: 100% (112/112), done.
remote: Total 132 (delta 41), reused 0 (delta 0)
Receiving objects: 100% (132/132), 256.54 KiB, done.
Resolving deltas: 100% (41/41), done.
Okay, after running that command, run this next:
php ~/clitools.org/clitools/installto.php ~/fbciexample.abovemarket.com/clitools
You'll see the following output:
Success: You've successfully installed clitools to ~/fbciexample.abovemarket.com/clitools/
Okay, now it's time to create both our local and remote databases:
After walking through the process pictured above twice (once locally, and once on your remote production machine), open the following two files:
open ~/fbciexample.abovemarket.com/clitools/_env.php
open ~/fbciexample.abovemarket.com/clitools/_release.php
Add your database credentials as illustrated:

The rest of this post is going to assume you have an empty database setup in both your local and remote environments and that you've properly filled out your _env.php and _release.php files.

We'll continue to use clitools throughout this tutorial but now is a good time to mention that you can read more about clitools at clitools.org.

Ok, back to the task at hand. Your local database should look like this:
Now again, on your local machine, run the following command:
php ~/fbciexample.abovemarket.com/clitools/uschema.php
After running that command you should see the following output:
mysql -h localhost -u fbciexample -p********** fbciexample < ~/fbciexample.abovemarket.com/clitools/changes/schema/1.sql
Success: Your database is up to date (at 1.sql)
Files Applied:
~/fbciexample.abovemarket.com/clitools/changes/schema/1.sql
Now, if you refresh your database page it should look like this:
If you click into the version table you'll see:

Next, create a BitBucket (or GitHub) project repo:
Next, on your local machine, go to the root of your project dir via the following command:
cd ~/fbciexample.abovemarket.com
Okay, now run the following commands:
git remote add origin ssh://git@bitbucket.org/abovemarket/fbciexample.abovemarket.com.git
git add .
git commit -m 'Initial commit'
Now open your .git/config file:
nano .git/config
Add the following lines to the end (make sure you indent using one tab rather than 4 spaces):
[branch "master"]
    remote = origin
    merge = refs/heads/master
Save the file. Push your changes:
git push -u origin --all
You'll see the following output:
Counting objects: 410, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (394/394), done.
Writing objects: 100% (410/410), 2.17 MiB | 3.96 MiB/s, done.
Total 410 (delta 127), reused 0 (delta 0)
remote: bb/acl: johnerck is allowed. accepted payload.
To ssh://git@bitbucket.org/abovemarket/fbciexample.abovemarket.com.git
 * [new branch]      master -> master
Branch master set up to track remote branch master from origin.
Great. Now ssh into your remote machine:
ssh -p your_port you@your_ip_address
Remember that if you run into trouble here, it may be because you have MAMP turned on and so whatever domain you're using is resolving to localhost rather than hitting the net.

Now that you're on your remote machine, run the following command:
git clone git@bitbucket.org:abovemarket/fbciexample.abovemarket.com
You'll see the following output:
Cloning into fbciexample.abovemarket.com...
remote: Counting objects: 410, done.
remote: Compressing objects: 100% (267/267), done.
remote: Total 410 (delta 127), reused 410 (delta 127)
Receiving objects: 100% (410/410), 2.17 MiB, done.
Resolving deltas: 100% (127/127), done.
The directory created when you get cloned the project needs to match apache's web root. If you're interested in knowing how to set up vhosts, checkout a post I did awhile back on that topic: http://oneqonea.blogspot.com/2013/04/how-do-i-set-up-apache-virtual-hosts-on.html

This tutorial assumes you have your remote apache server environment set up properly. You can exit your remote machine:
exit
Okay, now it's time to release our app!

You can run a git status just to see where we're at right now.
git status
It should output:
# On branch master
nothing to commit (working directory clean)
Okay, great. Since our current branch is "clean", we know we can release. Since we're on the "master" branch, we know we're about to release master (this is the nature of clitools).

Run the following command:
php clitools/releaseto.php production
clitools will tell you what it's doing while it runs. The last line should say:
Local status: You've successfully released your project from master to production (v00.001.000)
clitools just did a number of things for us. A quick review would include:
  • Created a new release branch (rb00.001)
  • Created a new release tag from that branch (v00.001.000)
  • Ssh'd into our remote machine and checked out git tag v00.001.000
  • Triggered clitools/uschema.php (updated the target machine's database)
  • Triggered clitools/udata.php (php file that's available to be run on release if need be)
  • Updated clitools/version.php's file content with v00.001.000
  • Version stamped each change file applied (if target was "production")
  • Version stamped a copy of udata's source file (regardless of target environment but only if udata's source file was not empty)
  • Printed a success message to our screen and pushed the release branch to origin so the rest of our team can be in the loop!
Now access your fbciexample.abovemarket.com:
On your local machine, run the following command:
open ~/fbciexample.abovemarket.com/www/index.php
Add the following lines of php code to the top of the file after the opening php tag:
require_once dirname(__FILE__) . '/../clitools/_env.php';
date_default_timezone_set('UTC'); // So we can call new DateTime();
Where the file says:
define('ENVIRONMENT', 'development');
Replace it with:
$ci_environment_translation = CLITOOLS__ENVIRONMENT === 'local' ? 'development' : CLITOOLS__ENVIRONMENT;
define('ENVIRONMENT', $ci_environment_translation);
If you want errors to get logged in production, switch production's error_reporting from error_reporting(0); to:
error_reporting(E_ALL);
Now set $system_path and $application_folder like so:
$system_path = CLITOOLS__CI_SYSTEM_PATH;
$application_folder = CLITOOLS__CI_APPLICATION_FOLDER;
Now open your clitools/_env.php file:
open ~/fbciexample.abovemarket.com/clitools/_env.php
Add the following lines to your _env.php file (but translated for YOUR local machine of course):
define('CLITOOLS__CI_SYSTEM_PATH', '/Users/johnerck/fbciexample.abovemarket.com/system');
define('CLITOOLS__CI_APPLICATION_FOLDER', '/Users/johnerck/fbciexample.abovemarket.com/application');
Now open your clitools/_release.php file:
open ~/fbciexample.abovemarket.com/clitools/_release.php
Add the following lines to your _release.php file's $content var (but translated for YOUR remote machine of course):
"define('CLITOOLS__CI_SYSTEM_PATH', '/home/admin/fbciexample.abovemarket.com/system');
define('CLITOOLS__CI_APPLICATION_FOLDER', '/home/admin/fbciexample.abovemarket.com/application');"
Now run:
git status
git add .
git commit -m 'Updated some environment related settings (i.e. fixed bug in app)'
git push
php clitools/releaseto.php production
clitools will tell you what it's doing while it runs. The last line should say:
Local status: You've successfully released your project from master to production (v00.002.000)
Now access your fbciexample.abovemarket.com
Congrats! You're on fire!

Want pretty URLs? Me too. Add the following .htaccess file in www/:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?/$1 [L]
Then
open application/config/config.php
and update to:
$config['index_page'] = ''; // Was previously 'index.php'
That's all for now. At a future date I'll extend this post to show you how to install Sparks (SolidSess to be exact). That's where FB comes into the mix too! Later!

Saturday, April 27, 2013

How do I set up Apache virtual hosts on a Debian based Linux machine and configure to support HTTPS?

Preliminary quick note, if you haven't enabled ssh keys between your local machine and your remote machine, I recommend that you do. I just posted a how to on this you can check out here: http://oneqonea.blogspot.com/2013/04/how-do-i-set-up-ssh-keys-and-turn-off_27.html

Okay, now on to virtual host configuration! Connect to your remote machine (hopefully via ssh keys!):
ssh -p your_port you@your_ip_address
Then run the following command:
sudo mkdir -p /etc/apache2/ssl/your_site.com
Then run the following command:
sudo openssl req -new -x509 -days 365 -nodes -out /etc/apache2/ssl/your_site.com/apache.pem -keyout /etc/apache2/ssl/your_site.com/apache.pem
You'll see the following output:
Generating a 1024 bit RSA private key
..++++++
...........................++++++
writing new private key to '/etc/apache2/ssl/your_site.com/apache.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]: # your input here...
State or Province Name (full name) [Some-State]: # your input here...
Locality Name (eg, city) []: # your input here...
Organization Name (eg, company) [Internet Widgits Pty Ltd]: # your input here...
Organizational Unit Name (eg, section) []: # your input here...
Common Name (eg, YOUR name) []: # your input here...
Email Address []: # your input here...
Now enable ssl within apache:
sudo a2enmod ssl
You'll see the following output:
Enabling module ssl.
See /usr/share/doc/apache2.2-common/README.Debian.gz on how to configure SSL and create self-signed certificates.
Run '/etc/init.d/apache2 restart' to activate new configuration!
We don't need to restart apache at the moment as we still have work to do! Also note, you can open and read the file they recommend and get apache config info straight from the horse's mouth too if you want! Here's a blog post that shows you the content of that file: http://oneqonea.blogspot.com/2013/04/whats-best-place-to-look-for-how-to.html

While we're at it let's enable apache's mod_rewrite too:
sudo a2enmod rewrite
Again, it's not necessary to restart your server at this time.

Next we're going to set up our virtual hosts. Run the following command:
sudo cp /etc/apache2/sites-available/default /etc/apache2/sites-available/your_site.com
Then run:
sudo nano /etc/apache2/sites-available/your_site.com
Update it with your site's info (and set "AllowOverride" to "All" to enable .htaccess files):
<VirtualHost *:80>
        ServerAdmin admin@your_site.com
        ServerName your_site.com
        ServerAlias www.your_site.com

        DocumentRoot /home/admin/your_site.com/www
        <Directory />
                Options FollowSymLinks
                AllowOverride None
        </Directory>
        <Directory /home/admin/your_site.com/www/>
                Options Indexes FollowSymLinks MultiViews
                AllowOverride All
                Order allow,deny
                allow from all
        </Directory>

        ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
        <Directory "/usr/lib/cgi-bin">
                AllowOverride None
                Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
                Order allow,deny
                Allow from all
        </Directory>

        ErrorLog /error.log

        # Possible values include: debug, info, notice, warn, error, crit,
        # alert, emerg.
        LogLevel warn

        CustomLog /access.log combined
</VirtualHost>
Also, be sure to add ServerName your_site.com and ServerAlias www.your_site.com after the ServerAdmin line (so you'll be in a position to host multiple https sites on a single machine).

Now, we need to create almost the exact same thing in the same file but wrap the config settings in <VirtualHost *:443> rather than <VirtualHost *:80>, to do this easily, run the following series of commands:
su root
Then run the following TWO commands as root (we're appending to the new file so we want to run the same command twice):
cat /etc/apache2/sites-available/your_site.com >> /etc/apache2/sites-available/new_temp
cat /etc/apache2/sites-available/your_site.com >> /etc/apache2/sites-available/new_temp
Then exit from root:
exit
Then replace your old file:
sudo mv /etc/apache2/sites-available/new_temp /etc/apache2/sites-available/your_site.com
Now open your file for editing:
sudo nano /etc/apache2/sites-available/your_site.com
Scroll down to the second instance of <VirtualHost *:80> and replace it with:
<VirtualHost *:443>
Now add the following two lines within your :443 settings block:
SSLEngine on
SSLCertificateFile /etc/apache2/ssl/your_site.com/apache.pem
Next, you need to create your website's document root. I do this by running a git clone. If you don't have git installed on your server or you haven't yet linked your machine with your BitBucket/GitHub account, checkout the following post before continuing (it's easy): http://oneqonea.blogspot.com/2013/04/how-do-i-install-git-and-link-my-linux.html

Okay cool, you're back. After checking out that post you should now have your project cloned to your remote machine (i.e. the document root dir referenced in our vhost config file now points to a directory that exists).

Next, we need to edit our ports.conf file:
sudo nano /etc/apache2/ports.conf
Add the following line as depicted in the following image:
NameVirtualHost *:443
Now is a good time to double check and make sure "your_site.com" points to "your_ip_address" at the DNS level. Once you've double checked that all we need to do is enable our site, disable default, and restart apache:
sudo a2ensite your_site.com
Output will tell you to run a follow up command. You don't need to at this time. Next run:
sudo a2dissite default
Now restart apache (as opposed to reload):
sudo /etc/init.d/apache2 restart
Badda bing, badda boom! You're up and running with a secure site! Now let's test it!

Put a "test" info.php file inside your project's web root:
echo '<?php phpinfo();' > your_site.com/www/info.php
Now access your_site.com/info.php via http first and https second. The following screenshots show what you should see!




If your screens look like my screens then you rock! Let's wrap up by removing our test file:
rm your_site.com/www/info.php
After doing that you're done! You can exit your remote machine.
exit
Congrats!

In a future post we'll be looking at how to add a release management library I wrote called clitools to a CodeIgniter project and doing your first release to your new machine! Stay tuned!

How do I install git and link my Linux machine to my BitBucket/GitHub account?

To start things off, connect to your remote machine:
ssh -p your_port you@your_ip_address
Now, see if you already have git installed:
which git
If your machine has git installed you'll see its path printed to your screen. Else, you'll need to install it:
sudo aptitude install git
You'll be prompted regarding incoming file size. Enter "yes". Now run:
which git
You'll see the program's path printed to your screen:
/usr/bin/git
Now we need to check and see if you have an ssh key pair on your machine or if we need to create one. To start off, we need to examine your remote machine. Run the following command:
cat ~/.ssh/id_rsa.pub
If the above command prints "No such file or directory", then you'll need to generate an ssh key pair before continuing. If the previous command printed a bunch of funny looking letters and numbers, then you already have an ssh key pair on your local machine that we can make use of!

Okay, so if your machine doesn't already have an ssh key pair on file, we can easily create one. Enter the following command:
ssh-keygen -t rsa -C "your_email@your_domain.com"
You'll be prompted with the following:
Enter file in which to save the key (/Users/you/.ssh/id_rsa):
Just press enter and "~/.ssh/id_rsa" will be used (which is what we want).

Next, you'll be prompted with the following:
Enter passphrase (empty for no passphrase):
Press enter twice to generate a key pair without a passphrase.

Now, at this point, everybody should have an "~/.ssh/id_rsa.pub" file on their remote machine. Next, log in to your BitBucket or GitHub account.

For BitBucket follow these steps:

  • Step 3) Print your machine's id_rsa.pub file content on the command line so you can manually copy it into memory:
    cat ~/.ssh/id_rsa.pub
    After copying it, without getting a single extra character accidentally added, paste it into your BitBucket account as shown in the following screenshot:


For GitHub follow these steps:

  • Step 3) Print your machine's id_rsa.pub file content on the command line so you can manually copy it into memory:
    cat ~/.ssh/id_rsa.pub
    After copying it, without getting a single extra character accidentally added, paste it into your GitHub account as shown in the following screenshot:
Next, config git to use your BitBucket/GitHub email address:
git config --global user.name "Your Full Name Here"
git config --global user.email your_repo_email@your_domain.com
Now, clone your project!

For BitBucket:
git clone git@bitbucket.org:your_username/your_project.git your_domain.com
For GitHub:
git clone git@github.com:your_username/your_project.git your_domain.com
In either case, you'll be prompted about "The authenticity of host...", enter "yes".

Boom! You're done! Way to go!

Lastly, if you're coming from my post titled, "How do I set up Apache virtual hosts on a Debian based Linux machine and configure to support HTTPS?", you can get back to it here: http://oneqonea.blogspot.com/2013/04/how-do-i-set-up-apache-virtual-hosts-on.html

What's the best place to look for how to manage an Apache2 server running on a Debian-based Linux box?

If you don't already have apache2 installed on your machine, run the following command:
sudo aptitude install apache2
Then run:
sudo gunzip /usr/share/doc/apache2.2-common/README.Debian.gz
Followed up by:
cat /usr/share/doc/apache2.2-common/README.Debian
Which will print 399 lines of very helpful information:
Contents
========

 Apache2 Configuration under Debian GNU/Linux
  Files and Directories in /etc/apache2
  Tools

 Using mod_disk_cache

 SSL
  Enabling SSL
  Creating self-signed certificates
  SSL workaround for MSIE

 Suexec
 
 Documentation

 Upgrades

 Common Problems


Apache2 Configuration under Debian GNU/Linux
============================================

Debian's default Apache2 installation attempts to make adding and
removing modules, virtual hosts, and extra configuration directives as
flexible as possible, in order to make automating the changes and
administering the server as easy as possible.

Please be aware that this layout is quite different from the standard
Apache configuration. Due to the use of environment variables, apache2
needs to be started/stopped with /etc/init.d/apache2 or apache2ctl. 
Calling /usr/bin/apache2 directly will not work with the default
configuration. To call apache2 with specific command line arguments,
just call apache2ctl with the same arguments.

Files and Directories in /etc/apache2:
-------------------------------------

apache2.conf

 This is the main configuration file.

envvars

 This contains environment variables that may be used in the
 configuration. Some settings, like user and pid file, need to
 go in here so that other scripts can use them. It can also
 be used to change some default settings used by apache2ctl.
 Here is also the default LANG=C setting that can be changed
 to a different language.

conf.d/

 Files in this directory are included by this line in
 apache2.conf:

 # Include generic snippets of statements
 Include /etc/apache2/conf.d

 This is a good place to add additional configuration
 directives. Packages should not use configuration
 files that start with 'local-' or end with '.local'.
 The local administrator can use these filenames to make
 sure that there are no conflicts with files provided by
 packages.

 If the local administrator is not comfortable with packages
 activating their config files by default, it is possible
 to change the 'Include /etc/apache2/conf.d/' in apache2.conf
 into 'Include /etc/apache2/conf.d.enabled/' and create that
 directory. He can then put symlinks to the files in conf.d
 which he wants to enable into conf.d.enabled.

httpd.conf

 Empty file.

magic

 Patterns for mod_mime_magic. This is not compatible with the format
 used by current versions of the file/libmagic packages.

mods-available/

 This directory contains a series of .load and .conf files.
 The .load files contain the Apache configuration directive
 necessary to load the module in question.  The respective
 .conf files contain configuration directives necessary to
 utilize the module in question.

mods-enabled/

 To actually enable a module for Apache2, it is necessary to
 create a symlink in this directory to the .load (and .conf, if
 it exists) files associated with the module in
 mods-available/.  For example:

 cgi.load -> /etc/apache2/mods-available/cgi.load

ports.conf

 Configuration directives for which ports and IP addresses to
 listen to.

sites-available/

 Like mods-available/, except it contains configuration
 directives for different virtual hosts that might be used with
 apache2.  Note that the hostname doesn't have to correspond
 exactly with the filename.  'default' is the default host.

sites-enabled/

 Similar in functionality to mods-enabled/, sites-enabled
 contains symlinks to sites in sites-available/ that the
 admnistrator wishes to enable.

 Apache uses the first VirtualHost that matches the IP/Port
 as default for named virtual hosts. Therefore the 'default'
 site is linked to '000-default' so that it will be read first.

 Example:
 dedasys -> /etc/apache2/sites-available/dedasys

The Include directive ignores files with names that

- do not begin with a letter or number
- contain a character that is neither letter nor number nor _-.
- contain .dpkg

Other files
-----------

For historical reasons, the pid file is in /var/run/apache2.pid and not in
/var/run/apache2/apache2.pid.

Tools
-----

a2enmod and a2dismod are available for enabling and disabling modules utilizing
the above configuration system.

a2ensite and a2dissite do essentially the same thing as the above tools, but
for sites rather than modules.

apxs2 -a/-A is modified to use a2enmod to activate newly installed modules.


Using mod_disk_cache
====================

To ensure that the disk cache does not grow indefinitely, htcacheclean is
started when mod_disk_cache is enabled. Both daemon and cron (daily) mode
are supported. The configuration (run mode, cache size, ...) is in
/etc/default/apache2 .

Normally, htcacheclean is automatically started and stopped by
/etc/init.d/apache2. However, if you change the state of mod_disk_cache or the
configuration of htcacheclean while apache2 is running, you may need to
manually start/stop htcacheclean with "/etc/init.d/apache2 start-htcacheclean"
or "/etc/init.d/apache2 stop-htcacheclean".


SSL
===

Enabling SSL
------------

To enable SSL, type (as user root):

 a2ensite default-ssl
 a2enmod ssl

If you want to use self-signed certificates, you should install the ssl-cert
package (see below). Otherwise, just adjust the SSLCertificateFile and
SSLCertificateKeyFile directives in /etc/apache2/sites-available/default-ssl to
point to your SSL certificate. Then restart apache:

 /etc/init.d/apache2 restart

The SSL key file should only be readable by root, the certificate file may be
globally readable. These files are read by the Apache parent process which runs
as root. Therefore it is not necessary to make the files readable by the
www-data user.

Creating self-signed certificates
---------------------------------

If you install the ssl-cert package, a self-signed certificate will be
automatically created using the hostname currently configured on your computer.
You can recreate that certificate (e.g. after you have changed /etc/hosts or
DNS to give the correct hostname) as user root with:

 make-ssl-cert generate-default-snakeoil --force-overwrite

To create more certificates with different host names, you can use

 make-ssl-cert /usr/share/ssl-cert/ssleay.cnf /path/to/cert-file.crt

This will ask you for the hostname and place both SSL key and certificate in
the file /path/to/cert-file.crt . Use this file with the SSLCertificateFile
directive in the Apache config (you don't need the SSLCertificateKeyFile in
this case as it also contains the key). The file /path/to/cert-file.crt should
only be readable by root. A good directory to use for the additional
certificates/keys is /etc/ssl/private .

SSL workaround for MSIE
-----------------------

The SSL workaround for MS Internet Explorer needs to be added to your SSL
VirtualHost section (it was previously in ssl.conf but caused keepalive to be
disabled even for non-SSL connections):

 BrowserMatch "MSIE [2-6]" \
  nokeepalive ssl-unclean-shutdown \
  downgrade-1.0 force-response-1.0
 BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown

The default SSL virtual host in /etc/apache2/sites-available/default-ssl
already contains this workaround.


Suexec
======

Debian ships two version of the suexec helper program required by mod_suexec.
It is not installed by default, to avoid possible security issues. The package
apache2-suexec contains the standard version that works only with document root
/var/www, userdir suffix public_html, and Apache run user www-data. The package
apache2-suexec-custom contains a customizable version, that can be configured
with a config file to use different settings (like /srv/www as document root).
For more information see the suexec(8) man page in the apache2-suexec-custom
package.

Since apache2-suexec-custom has received less testing and might be slightly
slower, apache2-suexec is the recommended version unless you need the features
from apache2-suexec-custom.


Documentation
=============

The full Apache 2 documentation can be found on the web at

http://httpd.apache.org/docs/2.2/

or, if you have installed the apache2-doc package, in

/usr/share/doc/apache2-doc/manual/

or at

http://localhost/manual/

There is also a wiki that contains useful information:

http://wiki.apache.org/httpd/

Some hints about securing Apache 2 on Debian are available at

http://wiki.debian.org/Apache/Hardening


Upgrades
========

Changes in the Apache packages that require manual configuration adjustments
are announced in NEWS.Debian. Installing the apt-listchanges package is
recommended. It will display the relevant NEWS.Debian sections before
upgrades.


Multiple instances
==================

There is some support for running multiple instances of Apache2 on the same
machine. See /usr/share/doc/apache2.2-common/README.multiple-instances for more
information.


Common Problems
===============

1) Error message "Could not reliably determine the server's fully qualified 
domain name, using 127.0.0.1 for ServerName" during start

This can usually be ignored but it means that Apache httpd was unable to obtain
a fully-qualified hostname by doing a reverse lookup on your server's IP
address. You may want to add the fully-qualified hostname to /etc/hosts .
An alternative is to specify "ServerName 127.0.0.1" in the global server
context of the configuration, e.g. in /etc/apache2/conf.d/servername.local .

2) Error message "mod_rewrite: could not create rewrite_log_lock"

This probably means that there are some stale SYSV semaphores around. This
usually happens after apache2 has been killed with kill -9 (SIGKILL). You can
clean up the semaphores with:

 ipcs -s | grep www-data | awk ' { print $2 } ' | xargs ipcrm sem

3) Message "NameVirtualHost *:80 has no VirtualHosts" in error log

Probably the VirtualHost definitions have not been adjusted after the 
NameVirtualHost directive was changed in ports.conf. 
See /usr/share/doc/apache2.2-common/NEWS.Debian.gz

4) Message "File does not exist: /etc/apache2/htdocs" in error log

In most cases this means that no matching VirtualHost definition could be
found for an incoming request. Check that the target IP address/port and the
name in the Host: header of the request actually match one of the virtual
hosts.

5) Message "Couldn't create pollset in child; check user or system limits" in
  error log

On Linux kernels since 2.6.27.8, the value in

    /proc/sys/fs/epoll/max_user_instances

needs to be larger than

    for prefork/itk  MPM: 2 * MaxClients
    for worker/event MPM: MaxClients + MaxClients/ThreadsPerChild

It can be set on boot by adding a line like

        fs.epoll.max_user_instances=1024

to /etc/sysctl.conf.

There are several other error messages related to creating a pollset that can
appear for the same reason.

On the other hand, errors about to adding to a pollset are related to the
setting fs.epoll.max_user_watches. On most systems, max_user_watches should be
high enough by default.

6) Message "Server should be SSL-aware but has no certificate configured" in
   error log

Since 2.2.12, Apache is stricter about certain misconfigurations concerning
name based SSL virtual hosts. See NEWS.Debian.gz for more details.

7) Apache does not pass Authorization header to CGI scripts

This is intentional to avoid security holes. If you really want to change it,
you can use mod_rewrite:

 RewriteCond %{HTTP:Authorization} (.*)
 RewriteRule . - [env=HTTP_AUTHORIZATION:%1]

8) mod_dav is behaving strangely

In general, if you use mod_dav_fs, you need to disable multiviews and script
execution for that directory. For example:

    <Directory /var/www/dav>
        Dav on
        Options -MultiViews -ExecCGI
        SetHandler none
        <IfModule mod_php5.c>
            php_admin_value engine Off
        </IfModule>
    </Directory>

9) Message "apache2: bad user name " when starting apache2
   directly

Use apache2ctl (it accepts all options of apache2).

10) Apache is using a lot of memory and is not freeing it even when idle

By default, Apache will not give back unused memory but keep it around for
later use.

  * Tune StartServers, MaxRequestsPerChild, MinSpareThreads/MinSpareServers,
    MaxSpareThreads/MaxSpareServers in /etc/apache2/apache2.conf

  * If you are really starved for memory, try adding 'MaxMemFree 4' to your
    Apache configuration. This will reduce Apache's performance.
    Because of the way Apache's memory allocator interacts with glibc's malloc,
    higher values of MaxMemFree don't have much effect.

11) A PUT with mod_dav_fs fails with "Unable to PUT new contents for /...
[403, #0]" even if Apache has permission to write the file.

Apache also needs write permission to the directory containing the file, in
order to replace it atomically.

12) How to increase the ulimit for the max number of open files?

Add the following line to /etc/apache2/envvars:

 APACHE_ULIMIT_MAX_FILES='ulimit -n 65536'

How do I set up ssh keys and turn off password access on my new Linux box?

To start off, we need to examine your local machine. Run the following command:
cat ~/.ssh/id_rsa.pub
If the above command prints "No such file or directory", then you'll need to generate an ssh key pair before continuing. If the previous command printed a bunch of funny looking letters and numbers, then you already have an ssh key pair on your local machine that we can make use of!

Okay, so if your machine doesn't already have an ssh key pair on file, we can easily create one. Enter the following command:
ssh-keygen -t rsa -C "your_email@example.com"
You'll be prompted with the following:
Enter file in which to save the key (/Users/you/.ssh/id_rsa):
Just press enter and "~/.ssh/id_rsa" will be used (which is what we want).

Next, you'll be prompted with the following:
Enter passphrase (empty for no passphrase):
Press enter twice to generate a key pair without a passphrase.

Now, at this point, everybody should have an "~/.ssh/id_rsa.pub" file on their local machine. Next, connect to your remote machine using your password:
ssh -p your_port you@your_ip_address
Then, run the following command (to ensure you have an ".ssh" dir on file):
mkdir -p ~/.ssh
Now exit and return to your local machine:
exit
Next, copy your public key to your remote machine:
scp -P your_ssh_port ~/.ssh/id_rsa.pub your_user@your_ip_address:~/incoming_public_key.pub
Next, connect to your remote machine via username and password:
ssh -p your_port you@your_ip_address
Next, enter the following command:
cat ~/incoming_public_key.pub >> ~/.ssh/authorized_keys
Then remove the source file:
rm ~/incoming_public_key.pub
Now, exit your remote machine:
exit
SSH keys have now been set up! Now, with a single command you're into your remote machine:
ssh -p your_ssh_port you@your_ip_address
Boom! Time to disallow password-based ssh connections.

K, starting from within your remote machine, run the following command:
sudo nano /etc/ssh/sshd_config
Then, scroll down to the section that looks like this:
# Change to no to disable tunnelled clear text passwords
PasswordAuthentication yes
and switch it to this:
# Change to no to disable tunnelled clear text passwords
PasswordAuthentication no
Save the file. Now restart the ssh daemon:
sudo /etc/init.d/ssh restart
Boom. We're done, ssh key pair connections only! Before exiting the remote machine you can validate this yourself if you'd like by walking through the following process:
  • Step 0) Make sure you have an open connection to your remote machine.
  • Step 1) Open a new Terminal window.
  • Step 2) Run the following command on your remote machine:
mv ~/.ssh/authorized_keys ~/.ssh/authorized_keys_mimic_no_machines_authed
  • Step 3) In your other Terminal window (local machine), try to ssh into your machine:
ssh -p your_ssh_port you@your_ip_address
You'll see the following output:
Permission denied (publickey).
Boom! Now das wassup!

If you're interested in what's going on process-wise, here's the skinny: By moving the location of the "authorized_keys" file on the remote machine we're mimicking your local machine not having a "machine to machine ssh key connection" with your remote box. Therefore, when we run the above ssh command, ssh first tries to connect using your machine's local ssh key pair, but gets denied because the public key counterpart is "not on file" on our remote machine (remember that we moved the "authorized_keys" file to "authorized_keys_mimic_no_machines_authed" to create this scenario). Next, ssh looks to use a password picked up from the command line and gets rejected on that due to our latest sshd config update! Woo hoo! At this point you can test connecting with your root user too if you'd like and you'll see that not even root can log in to the remote machine! Now you see why I said, "Make sure you have an open connection to your remote machine." in "Step 0" above. Let's put things back now. Run the following command on your remote machine:
mv ~/.ssh/authorized_keys_mimic_no_machines_authed ~/.ssh/authorized_keys
Now, from your other Terminal window, you can run:
ssh -p your_ssh_port you@your_ip_address
And boom you'll be good to go.

Now das wassup! You're done! You can even exit your remote machine if you want!
exit
Lastly, if you're coming from my "How do I set up Apache virtual hosts on a Debian based Linux machine and configure to support HTTPS?" post, you can get back to it here: http://oneqonea.blogspot.com/2013/04/how-do-i-set-up-apache-virtual-hosts-on.html

Sunday, April 21, 2013

How do I install the latest versions of Apache, MySQL, and PHP on a Debian based Linux machine?

What up! So you want to know how to install the latest versions of Apache, MySQL, and PHP on a Debian based Linux machine? Sweet. Me too.

If you need help getting a Debian based Linux machine online, check out a post I did the other day titled: How do I set up a Next Generation Rackspace Cloud Server running Debian 7 (Wheezy)?

Okay, slap yourself in the face real quick. It's time to get started!

SSH into your machine.

Then walk through the following post: How do I install mysql-client, mysql-server, and libmysqlclient-dev on a Next Generation Rackspace Cloud Server running Debian 7 (Wheezy)? Note that you can skip the libmysqlclient-dev piece.

Great. You're back. Okay, now run the following command:
sudo aptitude install apache2
You'll be prompted to "ok" the amount of space that will be used after unpacking the archives. Enter "yes" to proceed.

Apache's default document root is /var/www on Debian, and the configuration file is /etc/apache2/apache2.conf. Additional configurations are stored in subdirectories of the /etc/apache2 directory such as /etc/apache2/mods-enabled (for Apache modules), /etc/apache2/sites-enabled (for virtual hosts), and /etc/apache2/conf.d.

If you enter your server's IP address into your browser, you'll see that we're on fire!
Okay, now on to installing php:
sudo aptitude install php5
PHP 5.4 will be installed. If you're setting up a Debian 6.0 (Squeeze) box and require php 5.4 (like I used to) then splash some hot coffee in your face because we've got an extra couple of steps to perform!

Run the following command:
sudo nano /etc/apt/sources.list
Add the following lines to the end of the file:
# http://www.dotdeb.org/instructions/ (but only for php54)
deb http://packages.dotdeb.org squeeze-php54 all
deb-src http://packages.dotdeb.org squeeze-php54 all
Now save the file. Next, run the following two commands:
wget http://www.dotdeb.org/dotdeb.gpg
cat dotdeb.gpg | sudo apt-key add -
After doing that, we can now update our list of available packages via the following command:
sudo aptitude update
Ok, now we can install php 5.4 via the following command:
sudo aptitude install php5
Boom goes the dynamite! We can verify our install by running the following command:
php -v
Which will output:
PHP 5.4.14-1~dotdeb.1 (cli) (built: Apr 21 2013 05:21:34)
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies
Okay, sweet! Now that we have php installed we can put a dot php file in apache's default document root (/var/www), restart apache, and then test our new setup. To begin, run the following command:
sudo nano /var/www/info.php
Then enter:
<?php
phpinfo();
Save the file. Now restart apache (since we haven't done so yet since installing php) via the following command:
sudo /etc/init.d/apache2 restart
Now access your new info.php page. You'll see the following:
You'll see we now have php working via the "Apache 2.0 Handler" (see "Server API" line). If you do a search for "mysql" you'll see that "mysql" is nowhere to be found! We'll need to fix that (as well as install other useful php modules). To see your options, run the following command:
aptitude search php5
I recommend installing php5-mysql, php5-curl, php5-gd, php-pear, php5-imagick, php5-imap, php5-mcrypt, php5-memcache, php5-sqlite, php5-tidy, php5-xmlrpc, and php5-xsl via the following command:
sudo aptitude install php5-mysql php5-curl php5-gd php-pear php5-imagick php5-imap php5-mcrypt php5-memcache php5-sqlite php5-tidy php5-xmlrpc php5-xsl
Okay sweet. Now we're talking! Revisit your info.php page (aptitude will have already restarted apache for you), do a search for "mysql" and then revel in your success! You are on fire!
Okay, now if you're anything like me you'd like a web interface to your remote database. PHPMyAdmin has you covered... but only if we install it! Get started with the following command:
sudo aptitude install phpmyadmin
As usual you'll be prompted about incoming file size. Enter "yes" when prompted. Next, you'll be presented with the following package configuration screen:

Select "apache2". You'll then be prompted with a second package configuration screen:

Select "No". And boom! You've got PHPMyAdmin installed! Not! There's actually one more step. To see for yourself visit your /phpmyadmin page and observe the 404!
To fix this. Run the following command:
sudo nano /etc/apache2/conf.d/phpmyadmin.conf
Then add the following line to the file:
Include /etc/phpmyadmin/apache.conf
Save the file. Then, restart apache via the following command:
sudo /etc/init.d/apache2 restart
Now revisit your /phpmyadmin page and observe your awesomeness!
Now that we've got our system set up properly we can remove our info.php file via the following command:
sudo rm /var/www/info.php
Now das wassup! Congrats, you're done! You successfully installed the latest versions of Apache, MySQL, and PHP.

If you're interested in getting your Apache hosting environment set up you should check out a post I wrote the other day titled: How do I set up Apache virtual hosts on a Debian based Linux machine and configure to support HTTPS?

Saturday, April 20, 2013

How do I install mysql-client, mysql-server, and libmysqlclient-dev on a Next Generation Rackspace Cloud Server running Debian 7 (Wheezy)?

First things first, there are a lot of MySQL packages available for install. If you want to see a list, run the following command:
aptitude search mysql
In this blog post we'll be installing mysql-client, mysql-server, and libmysqlclient-dev. Each is described as follows:

mysql-client:
MySQL database client (metapackage depending on the latest version)

mysql-server:
MySQL database server (metapackage depending on the latest version)

libmysqlclient-dev:
MySQL database development files

To get started, run the following command:
sudo aptitude install mysql-client
You'll be prompted for your password. Enter it. You'll then be prompted to "ok" the amount of space that will be used after unpacking the archives. Enter "yes" to proceed.

Next, run the following command:
sudo aptitude install mysql-server
Again, you'll get prompted regarding disk space. Enter "yes". Next, you'll be presented with a blue package configuration screen prompting you to enter a password for the root mysql user (twice). Enter something insane. Here's what the package configuration screen will look like:

mysql-server package configuration screen (for setting root user password)
After entering your totally insane root user password the installation process will continue on and then wrap itself up.

Next, if you're interested in prepping your machine for master/slave replication, run the following command:
sudo aptitude install libmysqlclient-dev
Again, you'll get prompted regarding disk space. Enter "yes". Next, you'll be throwing yourself a frickin' party because you're done! Congrats!

In a future post we'll be looking at how to set up MySQL master/slave replication (hence the reason I've added the libmysqlclient-dev section above)! Brace yo self foo!

Lastly, if you came to this page from my "How to install the latest versions of Apache, MySQL, and PHP" post and want to get back, or you're interested in installing Apache and/or PHP as a next step in setting up your server, click here: http://oneqonea.blogspot.com/2013/04/how-do-i-install-latest-versions-of.html

Wednesday, April 17, 2013

How do I set up a Next Generation Rackspace Cloud Server running Debian 7 (Wheezy)?

First, launch a new Debian 7 (Wheezy) server by following the instructions found at:
http://www.rackspace.com/knowledge_center/article/rackspace-cloud-essentials-2-creating-a-cloud-server

After doing so, you should have a new root user, the root user's password, and an IP address.

Next, launch Terminal and run the following command (using your server's IP address rather than 165.210.5.238):
ssh root@165.210.5.238
You'll be prompted with the following message:
The authenticity of host '165.210.5.238 (165.210.5.238)' can't be established.
RSA key fingerprint is 9a:7d:4r:25:1b:30:a9:39:ft:b2:a1:99:t9:52:z6:99.
Are you sure you want to continue connecting (yes/no)?
Enter the following word:
yes
You'll then be prompted with the following message:
Warning: Permanently added '165.210.5.238' (RSA) to the list of known hosts.
Perfect. After that you'll be asked for the root user's password via the following prompt:
root@165.210.5.238's password:
Enter it.

Next we're going to update the root user's password to something insane. We'll do so by entering the following command:
passwd
You'll be prompted to input your new, totally insane, root user password via the following prompt:
Enter new UNIX password:
You'll enter it. Then you'll be prompted again. You'll enter it again.

At this point you should start to feel awesome.

But not too awesome because we're running commands as root right now which isn't awesome. So, let's fix that. Time to create a new user.

Enter the following command (this tutorial uses 'admin' throughout but you can name your user whatever you want... like tim, jane, bob, or even tbone_smith):
adduser admin
You'll see the following output:
Adding user `admin' ...
Adding new group `admin' (1000) ...
Adding new user `admin' (1000) with group `admin' ...
Creating home directory `/home/admin' ...
Copying files from `/etc/skel' ...
You'll then be prompted to enter the new user's password via the following prompt (twice):
Enter new UNIX password:
You'll enter the new password (twice). You'll then be prompted for some additional information:
passwd: password updated successfully
Changing the user information for admin
Enter the new value, or press ENTER for the default
 Full Name []: 
 Room Number []: 
 Work Phone []: 
 Home Phone []: 
 Other []: 
If you're working out of a hotel room make sure to enter your room number. After answering all the questions above (whichever ones you want) you'll be prompted with the following:
Is the information correct? [Y/n]
Enter:
yes
Now that's pretty cool, but not that cool. Our new user can't do much unless we grant them sudo privileges. So enter the following command:
visudo
You'll notice a section near the middle of the file that matches:
# User privilege specification
root    ALL=(ALL) ALL
Add an additional line after root for your new user like so:
# User privilege specification
root    ALL=(ALL) ALL
admin   ALL=(ALL) ALL
Save the file.

Now we need to update our ssh config file. We're going to update our ssh port number to be non-standard, enable password authentication, and white label (allow) the user we just created. Let's kick off this bad-ass-ness by running the following command:
nano /etc/ssh/sshd_config
Find the lines (near the top) that match:
# What ports, IPs and protocols we listen for
Port 22
Update the digit 22 to be something highly random like 30062. Next, find the lines that match:
# Change to no to disable tunnelled clear text passwords
#PasswordAuthentication yes
Uncomment the 2nd line above to make it so we can ssh in to this machine using a password (you can set this directive to "no" later, after you get ssh keys set up). Save the file.

Now that's pretty bomb, but not that bomb. In order to go bomb-status we need to setup our software firewall using iptables. To get started run the following command:
nano /etc/iptables.test.rules
Then, copy and paste the following rules into your /etc/iptables.test.rules file:
*filter


#  Allows all loopback (lo0) traffic and drop all traffic to 127/8 that doesn't use lo0
-A INPUT -i lo -j ACCEPT
-A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT


#  Accepts all established inbound connections
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT


#  Allows all outbound traffic
#  You can modify this to only allow certain traffic
-A OUTPUT -j ACCEPT


# Allows HTTP and HTTPS connections from anywhere (the normal ports for websites)
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT


#  Allows SSH connections
#
# THE -dport NUMBER IS THE SAME ONE YOU SET UP IN THE SSHD_CONFIG FILE
#
-A INPUT -p tcp -m state --state NEW --dport 30062 -j ACCEPT


# Allow ping
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT


# log iptables denied calls
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7


# Reject all other inbound - default deny unless explicitly allowed policy
-A INPUT -j REJECT
-A FORWARD -j REJECT

COMMIT
We're basically accepting localhost traffic, outbound traffic, http, https, ssh (on our custom port), pings, and rejecting everything else.

Note: The above template is an exact copy of a SliceHost reference doc located at http://articles.slicehost.com/assets/2007/9/4/iptables.txt (with the exception of line 27 which you can see I've updated to match our highly random custom ssh port of 30062).

To apply this bomb-status-ness run the following command:
iptables-restore < /etc/iptables.test.rules
To review our work we can run the following command:
iptables -L
Which should output:
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            
REJECT     all  --  anywhere             loopback/8          reject-with icmp-port-unreachable 
ACCEPT     all  --  anywhere             anywhere            state RELATED,ESTABLISHED 
ACCEPT     tcp  --  anywhere             anywhere            tcp dpt:www 
ACCEPT     tcp  --  anywhere             anywhere            tcp dpt:https 
ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:30077 
ACCEPT     icmp --  anywhere             anywhere            icmp echo-request 
LOG        all  --  anywhere             anywhere            limit: avg 5/min burst 5 LOG level debug prefix `iptables denied: ' 
REJECT     all  --  anywhere             anywhere            reject-with icmp-port-unreachable 

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         
REJECT     all  --  anywhere             anywhere            reject-with icmp-port-unreachable 

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            
Pretty cool, right? Wrong! Well not totally wrong, we just need to save these rules as our default configuration and then wire them up so when we restart the server we don't lose them!

There are a few ways to go about this. You can either edit your interfaces file directly or create a special script that gets run when your network interfaces are started. I've been told the scripting approach is superior. I'll cover both approaches ("editing your interfaces file directly" first, "scripting" second).

With either approach, we begin by saving our rules to a file via the following command:
iptables-save > /etc/iptables.up.rules
Okay, if you'd like to edit your interfaces file directly, start by opening your network interface config file via the following command:
nano /etc/network/interfaces
The first 5 lines will be as follows:
# Used by ifup(8) and ifdown(8). See the interfaces(5) manpage or
# /usr/share/doc/ifupdown/examples for more information.
# The loopback network interface
auto lo
iface lo inet loopback
Add a sixth line right after 'iface lo inet loopback' that says:
pre-up iptables-restore < /etc/iptables.up.rules
Then, save the file. Now we won't lose our software firewall rules on reboot. Now that's pretty cool!

Okay, that concludes the "edit your interfaces file directly" approach. If you want to take the "scripting" approach (which, again, I've been told is a superior method), follow these steps:
nano /etc/network/if-pre-up.d/iptables
Add the following lines to the new file:
#!/bin/sh
/sbin/iptables-restore < /etc/iptables.up.rules
Save your changes, then make the new script executable:
chmod +x /etc/network/if-pre-up.d/iptables
Okay cool, now we won't lose our software firewall rules on reboot! Yay!

Alright, we're almost done with our root account and we're about to switch over to operating via our new admin user. Before we do that though, since we made changes to our ssh config file, we need to apply them. You can do so via the following command:
/etc/init.d/ssh reload
Now exit:
exit
Then, ssh back into the machine via our new admin user account using our custom ssh port:
ssh -p 30062 admin@165.210.5.238
And if you successfully connected to the machine... we can officially say, "Boom goes the dynamite".

We're done right? Wrong! It's time get down with some personal preference style settings in our bash config file (you can skip this step if you'd like). Start by running the following command:
nano ~/.bashrc
Then, find the following line:
#force_color_prompt=yes
Remove the # character, save the file, then reload your config file via the following command:
source ~/.bashrc
Boom. Your terminal prompt just got jacked! Well I don't even know exactly what that means but you'll notice your prompt is now printed in a fatty daddy green color which helps distinguish it from command output.

At this point you're probably whining like a little baby wondering if we're done yet. No!

Time to update our server so we're not running code that's like 40 thousands years old. To do this, run the following command:
sudo aptitude update
Next, we'll want to set up our region information. First, let's start with installing locales. Run the following command:
sudo aptitude install locales
After doing that, let's reconfigure it:
sudo dpkg-reconfigure locales
A blue screen should pop up. Select en_US.UTF-8 until you're back in your regular command prompt (should take two selections of en_US.UTF-8 to complete).

Next we're going to set up our timezone info:
sudo dpkg-reconfigure tzdata
A blue screen should pop up. I selected America then Chicago (since my server is in Chicago). After completing this step you'll see the following information printed to your screen:
Current default time zone: 'America/Chicago'
Local time is now:      Wed Apr 17 08:56:45 CDT 2013.
Universal Time is now:  Wed Apr 17 13:56:45 UTC 2013.
Now that we've updated our software listings from the repositories (in a previous step), it's time to run the actual upgrade (we'll do this via two commands starting with a safe upgrade first):
sudo aptitude safe-upgrade
You'll get prompted about disk usage (incoming file size) along the way. Say yes to these prompts. Once that's done we'll run the full upgrade:
sudo aptitude full-upgrade
Now we're pretty much done except for one thing. Let's install the build essential package to help resolve future dependencies... that is, unless you'd rather spend your time in dependency hell rather than getting barreled in some sick surf.
sudo aptitude install build-essential
Now das wassup! Our server is on lock down & ready to go! You now have proof that you're awesome!

Way to go!

Now that you've got your server set up and on lock down you may be interested in setting up the rest of the LAMP stack (Apache, MySQL, & PHP). If so, checkout a post I recently published that walks you through the process step by step: http://oneqonea.blogspot.com/2013/04/how-do-i-install-latest-versions-of.html

Final note: The vast majority of this tutorial was derived from a YouTube video by ckeck. So props there! Thx dude!

Thursday, April 11, 2013

What's the MySQL process/syntax for renaming a field that's wired up as a foreign key?

ALTER TABLE `your_referencing_table` DROP FOREIGN KEY `your_existing_fk_name`;
ALTER TABLE `your_referencing_table` CHANGE `existing_field_name` `new_field_name` INT( 11 ) UNSIGNED NULL DEFAULT NULL COMMENT 'fk';
ALTER TABLE `your_referencing_table` DROP INDEX `existing_index_name`, ADD INDEX `new_index_name` (`new_field_name`);
ALTER TABLE `your_referencing_table` ADD CONSTRAINT `your_new_fk_name` FOREIGN KEY (`new_field_name`) REFERENCES `your_existing_reference_table` (`your_existing_reference_table_field`) ON DELETE CASCADE ON UPDATE CASCADE;

What's the MySQL syntax for dropping a foreign key?

ALTER TABLE `your_referencing_table` DROP FOREIGN KEY `your_existing_fk_name`;

What's the MySQL syntax for adding a foreign key?

ALTER TABLE `your_referencing_table` ADD CONSTRAINT `your_new_fk_name` FOREIGN KEY (`your_referencing_table_field`) REFERENCES `your_foreign_table` (`your_foreign_table_field`) ON DELETE CASCADE ON UPDATE CASCADE;
Note that `your_referencing_table_field` must be indexed.

Wednesday, April 3, 2013

Wednesday, March 27, 2013

How do I enable or disable an apache virtual host?

To enable an apache virtual host run the following command:
sudo a2ensite example.com
To disable an apache virtual host run the following command:
sudo a2dissite example.com
Both of the examples above assume you're interested in enabling/disabling the site configured via the following file:
/etc/apache2/sites-available/example.com
Lastly, if you're interested in learning more about the a2ensite/a2dissite command, checkout the following notes:
#This manual page documents briefly the a2ensite and a2dissite commands.

#a2ensite  is a script that enables the specified site (which contains a
#<VirtualHost> block) within the apache2 configuration.  It does this by
#creating   symlinks   within   /etc/apache2/sites-enabled.    Likewise,
#a2dissite disables a site by removing those symlinks.   It  is  not  an
#error  to  enable  a  site  which is already enabled, or to disable one
#which is already disabled.

#The default site is handled specially: The resulting  symlink  will  be
#called 000-default in order to be loaded first.

Tuesday, March 26, 2013

How do I list all running processes and the amount of memory/cpu each is consuming on a linux machine?

First, start off by listing the processes that are running on your machine (i.e. their names). You can do so via the following command:
ps -e
After running the above command you'll see a list of running process and their names. Find the one you're interested in (or the one you think you're interested in) and then use its name in the following command:
ps -U www-data -u www-data u
In this case we used the name 'www-data'. You should see the instances of that process listed and the percentage of memory/cpu each is using.

Lastly, you may be wondering what the 'ps' command does (other than what you've observed here). If you run the following command, you can read all about it:
man ps
Lastly (again), the 'top' command is really awesome. It does the same stuff as the commands above but in real-time:
top

Saturday, March 23, 2013

What's the easiest way to get the latest version of ruby installed on my local *nix machine?

Using RVM (Ruby Version Manager). You can checkout the official site here: https://rvm.io/.

In short though, you can install ruby (and gems such as rails) via the following command:
curl -L https://get.rvm.io | bash -s stable --rails

Friday, March 22, 2013

How do I install a command line tool after uncompressing it?

First, you need to cd into the directory created as a result of uncompressing via tar. Something along the lines of:
cd path-to-software/
Once in the directory, run the following command:
./configure
"./configure" will configure the software to ensure your system has the necessary functionality and libraries to successfully compile the package.

If you're doing this on a Mac and you get a missing "c compiler" type error then you probably just need to install Xcode's command line tools package. To do so, simply open Xcode, go to preferences then downloads. There is an "Install" link to add the command line tools. Once this has been completed, make sure to re-open your terminal window.

Then run:
make
"make" will compile all the source files into executable binaries.

The purpose of the make utility is to determine automatically which pieces of a large program need to be recompiled, and issue the commands to recompile them.

Then run:
sudo make install
From the documentation, "make install" will copy the executable file into a directory that users typically search for commands; copy any auxiliary files that the executable uses into the directories where it will look for them (e.g. /usr/local/bin/).

Lastly, most software packages have a README or INSTALL file you should probably take a look at. You can do so by running the following command:
cat README

How do I uncompress a tarball?

To uncompress a tarball, execute the following command(s) depending on the extension:
tar zxf file.tar.gz
tar zxf file.tgz
tar jxf file.tar.bz2
tar jxf file.tbz2
The following doc snippets explain the tar options being used:
#Extract: tar -xf <archive-filename>
#-z, -j, -J, --lzma  Compress archive with gzip/bzip2/xz/lzma
Lastly, if you were to run "tar zxf file.tar.gz" you would end up with a new directory named "file" in your current directory.

Monday, March 18, 2013

How do I get and install a trusted SSL cert on a linux machine?

It starts with understand the basic pieces of the puzzle.

In SSL there's a concept of a "key pair". A "key pair" is composed of a "private key" and a matching "certificate signing request".

So, to get started, you need to create a private key. Yup, it's all you and it's as simple as running a single command. The private key is created via:
openssl genrsa -out www.yourdomain-example.com.key 2048
Then, after you've created your private key, you can proceed to creating your certificate signing request. Your "CSR" is created via:
openssl req -new -key www.yourdomain-example.com.key -out www.yourdomain-example.com.csr
This is the point in the process where you load your SSL cert with info about your company. You can read the following article if you have questions about what to enter for each prompt: https://knowledge.geotrust.com/support/knowledge-base/index?page=content&id=AR876

A public/private key pair has now been created. The private key (www.yourdomain-example.com.key) is stored locally on the server machine and is used for decryption. The public portion, in the form of a Certificate Signing Request (www.yourdomain-example.com.csr), will be used for certificate enrollment. System admins need to submit their www.yourdomain-example.com.csr files to a "trusted" signing authority such as VeriSign or GeoTrust. The trusted source will then respond with a related "public key". Information encrypted with a public key can only be decrypted with the corresponding private key, and vice-versa.

Okay cool, that makes sense and all but I've heard that intermediate certificates are involved too… What gives? Well, first things first, we should establish the purpose of an intermediate certificate. The purpose of an intermediate certificate is to provide maximum browser and server coverage to ensure visitors won't receive "invalid SSL" warnings when they visit your site. The "trusted sources" intermediate certificate bundle "chains" your SSL certificate to their trusted root certificates, letting your certificate secure connections with older browsers that might have only an old root certificate installed. So yes, you should be getting an intermediate certificate from your chosen certificate signing authority.

Installation of the cert depends on your web server software. Checkout the following GoDaddy support article that does a great job of describing how to install the cert depending on the web sever software you're working with here: http://support.godaddy.com/help/article/5346/installing-an-ssl-server-instructions?locale=en

What's the purpose of each directory in a standard linux install?

Run the following command:
man hier
and you'll have something like this that prints to your screen:
HIER(7)                                                                                                                Linux Programmer's Manual                                                                                                                HIER(7)

NAME
       hier - Description of the file system hierarchy

DESCRIPTION
       A typical Linux system has, among others, the following directories:

       /      This is the root directory.  This is where the whole tree starts.

       /bin   This directory contains executable programs which are needed in single user mode and to bring the system up or repair it.

       /boot  Contains static files for the boot loader.  This directory only holds the files which are needed during the boot process.  The map installer and configuration files should go to /sbin and /etc.

       /dev   Special or device files, which refer to physical devices.  See mknod(1).

       /etc   Contains  configuration  files  which  are local to the machine.  Some larger software packages, like X11, can have their own subdirectories below /etc.  Site-wide configuration files may be placed here or in /usr/etc.  Nevertheless, programs should
              always look for these files in /etc and you may have links for these files to /usr/etc.

       /etc/opt
              Host-specific configuration files for add-on applications installed in /opt.

       /etc/sgml
              This directory contains the configuration files for SGML and XML (optional).

       /etc/skel
              When a new user account is created, files from this directory are usually copied into the user's home directory.

       /etc/X11
              Configuration files for the X11 window system (optional).

       /home  On machines with home directories for users, these are usually beneath this directory, directly or not.  The structure of this directory depends on local administration decisions.

       /lib   This directory should hold those shared libraries that are necessary to boot the system and to run the commands in the root file system.

       /media This directory contains mount points for removable media such as CD and DVD disks or USB sticks.

       /mnt   This directory is a mount point for a temporarily mounted file system.  In some distributions, /mnt contains subdirectories intended to be used as mount points for several temporary file systems.

       /opt   This directory should contain add-on packages that contain static files.

       /proc  This is a mount point for the proc file system, which provides information about running processes and the kernel.  This pseudo-file system is described in more detail in proc(5).

       /root  This directory is usually the home directory for the root user (optional).

       /sbin  Like /bin, this directory holds commands needed to boot the system, but which are usually not executed by normal users.

       /srv   This directory contains site-specific data that is served by this system.

       /tmp   This directory contains temporary files which may be deleted with no notice, such as by a regular job or at system boot up.

       /usr   This directory is usually mounted from a separate partition.  It should hold only sharable, read-only data, so that it can be mounted by various machines running Linux.

       /usr/X11R6
              The X-Window system, version 11 release 6 (optional).

       /usr/X11R6/bin
              Binaries which belong to the X-Window system; often, there is a symbolic link from the more traditional /usr/bin/X11 to here.

       /usr/X11R6/lib
              Data files associated with the X-Window system.

       /usr/X11R6/lib/X11
              These contain miscellaneous files needed to run X;  Often, there is a symbolic link from /usr/lib/X11 to this directory.

       /usr/X11R6/include/X11
              Contains include files needed for compiling programs using the X11 window system.  Often, there is a symbolic link from /usr/include/X11 to this directory.

       /usr/bin
              This is the primary directory for executable programs.  Most programs executed by normal users which are not needed for booting or for repairing the system and which are not installed locally should be placed in this directory.

Thursday, March 14, 2013

When I create a new file or folder, what determines the default set of permissions?

Your environment's umask setting. Default is typically
umask 022
which results in directories and files getting created with 755 and 644 permissions respectively.

When I create a new file or folder, what determines the group that owns it?

The new file or folder will be owned by the same group that owns the directory that you're adding it to (tested on Mac OS X).

About Me

My photo
I code. I figured I should start a blog that keeps track of the many questions and answers that are asked and answered along the way. The name of my blog is "One Q, One A". The name describes the format. When searching for an answer to a problem, I typically have to visit more than one site to get enough information to solve the issue at hand. I always end up on stackoverflow.com, quora.com, random blogs, etc before the answer is obtained. In my blog, each post will consist of one question and one answer. All the noise encountered along the way will be omitted.

Blog Archive