How to host google web fonts on my own server?
Asked Answered
E

13

292

I need to use some google fonts on an intranet application. The clients may or may not have internet connection. Reading the license terms, it appears that its legally allowed.

Enidenigma answered 23/1, 2012 at 2:52 Comment(0)
A
232

Please keep in mind that my answer has aged a lot.

There are other more technically sophisticated answers below, e.g.:

so don't let the fact that this is the currently accepted answer give you the impression that this is still the best one.


You can also now also download google's entire font set via on github at their google/font repository. They also provide a ~1GB zip snapshot of their fonts.


You first download your font selection as a zipped package, providing you with a bunch of true type fonts. Copy them somewhere public, somewhere you can link to from your css.

On the google webfont download page, you'll find a include link like so:

http://fonts.googleapis.com/css?family=Cantarell:400,700,400italic,700italic|Candal

It links to a CSS defining the fonts via a bunch of @font-face defintions.

Open it in a browser to copy and paste them into your own CSS and modify the urls to include the right font file and format types.

So this:

    @font-face {
      font-family: 'Cantarell';
      font-style: normal;
      font-weight: 700;
      src: local('Cantarell Bold'), local('Cantarell-Bold'), url(http://themes.googleusercontent.com/static/fonts/cantarell/v3/Yir4ZDsCn4g1kWopdg-ehHhCUOGz7vYGh680lGh-uXM.woff) format('woff');
    }

becomes this:

    /* Your local CSS File */
    @font-face {
        font-family: 'Cantarell';
        font-style: normal;
        font-weight: 700;
        src: local('Cantarell Bold'), local('Cantarell-Bold'), url(../font/Cantarell-Bold.ttf) format('truetype');
    }

As you can see, a downside of hosting the fonts on your own system this way is, that you restrict yourself to the true type format, whilst the google webfont service determines by the accessing device which formats will be transmitted.

Furthermore, I had to add a .htaccess file to my the directory holding the fonts containing mime types to avoid errors from popping up in Chrome Dev Tools.

For this solution, only true type is needed, but defining more does not hurt when you want to include different fonts as well, like font-awesome.

#.htaccess
AddType application/vnd.ms-fontobject .eot
AddType font/ttf .ttf
AddType font/otf .otf
AddType application/x-font-woff .woff
Anam answered 2/11, 2012 at 15:2 Comment(14)
You're not restricted to TrueType, you just need to download the .woff files as well, ie. put 'http: //themes.googleusercontent.com/static/fonts/cantarell/v3/...80lGh-uXM.woff' into your web browser, save it as '/fonts/Cantarell-Bold.woff' and update the css to match (url('/fonts/Canterell-Bold.woff'))Pyoid
There's a reason why Google provides several font formats - TrueType doesn't work on old browsers. WOFF is the W3C standard.Annulment
The file changes content depending on the browser being used.Lenticular
This response is more complex to deploy than the alternatives listed below; it is also technically incorrect in several respects (no limitation to TTF, TTF is a bad idea, this will yield different results per browser, you can't host fonts anywhere public since same-origin applies). Please don't do that, use one of the other answers below.Percaline
@RobinBerjon Could you please reference the technically better approaches? I would like to link to them in my answer as this is rather high-voted and won't come down soon.Anam
Can you add @DamirBulic answer to the list? He created very nice tool.Enliven
@Enliven The list is supposed to make people scroll, it should not contain every possible answer ;)Anam
It's not so easy to find out the path to „the other formats“, is it? (I get entirely different hashes from google fonts for woff, ttf, oet...)Elmore
@FrankN That's right. The hashes used to be the same for all formats with just a different extension. For whatever reason Google made it more complicated and now they have differing file names. You can use localfont to get to all file names. See answer below.Marchpane
Here google developer says self hosting Google fonts has its own disadvantages , instead check these tips to use google font CDN and increase page speed.Keratose
renaming the font type from .woff2 to .ttf works perfectHennahane
Just want to say you kick arse for mentioning that your own high-cred answer is deprecated. I usually browse SO answers and choose the best solution, but this time I was in enough of a hurry to just hack in the accepted or highest-voted answer. You've saved me a disservice. Thank you for your community spirit. (And I've up-voted you for it.)Beasley
@MichaelScheper Thank you for the kind words. I still miss an option for the community to mark an answer as outdated, though. If I would not maintain it, any attempts of other editors to add a warning would be rejected as an attempt to reply.Anam
Yeah, I've been caught out by that, too. And once or twice, I've even seen grossly out-of-date answers still being marked as accepted and with high upvotes, and much better answers that apply to all currently supported browsers buried below. People still deserve credit for great answers they wrote in 2009, but if there's a better-this-year answer, it should be possible to make that clear without jumping through the hoops you went through. Anyhow, no worries. ☺Beasley
S
165

Great solution is google-webfonts-helper .

It allows you to select more than one font variant, which saves a lot of time.

Seeto answered 4/8, 2015 at 5:54 Comment(5)
Great tools! I love it. You can see the font preview and download all required files by one click.Refugia
Very nice tool. Works very well and allows to download latin-ext fonts too.Enliven
This is the best option. It does everything, you can even specify font folder prefix.Woofer
This saved me from lots of issues, I was generating pdfs using chromedp in golang the design was getting broken because of the remote font calls at times. Once I moved all the fonts into my local server all the issues were fixed. Great solution.Maddock
Perfect. Solution allows for generating only what you need to downloadCheryllches
N
64

I wrote a bash script that fetches the CSS file on Google's servers with different user agents, downloads the different font formats to a local directory and writes a CSS file including them. Note that the script needs Bash version 4.x.

See https://neverpanic.de/blog/2014/03/19/downloading-google-web-fonts-for-local-hosting/ for the script (I'm not reproducing it here so I only have to update it in one place when I need to).

Edit: Moved to https://github.com/neverpanic/google-font-download

Nought answered 19/4, 2014 at 18:50 Comment(6)
This is more then awesome! (I hope it works well not tested yet). I searched for something like this form time to time over years. No kidding, I even started to write my own script that is far from complete. Its mind blowing that so few people tend to want this. Google is hiding this fonts behind generated strings and does no open source the actually webfont files in the repo only the ttf. They want us to use their fonts, they want us to use their servers because they abuse this for tracking people. And even the most privacy aware people embed the fonts from googles server.Forewoman
My only concern is the actual font licenses, not really closely studied them. All I know is that font licenses differ from GPL or MIT. So are we actually legally allowed to catch this fonts from the Google servers and serv them on our own? Again I not believe for a minute that Google is giving all this fonts away just for the sake of making the world better, they actually pay devs to produce open fonts for them so they for sure have gain something, data lots of data. And if its not privacy your up to, you can test this fonts locally without Internet this way.Forewoman
This answer should be upvoted more, because this script can downloads all fonts formats and subsets in contrast to localfont.com.Enliven
I know you will take me as a lazy person, but as an average windows user, it sucks to have to compile it and etc to be able to use it...Coelom
@LucasB There is no compiling involved. It's a bash script. I know Windows doesn't come with Bash, but feel free to re-implement this in a way that supports Windows. It was just not part of my use-case, so I didn't spend any time on it.Nought
@Forewoman You can lookup the license for each font like this: fonts.google.com/specimen/Source+Code+Pro#license Probably most of them are under the OFL. The OFL is quite permissive, e.g. no attribution required in documents that are typeset with an OFL licensed font (cf. en.wikipedia.org/wiki/SIL_Open_Font_License and the OFL FAQ linked from the official website linked from that WP article). For google it's just another vehicle to entice web creators to use their CDN because of the convenience - for better tracking of page visitors.Byzantine
A
14

The contents of the CSS file (from the include URL) depends on what browser I view it from. For example, when browsing to http://fonts.googleapis.com/css?family=Open+Sans using Chrome, the file only contained WOFF links. Using Internet Explorer (below), it included both EOT and WOFF. I pasted all the links into my browser to download them.

@font-face {
  font-family: 'Open Sans';
  font-style: normal;
  font-weight: 400;
  src: url(http://themes.googleusercontent.com/static/fonts/opensans/v6/cJZKeOuBrn4kERxqtaUH3fY6323mHUZFJMgTvxaG2iE.eot);
  src: local('Open Sans'), local('OpenSans'), url(http://themes.googleusercontent.com/static/fonts/opensans/v6/cJZKeOuBrn4kERxqtaUH3fY6323mHUZFJMgTvxaG2iE.eot) format('embedded-opentype'), url(http://themes.googleusercontent.com/static/fonts/opensans/v6/cJZKeOuBrn4kERxqtaUH3T8E0i7KZn-EPnyo3HZu7kw.woff) format('woff');
}

When you host your own web fonts, you need to correctly link to each font type, deal with legacy browser bugs, etc. When you use Google Web Fonts (hosted by Google), Google automatically links to the correct font types for that browser.

Annulment answered 22/11, 2013 at 22:3 Comment(2)
+1 for linking to that article that explains the "universal" CSS code to use and a "reduced" one for modern browsers!Thielen
So I will need to smartly serve the browser with different format then. I know this is highly discouraged but we are serving our page to some China clients and it's the main reason we want to host it. They blocked most google resources.Orola
S
6

It is legally allowed as long as you stick to the terms of the font's license - usually the OFL.

You'll need a set of web font formats, and the Font Squirrel Webfont Generator can produce these.

But the OFL required the fonts be renamed if they are modified, and using the generator means modifying them.

Shawna answered 28/1, 2012 at 0:48 Comment(1)
Or, depending on the typeface, you can simply get the Webfont kit directly from the font squirrel. fontsquirrel.com/fonts/open-sansOligopsony
L
3

I have a script written in PHP similar to that of @neverpanic that automatically downloads both the CSS and fonts (both hinted and unhinted) from Google. It then serves the correct CSS and fonts from your own server based on the User Agent. It keeps its own cache, so fonts and CSS of a User Agent will only be downloaded once.

It's in a premature stage, but it can be found here: DaAwesomeP / php-offline-fonts

Leopold answered 20/4, 2014 at 2:46 Comment(0)
E
3

Easiest Approach - Using google-webfonts-helper

Lets say we want to host the font Red Rose:

  • Open google-webfonts-helper and filter for the required font on top left (type Red Rose and enter..)
  • Choose from the charsets (default is latin; select others like latin-ext if you want extended support)
  • Select the styles (deafult is regular)
  • From the Copy CSS tab
    • Select Modern Browser if you wish to support only modern browsers (woff2, woff)
    • Select Best Support if you wish to support all browsers (I chose this - woff2, woff,ttf,svg,eot)
  • In case your font files do not reside in ../fonts/ path, you can edit it to represent your actual path (for me it was ../assets/fonts/)
  • Copy the CSS and keep for future use
  • Download the zip file named red-rose-v1-latin-ext_latin; unzip it and place all fonts directly into your assets/fonts directory (based on what you gave earlier)
  • In your stylesheet where you wish to embed, paste the copied CSS. It will look like the below if you chose these options
/* red-rose-regular - latin-ext_latin */
@font-face {
  font-family: 'Red Rose';
  font-style: normal;
  font-weight: 400;
  src: url('../assets/fonts/red-rose-v1-latin-ext_latin-regular.eot'); /* IE9 Compat Modes */
  src: local('Red Rose Regular'), local('RedRose-Regular'),
       url('../assets/fonts/red-rose-v1-latin-ext_latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
       url('../assets/fonts/red-rose-v1-latin-ext_latin-regular.woff2') format('woff2'), /* Super Modern Browsers */
       url('../assets/fonts/red-rose-v1-latin-ext_latin-regular.woff') format('woff'), /* Modern Browsers */
       url('../assets/fonts/red-rose-v1-latin-ext_latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */
       url('../assets/fonts/red-rose-v1-latin-ext_latin-regular.svg#RedRose') format('svg'); /* Legacy iOS */
}
/* Red Rose will now be available for use in your stylesheet, provide this font */

:root {
  font-family: 'Red Rose', cursive, sans-serif;
}
  • Thats ALL!
Espagnole answered 20/8, 2020 at 10:21 Comment(0)
W
2

You can actually download all font format variants directly from Google and include them in your css to serve from your server. That way you don't have to concern about Google tracking your site's users. However, the downside maybe slowing down your own serving speed. Fonts are quite demanding on resources. I have not done any tests in this issue yet, and wonder if anyone has similar thoughts.

Windsor answered 25/2, 2016 at 10:52 Comment(1)
This should be the correct answer when it comes to users’ privacy. That is, to self-host your own fonts.Treadway
T
2

As you want to host all fonts (or some of them) at your own server, you a download fonts from this repo and use it the way you want: https://github.com/praisedpk/Local-Google-Fonts

If you just want to do this to fix the leverage browser caching issue that comes with Google Fonts, you can use alternative fonts CDN, and include fonts as:

<link href="https://pagecdn.io/lib/easyfonts/fonts.css" rel="stylesheet" />

Or a specific font, as:

<link href="https://pagecdn.io/lib/easyfonts/lato.css" rel="stylesheet" />
Tull answered 23/3, 2017 at 16:14 Comment(0)
C
2

Edit: As luckyrumo pointed out, typefaces is depricated in favour of: https://github.com/fontsource/fontsource

If you're using Webpack, you might be interested in this project: https://github.com/KyleAMathews/typefaces

E.g. say you want to use Roboto font:

npm install typeface-roboto --save

Then just import it in your app's entrypoint (main js file):

import 'typeface-roboto'
Clerissa answered 31/12, 2017 at 15:59 Comment(1)
Thanks for the link! typefaces' successor fontsource is exactly what I had looked for: github.com/fontsource/fontsource The CSS contains Unicode ranges as well, which is a rare feature, in my experience.Craigie
I
1

I used grunt-local-googlefont in a grunt task.

module.exports = function(grunt) {

    grunt.initConfig({
       pkg: grunt.file.readJSON('package.json'),

        "local-googlefont" : {
            "opensans" : {
                "options" : {
                    "family" : "Open Sans",
                    "sizes" : [
                        300,
                        400,
                        600
                    ],
                    "userAgents" : [
                        "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0)",  //download eot
                        "Mozilla/5.0 (Linux; U; Android 4.1.2; nl-nl; GT-I9300 Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30", //download ttf
                        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1944.0 Safari/537.36" //download woff and woff2
                    ],
                    "cssDestination" : "build/fonts/css",
                    "fontDestination" : "build/fonts",
                    "styleSheetExtension" : "css",
                    "fontDestinationCssPrefix" : "fonts"

                }
            }
        }
    });

    grunt.loadNpmTasks('grunt-local-googlefont');
 };

Then, to retrieve them:

grunt local-googlefont:opensans

Note, I'm using a fork from the original, which works better when retrieving fonts with whitespaces in their names.

Itch answered 10/12, 2015 at 14:27 Comment(0)
A
1

You may follow the script which is developed using PHP. Where you can download any google fonts by using the script. It will download the fonts and create a CSS file and archive to zip.
You can download the source code from the GitHub https://github.com/souravmsh/google-fonts-downloader

$obj = new GoogleFontsDownloader;
        
if(isset($_GET['url']) && !empty($_GET['url']))
{
    $obj->generate($_GET['url']);
}

if(isset($_GET['download']) && !empty($_GET['download']) && $_GET['download']=='true')
{
    $obj->download();
}

/**
* GoogleFontsDownloader
* Easy way to download any google fonts.
* @author     Shohrab Hossain
* @version    1.0.0 
*/
class GoogleFontsDownloader
{
    private $url      = '';
    private $dir      = 'dist/';
    private $fontsDir = 'fonts/';
    private $cssDir   = 'css/';
    private $fileName = 'fonts.css';
    private $content  = '';
    private $errors   = '';
    private $success  = '';
    public  $is_downloadable  = false;

    public function __construct()
    {
        ini_set('allow_url_fopen', 'on');
        ini_set('allow_url_include', 'on');
    }
 
    public function generate($url = null)
    {
        if (filter_var($url, FILTER_VALIDATE_URL) === FALSE) 
        {
            $this->errors .= "<li><strong>Invalid url!</strong> $url</li>";
        }
        else
        {
            $this->url = $url;
            // delete previous files
            $this->_destroy();
            // write font.css
            $this->_css();
            // write fonts
            $this->_fonts();
            // archive files
            $this->_archive();
        }  
        // show all messages
        $this->_message();
    }
 
    public function download()
    { 
        // Download the created zip file
        $zipFileName = trim($this->dir, '/').'.zip';
        if (file_exists($zipFileName))
        {
            header("Content-type: application/zip");
            header("Content-Disposition: attachment; filename = $zipFileName");
            header("Pragma: no-cache");
            header("Expires: 0");
            readfile("$zipFileName");
 
            // delete file 
            unlink($zipFileName);
            array_map('unlink', glob("$this->dir/*.*"));
            rmdir($this->dir);

        } 
    }   
 
    private function _archive()
    {
        if (is_dir($this->dir))
        {
            $zipFileName = trim($this->dir, '/').'.zip';
            $zip = new \ZipArchive(); 
            if ($zip->open($zipFileName, ZipArchive::CREATE) === TRUE) 
            {
                $zip->addGlob($this->dir. "*.*");
                $zip->addGlob($this->dir. "*/*.*");
                if ($zip->status == ZIPARCHIVE::ER_OK)
                {
                    $this->success .= '<li>Zip create successful!</li>';
                    $this->is_downloadable = true;
                }
                else 
                {
                    $this->errors .= '<li>Failed to create to zip</li>';
                } 
            } 
            else 
            {
                $this->errors .= '<li>ZipArchive not found!</li>';
            }  
            $zip->close(); 
        }
        else
        {
            $this->errors .= "<li><strong>File</strong> not exists!</li>";
        } 
    }   
  
    private function _css()
    {  
        $filePath = $this->dir.$this->cssDir.$this->fileName;
        $content  = $this->_request($this->url);
        if (!empty($content))
        {
            if (file_put_contents($filePath, $content))
            {
                $this->success .= "<li>$this->fileName generated successful!</li>";
                $this->content = $content; 
            }
            else
            {
                $this->errors .= '<li>Permission errro in $this->fileName! Unable to write $filePath.</li>';
            }
        }
        else
        {
            $this->errors .= '<li>Unable to create fonts.css file!</li>';
        }
    }

    private function _fonts()
    {
        if (!empty($this->content))
        {
            preg_match_all('#\bhttps?://[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/))#', $this->content, $match);
            $gFontPaths = $match[0];
            if (!empty($gFontPaths) && is_array($gFontPaths) && sizeof($gFontPaths)>0)
            {
                $count = 0;
                foreach ($gFontPaths as $url) 
                {
                    $name     = basename($url);
                    $filePath = $this->dir.$this->fontsDir.$name;
                    $this->content = str_replace($url, '../'.$this->fontsDir.$name, $this->content);

                    $fontContent  = $this->_request($url);
                    if (!empty($fontContent))
                    {
                        file_put_contents($filePath, $fontContent);
                        $count++;
                        $this->success .= "<li>The font $name downloaded!</li>";
                    }
                    else
                    {
                        $this->errors .= "<li>Unable to download the font $name!</li>";
                    } 
                }

                file_put_contents($this->dir.$this->cssDir.$this->fileName, $this->content);
                $this->success .= "<li>Total $count font(s) downloaded!</li>";
            }
        }
    }

    private function _request($url)
    {
        $ch = curl_init(); 
        curl_setopt_array($ch, array(
            CURLOPT_SSL_VERIFYPEER => FALSE,
            CURLOPT_HEADER         => FALSE,
            CURLOPT_FOLLOWLOCATION => TRUE,
            CURLOPT_URL            => $url,
            CURLOPT_REFERER        => $url,
            CURLOPT_RETURNTRANSFER => TRUE,
        ));
        $result = curl_exec($ch);
        curl_close($ch);

        if (!empty($result))
        {
            return $result;
        } 
        return false;
    }

    private function _destroy()
    {
        $cssPath = $this->dir.$this->cssDir.$this->fileName;
        if (file_exists($cssPath) && is_file($cssPath))
        {
            unlink($cssPath);
        } 
        else
        {
            mkdir($this->dir.$this->cssDir, 0777, true);
        }

        $fontsPath = $this->dir.$this->fontsDir;
        if (!is_dir($fontsPath))
        {
            mkdir($fontsPath, 0777, true);
        }
        else
        {
            array_map(function($font) use($fontsPath) {
                if (file_exists($fontsPath.$font) && is_file($fontsPath.$font))
                {
                    unlink($fontsPath.$font);
                }
            }, glob($fontsPath.'*.*')); 
        }
    }

    private function _message()
    {
        if (strlen($this->errors)>0)
        {
            echo "<div class='alert alert-danger'><ul>$this->errors</ul></div>";
        }  
        if (strlen($this->success)>0)
        {
            echo "<div class='alert alert-success'><ul>$this->success</ul></div>";
        } 
    } 
}
Address answered 4/2, 2020 at 19:22 Comment(1)
Required reading: Why check both isset() and !empty()Boxfish
T
0

You can download source fonts from https://github.com/google/fonts

After that use font-ranger tool to split your large Unicode font into multiple subsets (e.g. latin, cyrillic). You should do the following with the tool:

  • Generate subsets for each language you support
  • Use unicode-range subsetting for saving bandwidth
  • Remove bloat from your fonts and optimize them for web
  • Convert your fonts to a compressed woff2 format
  • Provide .woff fallback for older browsers
  • Customize font loading and rendering
  • Generate CSS file with @font-face rules
  • Self-host web fonts or use them locally

Font-Ranger: https://www.npmjs.com/package/font-ranger

P.S. You can also automate this using Node.js API

Tinsel answered 26/6, 2018 at 22:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.