--I found a solution. Please, see answers below.--

I've been trying for about about 25 hours to get a working, locally hosted, tile server running, using this guide from switch2osm.

I have a virtualbox machine, running Ubuntu 14.04, with a postgres/postgis database set up (using osm2pgsql), mapnik installed, mod_tile/renderd loaded with apache and set to run on startup.

I have the appropriate test image loading through firefox at http://localhost/osm_tiles/0/0/0.png.

I even have a leaflet.js 0.7.7 setup in the document root of my apache virtual host, and it displays map tiles when my tileLayer source is "http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", but not when I try and source the tiles from my localhost "http://{s}.{z}/{x}/{y}.png". The map remains blank, and the GET requests that show up in the firefox development tool do not have a status number (i.e. 404 not found) or a size/transferred amount.

The apache error and access logs show no indication that anything is wrong, except that the GETs for the tiles aren't showing up in the apache access log at all (only the GET for the leaflet.js).

My index.html is fairly sparse:

<!DOCTYPE html>
    <link rel="stylesheet" href="leaflet.css" />
    <link rel="stylesheet" href="map.css" />
    <script src="leaflet.js"></script>
    <div id="mapid"></div>
            var mymap = L.map('mapid').setView([43, -70], 5);

The map.css only contains the height for the mapid div.

#mapid { height: 600px }

Replacing the loopback IP ( with "localhost" yeilds 404 errors on all the tiles. Replacing it with my outward facing IP (, for use with the virtualbox host-only adapter), creates the same problem (no tiles displayed, no status/transfer/size).

My apache virtualhost is set up as follows:

<VirtualHost *:80>
    ServerAdmin webmaster@localhost

    LoadTileConfigFile /usr/local/etc/renderd.conf
    ModTileRenderdSocketName /var/run/renderd/renderd.sock
    # Timeout before giving up for a tile to be rendered
    ModTileRequestTimeout 0
    # Timeout before giving up for a tile to be rendered that is otherwise missing
    ModTileMissingRequestTimeout 30

    DocumentRoot /var/www/html

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

I'm not sure I've got that configured correctly, but I only added what the tutorial told me to. This is a minimally edited 000-default.conf file with the comments removed.

The only other thing I can think of, is that I have two network cards on the virtual machine. One is set up as a NAT device, in order to have access to the internet for updates. The other is a Host-Only device, in order to test access to the "outside world", but I haven't even gotten it displaying tiles from within the VM yet, so I'm not sure this is the source of my issue.

As of yet, the problem with a manual server build has not been solved

--EDIT: (Trying a different approach)--

I wanted to make absolutely sure I didn't mess up the configuration of all the pieces in this server, so I found the slightly easier (though less educational) installation by package off the same site, switch2osm.org.

After spinning up a fresh 14.04 VM, with only an SSH server, I followed the installation by package instructions, and I'm able to see tiles hosted on my guest OS from my host OS!

The only issue now is that the automatic install of this system is using OpenLayers as a front end instead of Leaflet. This is not a terrible issue, I could end up porting my code over from Leaflet to OpenLayers, but I would really like to try and solve this issue, as it seems like a simple misunderstanding of how the tileLayer method accesses a server's locally hosted tiles.

I decided to go even further with the swtich2osm tutorials by copy-pasting their "Getting Started with Leaflet" code. This default code got me back to where I was, pulling tiles off of tile.openstreetmap.org.

The edits I then made to try and access my local tiles got me a blank map again,


var map;
var ajaxRequest;
var plotlist;
var plotlayers=[];

function initmap() {
    // set up the map
    map = new L.Map('map');

    // create the tile layer with correct attribution
    var osmUrl='http://localhost/{z}/{x}/{y}.png';
    var osm = new L.TileLayer(osmUrl);

    // start the map in Portland, Maine.
    map.setView(new L.LatLng(43.651183, -70.249044),9);


<!DOCTYPE html>
    <link rel="stylesheet" type="text/css" href="leaflet/leaflet.css" />
    <script type="text/javascript" src="leaflet/leaflet.js"></script>
    <script type="text/javascript" src="leaflet/leafletembed.js"></script>
    <link rel="stylesheet" type="text/css" href="leaflet/map.css" />
    <div id='map'></div>

I did take the suggestions from Balazs and elrobis to remove the subdomain from my link and enable mod_rewrite, and it seems that now the loopback IP and "localhost" have the same effect.

The only other information I've come up with is that when viewing the site through Chrome instead of Firefox, the images that aren't loading are reporting an "net::ERR_CONNECTION_REFUSED" message instead of nothing:


2 Answers 2


Your problem is that you referenced {s} in your code but you dont have subdomains installed. The official OSM has 3 different subdomains for that: http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png where {s} = a,b and c. So you should create at least one subdomain (set a DNS server and configure apache2 properly). But you can use it without subdomains. They use it because of heavy loads. When a.tile.openstreetmap.org is offline the second 'b' is still active because it exists on a different server and wont cause any problem in service.

PS: Don't forget to activate mod_rewrite in apache2 configuration too.

  • 2
    +1..but I recommend OP just drop the {s} for testing purposes and add that complexity later, if they want
    – elrobis
    Commented Jul 13, 2016 at 20:16
  • Just to clarify about the use of subdomains:
    – atlefren
    Commented Jul 15, 2016 at 7:12

I figured it out!

OP here.

First, I will clarify that this is the solution to my setup from the edit I made, after my initial post. The setup was a from the installation by package using apt-get from switch2osm.org and an Ubuntu 14.04 server installation.

I am not sure if this solution will work for someone who has a manually configured server. Even if the server was configured using the manual installation guide on switch2osm.org.

I spun up a fresh VM in virtualbox with two NICs again, one set to NAT (for updates) the other set to host-only (for "outside access"). The only package I selected during install was an OpenSSH server. After booting into the system for the first time I installed vim, and proceeded to configure my host-only NIC in /etc/network/interfaces for access from my host OS. After that I followed the installation instructions from the guide I mentioned in my edit from the OP.

The results were that I could see my locally hosted map tiles through a masterfully configured OpenLayers front-end (I have nothing but the utmost respect for Kai Krueger and the rest of the team at switch2osm.org).

My issue was then to try and port this to a Leaflet.js front-end without breaking anything. I tried for a while to make OpenLayers work for me, but I just couldn't wrap my head around the API enough to get it to do what I had Leaflet doing already in my online map solution.

I first tried digging through the html and javascript that had been provided with the package installation, but the only reference I could find to the tiles being rendered was a relative path )"${z}/${x}/${y}.png") that didn't really tell me where they were coming from. Of course, the guide says they're served in the mod_tile directory as metatiles (whatever those are), but linking that directory provided futile. I started throwing different urls at the tileLayer method until I was dizzy, to no avail. I was sure that this was the source of my issue.

It occurred to me, while debugging with the Chrome developer tab, to inspect the source of the tiles themselves as they were being rendered through the OpenLayers front-end. I noticed that they were being sourced on a relative path starting with "osm" (i.e. osm/1/2/3.png).

The final piece of the puzzle was that the url needed to be "domain/osm/{z}/{x}/{y}.png". I ended up using my "remote IP" to access the tiles in the end:


The reason this may be specific to the package install is because I'm not quite sure how the preconfigured apache virtualhost affected where these tiles were being served.

And there seems to be a little magic going on with the url there as well. The documentroot of the server is set to "/var/www" and there is an "osm" folder within the documentroot where the html entry point for the map tiles is stored.. but that's all that's there. There isn't a tiles folder, or directory hierarchy at all, only the html file. So it seems like a trick that the map tiles are being served at all from that directory.

I'm going to be doing a bit more reading on all the working parts here (apache, mod_tile, mapnik, etc.) to try and better understand why this small change helped make everything work. But if anyone else gets caught up on serving their own tiles like I did, hopefully this will help someone out.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.