What is the best workaround for the 20 field history tracking cap?

Create an object called AccountHistoryTracking and fields like APIName__c,OldValue__c,NewValue__c then create a fieldset on Account called'HistoryTracking' with the fields you want to track on Account and then write below code to track history on account.This way you don't need to worry about history tracking limit per object.

trigger AccountHistoryTracker on Account (after update) {

    final List<Schema.FieldSetMember> trackedFields = 
        SObjectType.Account.FieldSets.HistoryTracking.getFields();

    if (trackedFields.isEmpty()) return;

    final List<AccountHistoryTracking__c> fieldChanges = 
        new List<AccountHistoryTracking__c>();

    if(!trigger.isUpdate)
        return;

    for (Account newAccount : trigger.new) {

        final Account oldAccount = trigger.oldmap.get(newAccount.Id);

        for (Schema.FieldSetMember fsm : trackedFields) {

            String fieldName  = fsm.getFieldPath();
            String fieldLabel = fsm.getLabel();

            if (newAccount.get(fieldName) == oldAccount.get(fieldName))
                continue;

            String oldValue = String.valueOf(oldAccount.get(fieldName));
            String newValue = String.valueOf(newAccount.get(fieldName));

            if (oldValue != null && oldValue.length()>255) 
                oldValue = oldValue.substring(0,255);

            if (newValue != null && newValue.length()>255) 
                newValue = newValue.substring(0,255); 

            final AccountHistoryTracking__c accountHistory = 
                new AccountHistoryTracking__c();

            accountHistory.name         = fieldLabel;
            accountHistory.apiName__c   = fieldName;
            accountHistory.User__c      = newAccount.Id;
            accountHistory.ChangedBy__c = UserInfo.getUserId();
            accountHistory.OldValue__c  = oldValue;
            accountHistory.NewValue__c  = newValue;

            fieldChanges.add(accountHistory);
        }
    }

    if (!fieldChanges.isEmpty()) {
        insert fieldChanges;
    }
}

@sfdc's method will consume a lot of Data Storage -- and that's expensive!

Do what @sfdc said but store the data in JSON in a Long Text Area Field on the record. Then build a Visualforce Page that displays the JSON in a readable way.