Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
SlimerJS on AWS EC2 with webgl support

There is not a lot of doc or posts about making an headless renderer with webgl support. Here are few of my findings

I tried things on Heroku, but I was not able to make anything work.

Next, I tried EC2 t2.micro, only to find out that OpenGL needs a graphic card to execute (sure, there are things like mesa that I didn't tried, but it looked like I needed to build Chrome and I didn't want to go that way).

The only easy solution that I found was AWS EC2 GPU Instances. They are pretty much overpriced for what I'm trying to acheive, but it worked. You need to use an AMI that support the Nvidia GRID thing. eg https://aws.amazon.com/marketplace/pp/B00FYCDDTE and its CentOS.

Slimer need Firefox and Firefox need shared libraries that we need to install (we will use a custom repo). And you need to start X because OpenGL uses the X thing. Xvfb was not needed finally.

Anyways, here's the commands I used.

sudo yum update
# https://github.com/nodesource/distributions
curl -sL https://rpm.nodesource.com/setup | sudo bash -
sudo yum install -y nodejs
# http://ithubinfo.blogspot.ca/2013/11/how-to-install-and-configure-xvfb-in.html
sudo yum install -y xorg-x11-server-Xvfb
wget http://download.slimerjs.org/releases/0.9.6/slimerjs-0.9.6-linux-x86_64.tar.bz2
tar xjf slimerjs-0.9.6-linux-x86_64.tar.bz2
# https://lambda-linux.io/blog/2015/01/28/announcing-firefox-browser-support-for-amazon-linux/
curl -X GET -o RPM-GPG-KEY-lambda-epll https://lambda-linux.io/RPM-GPG-KEY-lambda-epll
sudo rpm --import RPM-GPG-KEY-lambda-epll
curl -X GET -o epll-release-2015.03-1.1.ll1.noarch.rpm https://lambda-linux.io/epll-release-2015.03-1.1.ll1.noarch.rpm
sudo yum -y install epll-release-2015.03-1.1.ll1.noarch.rpm
sudo yum -y --enablerepo=epll install firefox-compat
# http://stackoverflow.com/a/21524859/808657
sudo /usr/bin/X :0 &
export DISPLAY=:0.0

Then I created these 3 files that I used to test. They may work, or not... but it gives the idea.

If you go with Ubuntu, I found these commands that may work.

sudo apt-get update
# http://docs.slimerjs.org/current/installation.html#requirements
sudo apt-get install -y libc6 libstdc++6 libgcc1 libgtk2.0-0 libasound2 libxrender1
# may not be needed
sudo apt-get install -y xvfb
# http://slimerjs.org/download.html
wget http://download.slimerjs.org/releases/0.9.6/slimerjs-0.9.6-linux-x86_64.tar.bz2
tar xjf slimerjs-0.9.6-linux-x86_64.tar.bz2
# https://github.com/nodesource/distributions
curl -sL https://deb.nodesource.com/setup_0.12 | sudo bash -
sudo apt-get install -y nodejs
// use it like `node script.js`
"use strict";
var http = require('http');
var childProcess = require('child_process');
var path = require('path');
var url = require('url');
http.createServer(function (request, response) {
response.writeHead(200, {'Content-Type': 'text/html'});
var query = url.parse(request.url, true).query;
if (query && query.url) {
childProcess.exec(path.join(__dirname, 'slimerjs-0.9.6/slimerjs') + ' slimer.js ' + query.url, { maxBuffer:1024*1024 }, function(err, imagesrc, stderr) {
response.end('<img src="data:image/png;base64,' + imagesrc + '">');
console.log(err);
console.log(stderr);
});
}
else {
response.end('<form><input type="text" name="lat" value="37.1314344"><input type="text" name="lng" value="-121.6598604"><input type="submit"></form>');
}
}).listen(1337);
console.log('Server running at http://127.0.0.1:1337/');
// used by script.js
var system = require('system')
var page = require("webpage").create();
page.customHeaders = {
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"User-Agent":"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36",
};
var url = system.args[1];
page.open(url).then(function(){
page.evaluate(function() {
setTimeout(function() {
var canvas = document.querySelector('canvas');
var body = document.querySelector('body');
body.appendChild(canvas);
while ( body.firstChild.tagName !== 'CANVAS' ) body.removeChild( body.firstChild );
}, 5000);
});
setTimeout(function() {
var image = page.renderBase64('PNG');
console.log(image);
phantom.exit();
}, 6000);
});
// standalone script that spawns a web server from SlimerJS
// start it with `slimerjs-0.9.6/slimerjs webserver.js`
"use strict";
var nbPages = 3;
var page_i = 0;
var pages = [];
for (var i = 0; i < nbPages; i++) {
pages[i] = require("webpage").create();
pages[i].customHeaders = {
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"User-Agent":"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36",
};
}
var webserver = require("webserver").create();
// use your exact hostname here. Otherwise the webserver won't be accessible
webserver.listen('ec2-22-173-41-22.compute-1.amazonaws.com:5000', function(request, response) {
console.log('requested' + request.url);
var infos = request.path.split('/');
if (infos.length === 2) {
var url = infos[1];
page_i = (++page_i) % nbPages;
console.log('using ' + page_i);
var page = pages[page_i];
page.open(url).then(function(){
page.evaluateAsync(function(__end) {
setTimeout(function() {
var canvas = document.querySelector('canvas');
var body = document.querySelector('body');
body.appendChild(canvas);
while ( body.firstChild.tagName !== 'CANVAS' ) body.removeChild( body.firstChild );
}, 2200);
});
setTimeout(function() {
var imagesrc = page.renderBase64('PNG');
response.writeHead(200, {'Content-Type': 'image/png'});
response.setEncoding('binary');
response.write(atob(imagesrc));
response.close();
}, 100 + 2200);
});
}
else {
response.statusCode = 404;
response.write('Not found');
response.close();
}
});
console.log('Listening on 5000');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.