Bitnami LAMP VM (Debian 9) on VirtualBox, macOS host


This is a setup I use for development environments, not recommended for production!

Basic VM Install

  • Download OVA file from (version used: PHP 7.1.16-0 64-bit)
  • In VirtualBox file menu, import appliance (OVA file) & start it
  • Wait until coloured screen appears
  • Login with bitnami / bitnami
  • Set a new password
  • Root access: $ sudo su
  • Shutdown: $ sudo init 0

Tweak VM resources

By default resources allocated to the VM are quite scarce. Depending on the use it will have and the resources on your host machine you may want to increase them. My setup includes:

  • all available CPUs at 80% for better performance
  • 1 or 2 GB of RAM
  • 8 MB of video memory (there's no GUI)

Stop the VM for adjusting them.

Configure VM network

This is a server for local development/testing so we just need it to be accessible from the host machine. Additionally we may need it to access the internet. Reference.

bridged mode

With this mode the VM can communicate in all directions. Limitation: the virtual adapter needs to be attached to a physical WiFi (AirPort) adapter. Configure this mode in the VM's Settings - Network - Adapter 1.

host-only adapter

If you don't need the VM to access the internet you can configure it in this way.For that we need to create a host-only adapter. In Global Tools - Host Network Manager create one with default parameters & enable DHCP. The first one gets by default the name vboxnet0 and the IP range 192.168.56.x. Then in VM's Settings - Network - Adapter 1 select Host-only adapter and vboxnet0.

Verify it works


Access the VM from the macOS terminal

I find it convenient to have SSH enabled so I can access the VM from a terminal Window. Partly because without GUI the default console is very limited: no window resize, no clipboard integration...


$ sudo rm -f /etc/ssh/sshd_not_to_be_run
$ sudo systemctl enable ssh
$ sudo systemctl start ssh
$ sudo ifconfig | grep 192
... inet 192.168.x.x ...


latest command above shows the local IP of the VM, use it to connect to it:
ssh bitnami@192.168.x.x

    Install VirtualBox Guest Additions

    This is optional but quite convenient in a development setup. Specifically I use the shared folders feature with the host so changes in code I make on macOS are immediately available within the VM.

    • In Settings - Storage add a new CD device to the existing controller and leave it empty
    • Start the VM

    Install dependencies

    Find out then Linux kernel version, it's the third column, "4.9.0-6-amd64" in this case:

    bitnami@debian:~$ uname -a
    Linux debian 4.9.0-6-amd64 #1 SMP Debian 4.9.82-1+deb9u3 (2018-03-02) x86_64 GNU/Linux

    the default DNS resolver was not working so I had to fix it using a Google's one.

    $ sudo vi /etc/resolv.conf
    $ sudo apt-get -y install dkms build-essential linux-headers-4.9.0-6-amd64
    $ sudo reboot

    Install Guest Additions

    Once the login prompt appears, insert the Guest Additions CD image (devices menu). Then mount & execute:

    $ sudo mkdir /mnt/cdrom
    $ sudo mount /dev/cdrom /mnt/cdrom
    $ cd /mnt/cdrom
    $ sudo sh ./ --nox11

    Check if running:
    bitnami@debian:/mnt/cdrom$ ps -ef | grep VBoxService | grep -v grep
    root 5447 1 0 11:46 ? 00:00:00 /usr/sbin/VBoxService --pidfile /var/run/

    $ sudo umount /dev/cdrom
    $ init 0

    Configure any shared folders (normally with auto-mount), start the VM, check folders are mounted:
    $ mount | grep media
    $ sudo ls /media/*

    User access to shared folders
    e.g. allow bitnami user R/W access to VB shared folders
    $ sudo usermod -a -G vboxsf bitnami

    Enable phpMyAdmin for private IPs

    Bitnami docs instruct to use an ssh tunnel to access phpMyAdmin, but I prefer to just allow access from the local network.

    $ vi /opt/bitnami/apps/phpmyadmin/conf/httpd-app.conf

    replace: Require local by Require ip 192.168

    $ /opt/bitnami/ restart apache

    Verify it works: http://192.168.x.x/phpmyadmin/

    Install WordPress module

    Following this guide:

    Obtain the module download URL from

    $ cd
    $ pwd
    $ cat bitnami_credentials
    *** contains MySQL root password used below ***
    $ exec sh /opt/bitnami/use_lampstack
    $ curl --remote-name --location
    $ chmod +x ./
    $ sudo ./
    installer asks for the following data:
    • language
    • Installation folder: /opt/bitnami
    • WP admin account data
    • MySQL "root" password (see above)
    • Blog name
    • mail support/SMTP Settings so your application can send notifications via email.  Either GMail or in my case "Custom":
      • Username
      • Password
      • SMTP Host 
      • SMTP Port [587]
      • Secure connection: None /SSL/TLS
    • Development o production environment
      Verify it works: http://192.168.x.x/applications.html

      Bitnami LAMP on CentOS 7.4


      • CentOS 7.4 default image on Digital Ocean, entry level plan, with 1 GB RAM


      local$ ssh root@SERVER_IP


      add swap if RAM+swap is less than 2 GB
      this is a short version of these two guides: Bitnami low memory & Digital Ocean swap guide

      # free -m | grep Swap
      Swap: 0 0 0
      # dd if=/dev/zero of=/swapfile count=1024 bs=1MiB
      # chmod 600 /swapfile
      # ls -lh /swapfile
      -rw-------. 1 root root 1.0G Jan 19 19:05 /swapfile
      # mkswap /swapfile
      Setting up swapspace version 1, size = 1048572 KiB
      no label, UUID=ed94f556-38a2-43de-a64b-a3829e85dbd0
      # swapon /swapfile
      # free -m | grep Swap
      Swap: 1023 0 1023
      # sysctl vm.swappiness=10
      vm.swappiness = 10
      # echo "/mnt/swap.0 swap swap defaults 0 0" >> /etc/fstab
      # reboot

      # free -m | grep Swap
      Swap: 1023 0 1023


      The MySQL installer requires perl and the perl Data::Dumper module.

      # yum install perl perl-Data-Dumper
      # perl

      create regular user

      # adduser lampy
      # passwd lampy
      # su lampy
      $ cd
      $ pwd

      Default install

      $ curl --remote-name --location
      $ chmod +x
      $ ./
      The installer warns about low memory (0.92GB instead on 1) but as the difference is minimal and we have increased the swap it is safe to continue.

      Then it asks optional components to install. Except phpMyAdmin which is always installed, the rest are optional if you just want to install WordPress (later).

      Installation folder. Accepted default /home/lampy/lampstack-7.1.15-0

      Finally it requires a password for the MySQL root user.

      Essential commands

      • Start servers (other options: restart, stop, status)
      $ /home/lampy/lampstack-7.1.15-0/ start
      • Uninstall:
        • $ /home/lampy/lampstack-7.1.15-0/uninstall
          $ rm -rf /home/lampy/lampstack-7.1.15-0/
        • you may need to do it if there was some problem with the installation, before trying to install again.

      Verify it works

      http://SERVER_IP:8080 should show Bitnami's "wellcome" page

      Start on boot

      # cp /home/lampy/lampstack-7.1.15-0/ /etc/init.d/bitnami-lamp
      # vi /etc/init.d/bitnami-lamp

      # chkconfig: 2345 80 30
      # description: Bitnami services


      # chkconfig --add bitnami-lamp
      # reboot

      ...then verify servers have started and pre-packaged apps work.

      Bitnami Tomcat 8.5 - native macOS installation cheatsheet


      Default install

      • location of apps/sites installed by default: /Applications/bitnami-tomcat/apache-tomcat/webapps/
        • docs/
        • examples/
        • host-manager/: Tomcat Virtual Host Manager
        • manager/: Tomcat manager above
        • ROOT/: Bitnami index page & default Tomcat site above

        Install own app

        The guide above has a paragraph "How To Create A Custom Java Application?". That didn't work for me. Instead, much simpler to drop the app's war file to /Applications/bitnami-tomcat/apache-tomcat/webapps/

        • E.g. you can try with this "hello world" app. You don't even need to restart any server for this one. Otherwise use BAM.

        Installing Ethereum's geth on macOS

        A quick guide of what worked for me. 

        Geth is the official implementation that allows you to run an Ethereum node. There are several others.

        I installed it with Homebrew based on the official geth guide for macOS.

        Homebrew installation:

        $ su admin
        $ /usr/bin/ruby -e "$(curl -fsSL"

        Geth installation:

        $ su admin
        $ brew tap ethereum/ethereum
        $ brew install ethereum

        Verify (as regular user):

        $ geth
        • wait for message "Starting P2P networking"
        • interrupt (Ctrl-C)
        • check that there are no obvious errors

        Setting up an Ethereum node on the Rinkeby testnet

        Warning: this worked for me on macOS as of August 2017. Over time you can expect some/most/all of the information here to have changed.

        There are several testnets, a number of them old/deprecated. The latest seem to be Kovan and Rinkeby. Kovan seems to work only with Parity while Rinkeby seems to work only with geth.

        You will need to install geth first.

        I mostly followed this guide.

        I tried first the experimental light mode but I got errors, so I tried with the full mode. Not a big deal at this moment because the size on disk is below 1GB and it took around one hour to download/build with a 2011 macbook Air.

        I prefer to make the data directory explicit (where the blockchain files will be stored), so I first create one on a disk of my choice. Also I will work from that directory, so I will assume all commands are entered from it.

        $ mkdir /path/to/rinkeby
        $ cd /path/to/rinkeby

        intitalise with genesis block

        $ curl -O $ geth --datadir=. init rinkeby.json

        load blockchain 

        $ geth --networkid=4 --datadir=. --ethstats='yournode:Respect my authoritah!' --bootnodes=enode://a24ac7c5484ef4ed0c5eb2d36620ba4e4aa13b8c84684e1b4aab0cebea2ae45cb4d375b77eab56516d34bfbd3c1a833fc51296ff084b770b94fb9028c4d25ccf@ --cache=1024

        Wait. You will see the INFO message "Block synchronisation started" then many INFO lines starting with "Imported...". Sync is in progress... 

        • Note the 1GB cache, you can use less or more depending on your available memory
        • Network id 4 corresponds to the Rinkeby chain
        • Blockchain data will be stored in geth/

        Check blockchain sync progress

        While the node is up & running (the above command) you can get info about the blockchain sync progress (among other data) through the JavaScript console. In another terminal window type:

        $ cd /path/to/rinkeby
        $ geth attach ipc:geth.ipc

        At the ">" prompt you can type, e.g.

        > eth
        > eth.syncing
        > adm
        > adm.peers

        You can double check you are seeing the right data progress by looking at the last block at home page.

        Note that the "NOTE...Importing..." messages include a number parameter which is the block being processed.

        Getting free (worthless) ether for testing

        Create a testing account

        Create an account, enter password, get its address (account data will be saved to keystore/):

        $ geth --datadir=. account new
        ...(enter password):..
        Address: {559b0e5a899d9ef4c04ee35ccbefab2e6d7f06da}

        That is the address I got. In order to use the faucet & get ether into this account, first create a github gist with just the hash in it (remember to prepend with "0x"). In my case:

        Now use your gist URL in the faucet feature at

        I requested 3 ETH, then I searched etherscan with my address to verify I got them:

        Next verification step would be to verify that locally we also get the correct balance.

        We first verify it is taking the accounts we created (files in keystore/)

        > eth.accounts
        ["0x559b0e5a899d9ef4c04ee35ccbefab2e6d7f06da", "0x62c8681441620cb0574fcee27d6085529067b8da"]

        The first one (index 0) is the one I got my 3 ETH, let's see if they are on our local blockchain (balance for account 0):

        > web3.fromWei(web3.eth.getBalance(web3.eth.accounts[0]));


        Now we may keep using geth, or a wallet for a nice UI.