Never Run Out of Space in SugarCRM or SuiteCRM using Block Storage on Digital Ocean

One issue that comes up occasionally for people hosting their own SugarCRM or SuiteCRM instance is running out of storage on their server. SugarCRM and SuiteCRM by default use a directory called ‘upload’ located in the root of your instance to store all file attachments. This tutorial will show you how to change this setting to another drive using Digital Ocean’s new block storage volumes.

Digital Ocean Droplet


Looking at Digital Ocean’s droplet pricing (as of October 2016) we see you get quite a bit of power with SSD speed in a $10-$40 per month VPS. For many applications, including SugarCRM and SuiteCRM, the stock storage of the VPS is sufficient. However, if your company works with large documents or uses an add-on from Sugar Outfitters to synchronize with a service like Box or Google Drive that storage can be used up quickly. While it is easy to upgrade to a higher sized droplet on Digital Ocean this can get pretty expensive quickly.


A new feature on Digital Ocean that solves this problem is called Block Storage where you can quickly add SSD storage to your VPS without having to upgrade to a higher sized droplet. This is a much less expensive option and allows you to quickly expand storage as requirements change. Below you can see the block storage pricing for Digital Ocean (as of October 2016). Let’s walk through the steps on how to change the storage location on your SugarCRM or SuiteCRM instance to a Digital Ocean Block Storage Volume.
Digital Ocean Block Storage Pricing


There are detailed instructions on how to install SugarCRM and SuiteCRM so this tutorial assumes you already have an up and running server with either SugarCRM or SuiteCRM installed. The instruction for adding block storage are identical for either platform.

Creating and attaching block storage


Log into your Digital Ocean account and click on the droplet you want to add storage to.

Click on Volumes from the options on the left and then click the ‘Add Volume’ button.

screen-shot-2016-10-16-at-10-19-06-pmNext you want to select the volume size you would like and name the volume. In this example we named this volume ‘crm-storage’. This is naming is completely up to you so use your own convention but remember to replace that name if you copy any commands below.


Creating the volume is quick and once complete you will see a popover listing the commands to mount the volume on your VPS. Below are the commands for this example. Note I have highlighted the volume name in red. I have also chosen to keep the same name on the server as the Digital Ocean interface. This is by no means required but may help if you have multiple volumes attached to one droplet. If you want a different name you would replace the highlighted red text after /mnt.

$ sudo mkfs.ext4 -F /dev/disk/by-id/scsi-0DO_Volume_crm-storage
$ sudo mkdir -p /mnt/crm-storage
$ sudo mount -o discard,defaults /dev/disk/by-id/scsi-0DO_Volume_crm-storage /mnt/crm-storage
$ echo /dev/disk/by-id/scsi-0DO_Volume_crm-storage /mnt/crm-storage ext4 defaults,nofail,discard 0 0 | sudo tee -a /etc/fstab

Now your volume is ready to use on your droplet. You can test that your new storage by logging into the droplet via SSH and creating a test file and reading it.

echo 'Hello, I exist' > /mnt/crm-storage/test.txt
$ cat /mtn/crm-storage/test.txt

In this example let’s create a directory for our production instance just in case you have a test environment set up that you would like to also store documents on the added volume. You also need to make sure the webserver user has write permissions to this directory just like you would if you were using the ‘upload’ of your CRM instance.

$ mkdir /mnt/crm-storage/production
$ sudo chown -R www-data:www-data /mnt/crm-storage/production
$ sudo chmod -R 775 /mnt/crm-storage/production

Using your favorite text editor edit the file named config_override.php located in the root directory of your instance. Add the following line and save the file. Just a reminder to change the names of the drive and or directory to follow what you have set up previously.

$sugar_config['upload_dir'] = '/mnt/crm-storage/production';


Now let’s create a Note with an attachment in the application to test. Log into your instance and create a Note with any attachment from your computer.


Create Note w/ Attachment


To see that the file was indeed stored on the new volume instead of the ‘uploads’ directory enter the following command into your terminal window.

$ ls /mtn/crm-storage/production

If everything was successful you should see something like ’26fde971-9465-2163-2c1d-5804565c552a’. This is normal as both SugarCRM and SuiteCRM store files as their unique id on disk and associates the filename in the database.

Lastly if you already have documents on your instance’s uploads directory those need to be moved to the new volume or you won’t be able access them.

$ cd <instance directory>/upload

$ mv * /mnt/crm-storage/production

I hope this tutorial is instructive and please add a comment if you have any questions corrections.  Also feel free to contact me directly if you prefer:

Shad Mickelberry



SugarCRM 7 Hide Completed Activities in Calendar

Early on when my company started with SugarCRM CE there was no option to hide completed activities in the Calendar so I followed this tutorial to change Calls/Meetings with status = Held and Tasks with status = Complete to background color = white. A later upgrade, I beleive 6.5.13, made this unnecessary with an added checkbox for hiding these items.

This worked well on our instance because we controlled the upgrades and I knew to update the files because the tutorial is not upgrade safe. We recently upgraded from SugarCRM CE 6.5.xx to Enterprise 7.6.  During our launch week I realized that the hide completed activities setting no longer existed. Additionally, we are on an On-Demand environment so the upgrades are controlled by SugarCRM so I wanted a different way.

Doing an inspect element in Chrome I noticed the div of an item, a Task in this case,  on the Calendar had this format:

 <div id="c51fbfab-5017-a40e-c307-55ef7dccc23b" class="act_item task_item" record="c51fbfab-5017-a40e-c307-55ef7dccc23b" module_name="Tasks" status="Not Started" detail="1" edit="1" duration_coef="1" style="border-color: rgb(1, 89, 0); height: 14px; top: -1px; left: -2px; width: 46%; background-color: rgb(177, 245, 174);"><div class="head"><div class="adicon" id="div_c51fbfab-5017-a40e-c307-55ef7dccc23b"></div><div>Expenses Update</div></div><div class="content" style="display: none;">Not Started</div><div class="content" style="display: none;"></div></div> 

Attempt 1 – Failed:

Noticing the ‘status’ attribute in the div this seemed like a pretty straight forward issue perhaps with some jQuery like:

 $('div[status="Held"]').css('display', 'none');

would do the trick but the activities weren’t affected. Just modifying a general <div> worked but not with referencing the status attribute.

Attempt 2 – Failed:

Next I tried adding some css by creating a file /custom/themes/custom.less with:

 div[status="Held"], div[status="Completed"] {
 display: none;

I saw the file in the browser editor with the syntax I wanted but still nothing was happening. I changed the file to:

 div {
 background-color: red;

This only changed the navigation bar and the footer to have background color of red. I don’t know why this was the case. Perhaps the order of page load?

Attempt 3 – Success: 

I knew the css worked as I had tested it in the editor. So I used a after_ui_footer global logic hook to include the css file when on the Calender page.


if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
class CalendarLogic
 function displayCalendarCss ($event, $arguments)
 {if (!isset($_REQUEST["to_pdf"]) && $_REQUEST['module'] == 'Calendar') {echo 'link rel="stylesheet" href="custom/modules/Calendar/Cal.css"/';}}

Please note the opending < and closing > for the link tags were removed in this post.



div[status="Held"], div[status="Completed"] {
 display: none;

This worked in testing but it took me a bit to get this packaged properly for testing but I finally got it.

Download the package below.

Hide Completed Activities Calendar Package

Perhaps a better way would be to override the calendar get activities to prevent the completed tasks from being included in the first place but I wasn’t having any luck overriding the base calendar functions.