Skip to content

Setting up a reverse proxy

Kevin Gaudin edited this page May 15, 2013 · 10 revisions

Why setting up a reverse proxy in frount of your CouchDB ?

Due to the limitation of the native CouchDB user management, unless you use Cloudant hosting there is no way for setting up a user which can write and only write to the acra-storage database. This means that anybody with the reporter credentials can have a full read acces to your whole crash reports database. These credentials can be hacked by decompiling the Android application package (.apk file).

One workaround for this is to avoid including your reporter user directly in your application by setting up a reverse proxy. This requires having access to an http server with advanced configuration rights. This should not be an issue if you're hosting CouchDB on your own servers.

We propose here 3 configurations, for Apache Httpd, Nginx or through a PHP script.

Apache httpd

This requires mod_rewrite, mod_proxy and mod_headers.

The report user and password have to be base64 encoded before being added to the Apache configuration. You can use online services to encode a string composed like username:password.

For example, with a username acra and a password r3p0rts, you have to encode the string acra:r3p0rts. The encoded value for this specific example is YWNyYTpyM3AwcnRz.

In a .htaccess file

On your webserver, create a directory in your document root which will be used as a path to post reports to.

For example in the document root of the server www.acme.com, let's create an acra directory.

In this acra directory, let's create an .htaccess file, where you write the following configuration:

SetEnvIf Request_URI acraproxy acraproxy
RequestHeader set Authorization "Basic YWNyYTpyM3AwcnRz" env=acraproxy
RewriteEngine On
RewriteRule ^acraproxy/(.*)$ http://acra.iriscouch.com/acra-storage/_design/acra-storage/_update/report/$1 [P]

Don't forget to replace YWNyYTpyM3AwcnRz with your own base64-encoded credentials.

In your ACRA configuration, just set the formUri to http://www.acme.com/acra/acraproxy.

In a virtualhost configuration

If you prefer using a configuration inside a virtualhost then you would have to add the following configuration:

SetEnvIf Request_URI acraproxy acraproxy
RequestHeader set Authorization "Basic YWNyYTpyM3AwcnRz" env=acraproxy
RewriteEngine On
RewriteRule ^/acraproxy/(.*)$ http://acra.iriscouch.com/acra-storage/_design/acra-storage/_update/report/$1 [P]

Don't forget to replace YWNyYTpyM3AwcnRz with your own base64-encoded credentials.

Your formUri would be http://www.acme.com/acraproxy

Nginx

Thanks to Andy from Stonekick

server {
  server_name MYDOMAIN.COM;
  listen *:80;
  [ any other nginx config here ]

  location  /crash_report {
    rewrite /crash_report/(.*)/(.*) /$1/_design/acra-storage/_update/report/$2 break;
    proxy_pass http://MYACCOUNT.IRISCOUCH.COM;

    # This is the couchdb reporter user and password base64 encoded (reporter:mypassword in this case, you'll need to change it to match yours)
    proxy_set_header Authorization "Basic YWNyYTpyM3AwcnRz";

    # This rewrites the location header line in the response so it doesn't reveal http://myaccount.iriscouch.com
    proxy_redirect default;

    # Only PUT requests are allowed - everything else will return 403 forbidden
    limit_except PUT {
       deny all;
    }
  }
}

With such a configuration, you then just need to configure ACRA with https://mydomain.com/crash_report/acra-myapp as the formUri.

PHP script

This requires mod_rewrite and php5-curl.

Create a folder on your php web server, for example http://www.acme.com/acra

In this folder, create a file acraproxy.php:

<?php
	$COUCH_INSTANCE = 'http://www.acmecouch.com'; // URL of your CouchDB instance
	$COUCH_PORT = 80; // Port of your CouchDB instance
	$REPORTER_USER = 'acra'; // Username of the reporter user
	$REPORTER_PASSWORD = 'r3p0rts'; // Password for the reporter user
	$APPNAME = 'myapp'; // the name of your app, same as defined when pushing your own acra-storage couchapp instance

	if($_SERVER['REQUEST_METHOD'] === 'PUT') {
		$curl = curl_init($COUCH_INSTANCE.'/acra-'.$APPNAME.'/_design/acra-storage/_update/report/'.$_GET["reportid"]); 
		curl_setopt($curl, CURLOPT_PORT, $COUCH_PORT); 
		curl_setopt($curl, CURLOPT_USERPWD, $REPORTER_USER . ":" . $REPORTER_PASSWORD);
		curl_setopt($curl, CURLOPT_FAILONERROR, true); 
		curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); 
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); 
		curl_setopt($curl, CURLOPT_PUT, true);
		curl_setopt($curl, CURLOPT_INFILE, fopen("php://input","r"));
		curl_setopt($curl, CURLOPT_INFILESIZE, $_SERVER['CONTENT_LENGTH']); 
		$result = curl_exec($curl); 
		echo $result;
	} else {
		// If not a PUT request, just get the root of the CouchDB.
		// This allows to check with a browser that the path from your php server
		// to the couch instance is operational.
		$curl = curl_init($COUCH_INSTANCE); 
		curl_setopt($curl, CURLOPT_FAILONERROR, true); 
		curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); 
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); 
		$result = curl_exec($curl); 
		echo $result;
	} 
?>

This PHP script requires an apache RewriteRule in order to operate with the PUT request generated by ACRA. You can add this to a .htaccess file in the same directory as the php script:

RewriteRule ^acraproxyphp/(.*)$ acraproxy.php?reportid=$1

The formUri in your ACRA configuration would be http://www.acme.com/acraproxyphp