Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Basic Ubuntu Web Dev Essentials


Recommended Editor:

From here on we'll use edit to denote the command that's meant to open the file in the editor. Replace edit with subl or atom as needed.

For Sublime Text

First Install [package control] ( and using package control (ctrl shift p + "install") add the following: "Git Gutter", "EditorConfig", "Babel", "CSS3"

Example Preferences / "Settings-User",

	"font_size": 9,
	"hot_exit": false,
	"remember_open_files": false,
	"trim_trailing_white_space_on_save": true,
	"word_wrap": false

Example Preferences / "Key Bindings - User"

	{ "keys": ["f2"], "command": "save" },
	{ "keys": ["f3"], "command": "copy" },
	{ "keys": ["f4"], "command": "paste" },
	{ "keys": ["f5"], "command": "cut" },
	{ "keys": ["alt+r"], "command": "find_all_under" }

The f* keys avoid hand strain problems. The alt r shortcuts is a primitive but extremely useful variable rename function.

Basic Tools

Increase inotify Limit

echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p

View Directory Structure

sudo apt-get install tree

Usage example, the structure of etc

tree -d /etc

It's generally useful to see structures in your project.

View Actual Useful Sizes

edit ~/.bashrc

Find the line,

alias ll='ls -alF'

And change it to

alias ll='ls -alFh'

The h will make sizes display in [h]uman readable format, instead of bytes.

Just use ll instead of ls -a, changing ls's default behavior is not advised.

Start in a Workspace

First create one,

mkdir ~/Workspace


edit ~/.bashrc

Add this at the end,

cd ~/Workspace

Case Insensitive Autocomplete

The system can be case sensitive but we really dont need this in our autocomplete, right?

Run the following two commands in the terminal,

if [ ! -a ~/.inputrc ]; then echo "\$include /etc/inputrc" > ~/.inputrc; fi
echo "set completion-ignore-case On" >> ~/.inputrc


File System Access Aliases

alias filesys="nautilus"
alias show="xdg-open"

Use the first to open any directory in the gui viewer. Use the second for opening files (eg. html files, etc) in the system default gui viewer.

Double-Line Prompt

By default the prompt looks something like this

your_name@computername:~/Workspace/some_project/subdir$ sudo service nginx restart

This can be annoying when you're working with very long directory structures. A solution is to just have the prompt be two lines, like so:

$ sudo service nginx restart

Arguably a bit easier to read too. To achieve this you'll need the following block:

if [ "$color_prompt" = yes ]; then
    PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\n\$ '
    PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\n\$ '

Find the block similar to the above in ~/.bashrc and replace them with the above. The block only adds line endings where required.

If you want a much lighter console, here's one with just username and path:

PS1='\e[0;33m\u\e[m \e[0;32m\w\e[m\nλ '

Replace second PS1 above.

For a eye catching prompt (useful when a lot of commands get executed in succession with long output), try the following:

PS1='\n\e[0;33m\u\e[m \e[0;32m\w\e[m$(__git_ps1)\n ◈ — '


curl -fsSL | sh

To be able to use docker with out sudo

sudo groupadd docker
sudo gpasswd -a ${USER} docker

You'll need to signout and log back in for above to take effect.

After installing docker you'll want to modify the docker service file to allow change the storage-driver to overlay; aufs won't work unfortunately--certain pacakages will cause it to completely break.

Edit the systemd unit file /etc/systemd/system/

Description=Docker Application Container Engine
Documentation= docker.socket

ExecStart=/usr/bin/docker daemon --storage-driver=overlay -H fd://

sudo systemctl daemon-reload
sudo systemctl restart docker
docker run hello-world


sudo apt-get install git

This won't be the latest bleeding edge version but good enough.

You will generally need to set up some variables now so just go to for a good list, recommend setting up ssh.

If you want the absolute latest git, (note: you probably don't!)

sudo add-apt-repository ppa:git-core/ppa
sudo apt-get update
sudo apt-get install git

May not support non-LTS. To remove ppa's add --remove to the add-apt-repository command.


To get nodejs run:

sudo apt-get install nodejs

To get the latest nodejs version run:

sudo apt-get install curl
curl --silent --location | sudo bash -
sudo apt-get install nodejs

To get latest npm run:

sudo apt-get install npm
sudo npm install npm -g

With just the above commands the node command is nodejs due to package conflicts. Assuming you don't care for the other node package, you can just symbolic link the nodejs executable to node for your purposes.

The location where the nodejs executable is placed can vary, use the following command to find where it's placed:

whereis nodejs

At the time of this writing it's placed in /usr/bin/nodejs (but it's been placed in the past in /usr/local/bin/nodejs so just check for yourself), assuming that's the location the command would be:

mkdir ~/bin
ln -s /usr/bin/nodejs ~/bin/node

If you still get the package not installed message, check PATH has ~/bin via echo $PATH and if it's missing add PATH=$PATH:~/bin to your ~/.bashrc

Yes you do NOT use sudo there, it's your local directory. You can also place it in /usr/bin but that may disrupt other users who may rely on the real node package instead of the nodejs package.


node --version
npm --version


sudo apt-get install nginx
sudo apt-get install mysql-server mysql-client

If you want php5.* use the following,

sudo apt-get install php5-fpm php5-cli
sudo apt-get install php5-json php5-mysql php5-curl php5-imagick
sudo apt-get install php5-xdebug

For php7.0 use the following,

sudo apt-add-repository ppa:ondrej/php
sudo apt-get install php7.0 php7.0-fpm php7.0-mysql -y
sudo apt-get install php7.0-json php7.0-curl php7.0-xml php7.0-mbstring -y

As shown above for json and mysql for installing php extensions you want the packages with the php5- prefix.

You may wish to install composer as well,

curl -sS | php
sudo mv composer.phar /usr/local/bin/composer

You may be asked to install curl


On systemd systems you can just run,

sudo systemctl status php7.0-fpm nginx mysql
php -v && composer --version

On older systems and when using older php versions,

sudo service nginx restart
sudo service mysql restart
sudo service php5-fpm restart
sudo nginx -t
php -v
composer --version

Depending on Ubuntu version you may see a confirmation message such [OK] or nothing at all in case the system just redirects to systemd; either way you'll get an error message if something went wrong.

Local Server

Create basic structure,

mkdir -p ~/server
cd ~/server
ln -s /etc/nginx/sites-enabled
ln -s /var/log/nginx logs

Its recommended you don't redirect logs from default locations. Use the logs directory only for extra logs you request on the servers. eg. mysql slow query log

Create a custom default site,

edit ~/server/sites-enabled/

The contents of the site configuration should be,

server {
	listen 80 default_server;

	client_max_body_size 10M;
	include mime.types;

	location / {
		root /home/YOURNAME/Workspace/projekt/syspath/stage;
		index index.php index.html;
		try_files $uri $uri/ /index.php?$args;

	location ~ \.php$ {
		include fastcgi_params;
		fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
		# OR if php5
		# fastcgi_pass unix:/var/run/php5-fpm.sock;
		fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
		fastcgi_split_path_info ^(.+\.php)(/.+)$;
		fastcgi_index index.php;

Excluding the "default_server" in the "listen 80 default_server;" rule, the configuration applies to just about every site; obviously change the name.

To make it work you also have to redirect to your hosts, so browsers will send you to your local server. So long as each site is named different nginx will direct the request to the right server.

For every site you should add an entry as the following to your hosts file, which you can access directly with sudo edit /etc/hosts,

If you are the only user of the machine, and if you properly installed the OS (ie. chose to mount /home on a separate partition) then you can save yourself a lot of hassle by "moving" the /etc/hosts file to your home directory.

cp /etc/hosts ~/hosts 
sudo rm /etc/hosts
sudo ln -s ~/hosts /etc/hosts 
sudo chown root:root ~/hosts

An alternative is to use dnsmasq to tell the system all subdomains of a given fake domain name should route to, this avoids the need of editing the hosts file.

sudo apt-get install dnsmasq
sudo echo "address=/" >> /etc/dnsmasq.conf
sudo systemctl restart dnsmasq

Now something like will automatically route to your nginx server on

Every time you add a new site don't forget to check your config for errors,

sudo nginx -t

...and restart nginx (in production you should just use reload)

sudo systemctl restart nginx

One last piece of advice, avoid code from nginx "tutorials." If you copy/paste anything make sure you know EXACTLY what it does because all that most toturials do is give you overly complicated unlegible server code rather then anything useful. Most of the time the code in question isn't even correct and is just a misinterpretation of nginx though the knowhow from working with other servers. Rule of thumb: if it looks too complicated, it's not correct nginx configuration

Installing phpmyadmin

sudo apt-get install phpmyadmin

In the promps use TAB key to skip the server selection. Let it configure the database when it prompts you. For root password and every other password just enter "root"

Once that's done you can use the following nginx site config to get up and running with it,

server {

	root /usr/share/phpmyadmin;
	listen 80;

	client_max_body_size 10M;
	include mime.types;

	location / {
		index index.php index.html;
		try_files $uri $uri/ /index.php?$args;

	location ~ \.php$ {
		fastcgi_split_path_info ^(.+\.php)(/.+)$;
		fastcgi_index index.php;
		fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
		# OR if php5
		# fastcgi_pass unix:/var/run/php5-fpm.sock;
		fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
		include fastcgi_params;


Replace YOURUSERNAME with your actual username. Why not use localhost? Because this way any of your coworkers can add your ip and the hostname in question and they'll have access to your local version though the local network; its' very useful. Note that for the server_name you can use a shorter name if your actual username is very clunky, it doesn't have to be the same so long as it's unique.

Installing PHP Tools

The best way to install/update and keep track of your php tools is to use composer and have it install binaries to your ~/bin directory.

cd ~/Workspace
mkdir phptools
cd phptools
edit composer.json

In composer.json write:

	"config": {
		"bin-dir": "/home/YOUR_USERNAME/bin"

	"require": {
		"ext-xml"                     : "*",
		"behat/behat"                 : "2.4@stable",
		"behat/mink-extension"        : "*",
		"behat/mink-goutte-driver"    : "*",
		"behat/mink-selenium2-driver" : "*",
		"phpunit/php-code-coverage"   : "*",
		"phpunit/phpunit"             : "4.5.*",
		"phpunit/dbunit"              : "*"

Then just run,

composer install

The example installs basic phpunit and behat support, but you can add anything you wish.

In the future you can run composer update to check for updates, you can also change the versions or add new tools and run composer update to get everything back up. If you have a good setup you can share composer.json with someone else to give them the exact toolchain you're using.

Managing Unix Access Hell

Never use octal syntax, ie. chmod 0770 thedir/, simple problem with this syntax chmod fails at distinguishing with files and dirs so almost always when you try to use the syntax you end up with exactly what you didn't want.

FYI, the non-octal syntax is shorter!

But before going to into chmod magic changing ownership solves a lot of problems most of the time, the following,

sudo chown -R YOURUSERNAME:www-data project/

Will change all files to you as owner and www-data as the group; www-data is the default group for nginx.

Learning chmod flags,

  • u = owner
  • g = group
  • o = others

The permissions flags r (read), w (write) and x (execute) are fairly self explanatory, a nice flag that's not obvious is X (execute on directories).

# set execute for owner
chmod u+x thefile

# set execute for owner and group
chmod ug+x thefile

# set execute for owner and group, remove execute from others
chmod ug+x,o-x thefile

# set execute for owner, remove from group and others
chmod u+x,go-x thefile

# same as above, the -c tells chmod to display files when it's affected
chmod -c u+x,go-x thefile

# same as above bur do recursively (-R flag)
chmod -cR u+x,go-x somedir

# same as above but changes write rights as well
chmod -cR u+wx,go-wx

In general for server files you'll set,

chmod -cR ug+wr,o+r,o-w,ugo-x,ugo+X serverfiles

If you need to be really precise with directory and file permissions,

find serverfiles/ -type d -exec chmod -c ug+rwX,o+rX {} \;
find serverfiles/ -type f -exec chmod -c ug+rw,o+r {} \;

WORD OF WARNING, above I've used "serverfiles" but be careful of touching files you do not fully control yourself, such as .git files. This is why it's generally useful to have all your sources in a src/ directory with other junk (vendor files, .git files, etc) next to it rather then it, if you have one then serverfiles above would be your src directory.

Recommended reading:

Creating a permission fix script

Let's assume you have a project. Lets also assume there is also a console script on the root of the project that needs to be executed, aside from the user, some crons and that there are also some tools (install, update, etc). A repair script that can automatically fix permission errors, including owner issues, would look something like this:

#!/usr/bin/env sh

# fix owner for files
sudo chown -c `whoami`:www-data -R .

# purge any setuid setgid bits (s) and sticky bits (t)
echo "Purging setuid, setgid and sticky bits"
find . -exec chmod a-st {} \;

# all files have owner/group read/write and only read for others
echo "Resetting file permissions"
find . -type d -exec chmod ug=rwx,o=rx {} \;
find . -type f -exec chmod ug=rw,o=r {} \;

# most tools should only be executed by owner
echo "Resetting tool scripts"
chmod u=rwx,go=r repair check install update
chmod u=rwx,g=rx,o=r console

You can now run ./repair (do NOT use sudo with it!) to fix the project. The whoami blocks will automatically fill in the current user.

If you're using apache then the group there should be apache instead of www-data or whatever you set as the user/group for your server to use.

Obviously this is only useful for fixing the aftermath of a permission errors; it's not a solution to any script that caused the error to begin with.

Access to group files

It's probably a good idea to add yourself to the server group so you don't encounter issues when the group creates things like log files

sudo usermod -a -G www-data YOURUSERNAME

The -a specifies "append" and is very important; omitting it may remove you from the "sudo" group preventing you from running commands with sudo!!

Making windows open in "Always on Visible Workspace"

sudo apt-get install compizconfig-settings-manager
sudo apt-get install compiz-plugins

In search type "Window Rules" (enable it and open it)

In the sticky field add the following rule:

class=Gnome-terminal | class=Pidgin | (class=Google-chrome-stable & !(role=pop-up)) | class=Thunderbird

Log off and back in. If that doesn't apply it try restart (it can be a bit iffy).

This will make terminals, pidgin, chrome windows (except inspector windows) and thunderbird windows stay in "Always on Visible Workspace" mode. It's a bit annoying since you can't actually unset this manually, it's a forced state, so careful what you put in there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment