# FixMyStreet turns a map pin into a report to the right authority

> FixMyStreet is a mySociety platform for reporting street problems, where a user pins a location and the software works out which council or authority should receive the report, then sends it by email or Open311. The current release is version 6.0 and the licence is a custom one rather than a standard open source licence.

**mysociety/fixmystreet** — This is mySociety's popular map-based reporting platform: easy to install in new countries and regions

- Repository: https://github.com/mysociety/fixmystreet
- Website: http://fixmystreet.org/
- Stars: 620 · Forks: 291
- Language: Perl
- License: NOASSERTION
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/mysociety-fixmystreet

## The routing is the product, not the map

FixMyStreet started in 2007 at mySociety as a way to report problems to UK councils, and it has since been copied in many other countries and regions. The interesting engineering is not the map. Users locate a problem with a combination of an address and a pin dropped on a map, without worrying about which authority is responsible. The platform then works out the correct authority using the problem location and the type of the problem, and sends the report on, by email or through a web service such as Open311. That authority resolution is the hard part of any civic reporting system, and it is the part FixMyStreet supplies. The audience is therefore a specific kind of organisation: a council, a city, a regional government or a civic group that already has the geographic data describing its boundaries and wants the reporting interface and delivery machinery around it. The examples listed are the UK, Sweden and Switzerland instances, and the project markets itself explicitly as easy to install in new countries and regions.

## Public visibility and subscriptions are built into the model

The second thing the platform does beyond routing is make the reports a shared public record. Reported problems are visible to everyone, so a user can see whether something has already been reported and can leave updates. That has two effects. It reduces duplicate reports, which matters when a council is measuring volume by report count, and it turns the report list into a public feed that residents can follow. On top of that, users can subscribe to email or RSS alerts for problems in their area, which is a subscription model built on the geographic index the platform already maintains. The consequence for an adopter is that the data model is public by default, and a decision to run the site privately is a change of assumption rather than a configuration flag. The repository layout shows the shape of the implementation: a `perllib/` for the Perl modules, `web/` for the web application, `templates/` for the page templates, `conf/` for configuration, `db/` for the database layer, `data/` for the data files, `bin/` for the command line scripts, `t/` for the test suite, a `locale/` directory for translations, and `commonlib` as a sibling module directory.

## Perl, a cpanfile and a shared common library

The primary language is Perl, and the dependency management is a `cpanfile` with a `cpanfile.snapshot` alongside it, which is the standard Perl toolchain for a project with a large dependency set. The repository also has a `vendor/` directory and `.gitmodules`, so some dependencies are vendored or pulled in as submodules, and a `setenv.pl` at the root that is the usual entry point for environment setup in this kind of project. A `commonlib` directory at the top level points to the shared mySociety library, and the Dockerfile confirms the relationship by fetching `install-site.sh` from the mysociety/commonlib repository, which is how the project installs itself inside a Debian-based image. The application runs under a PSGI file, `app.psgi`, and the web layer is served by nginx in the container setup, with the application listening on port 9000. This is a codebase built to be deployed and customised by organisations with their own Perl capacity, which tells you something about the intended adopter profile before you read a single line of the code.

## Running the stack with Docker Compose, and what it assumes

The Compose file describes four services and it is worth reading closely, because several of the choices are load-bearing. Nginx comes first and publishes 8000 to 80, and it is given a configuration file mounted from `conf/nginx.conf-docker`. The application service runs the `fixmystreet/fixmystreet:stable` image, and it declares a dependency on Postgres with the `service_healthy` condition and on memcached with `service_started`. The database is Postgres 13.11 built inline, with a locale generated for en_GB and the data directory on a named volume, and it has a healthcheck that runs `pg_isready -U postgres` every five seconds.

```yaml
  fixmystreet:
    image: fixmystreet/fixmystreet:stable
    tty: true
    depends_on:
      postgres:
        condition: service_healthy
      memcached:
        condition: service_started
    cgroup: host
    stop_signal: SIGRTMIN+3
```

The environment block is where the defaults live, and they are development defaults with a hardcoded database password and a hardcoded superuser.

```yaml
    environment:
      POSTGRES_PASSWORD: 'password'
      FMS_DB_HOST: 'postgres.svc'
      FMS_DB_PASS: 'fms'
      FMS_DB_NAME: 'fixmystreet'
      FMS_DB_USER: 'fms'
      FMS_ROOT: '/var/www/fixmystreet/fixmystreet'
      SUPERUSER_EMAIL: 'superuser@example.org'
      SUPERUSER_PASSWORD: '5up3r53cr3t'
```

Two details are worth flagging. The service uses `cgroup: host` and mounts `/sys/fs/cgroup`, which it needs for its own supervision, and it uses a non-standard stop signal of `SIGRTMIN+3` so the application can shut down cleanly rather than being killed. The `tmpfs` mounts for `/run` and `/run/lock` mean runtime state is not persisted between container restarts. The service names carry `.svc` aliases on the compose network, which is the convention this project uses for service-to-service addressing.

## The image installs itself with a sudoer rule and a preinit hook

The Dockerfile is unusual in a way that tells you how the project expects to be customised. It starts from a Debian base image, installs a small set of tools, then downloads `install-site.sh` from the mysociety commonlib repository and runs it with the arguments `fixmystreet`, `fms` and a hostname.

```dockerfile
RUN /install-site.sh --docker fixmystreet fms 127.0.0.1.xip.io \
      && apt-get purge -y --auto-remove \
        make \
        g++ \
        libexpat1-dev \
        libssl-dev \
        zlib1g-dev \
        libxml2-dev \
        postgresql-server-dev-all \
        exim4-daemon-light \
      && apt-get -y clean \
      && rm -fr /var/lib/apt/lists/* \
      && rm -fr /home/fms/.cpanm/*
```

The install runs as a non-root user, `fms`, which is why the image also writes a sudoers entry allowing that user to run one specific script without a password.

```dockerfile
RUN cp /var/www/fixmystreet/fixmystreet/bin/docker.preinit /usr/local/preinit/99-fixmystreet \
      && chmod +x /usr/local/preinit/99-fixmystreet

EXPOSE 9000
CMD ["/usr/local/bin/boot-debian-base"]
```

The `docker.preinit` script is copied into the image's preinit directory, so the container performs its setup on first boot rather than at build time, which is what lets the same image be reused with different configuration. Note the exposed port is 9000, the application port, with nginx in front of it doing the public serving.

## Development workflow, contribution labels and the licence question

For developers, the README points at Vagrant: if you have it installed, clone the repo and run `vagrant up`. The project uses Scripts to Rule Them All, so `script/update` updates your checkout, `script/server` runs a development server and `script/test` runs the tests. The `script/` directory and the `t/` directory in the repository listing are consistent with that. The contribution guidance is notable for a civic platform. Many contributions arrive as part of organisations setting up their own installation for their area, and stand-alone contributions are welcome too. There is a Suitable for Volunteers label in the issue tracker for tasks that suit people new to the codebase, and the README asks contributors to check the other issues first before adding a new one. There is also a `CHANGELOG.md` and a `.tx/` directory, which is the configuration for Transifex, so the interface translations are managed through a translation platform rather than by hand. The one thing to settle before reuse is the licence. The project is licensed under a custom licence that GitHub cannot classify, with the terms in `LICENSE.txt`, and that is a different thing in kind from the permissive licences most open source projects ship, so read it before you build on this. The release history shows version 6.0 on 2024-11-15, with version 5.0 in 2023 and version 4.0 in 2021, and the last push was on 2026-10-20.

## Conclusion

Adopt FixMyStreet when you are running a civic reporting site for a local authority and want the address lookup, authority routing and report sending already solved, ideally with the authority data supplied by someone else. Skip it if you need a modern framework, since this is a large Perl codebase, or if you are only collecting reports with no authority integration, because the routing layer is the product. Before you start, read the LICENSE file, since the licence is a custom one rather than a standard permissive licence, and check the fixmystreet.org installation documentation for the country and authority data you would need to supply.

## FAQ

### What does FixMyStreet actually do with a report?

It works out the correct authority from the problem location and the type of the problem, then sends the report on by email or through a web service such as Open311. Users never have to determine the responsible authority themselves.

### How do I run FixMyStreet for development?

With Vagrant installed, clone the repository and run `vagrant up`. The project uses Scripts to Rule Them All, so `script/update` updates the checkout, `script/server` runs a dev server and `script/test` runs the tests.

### What database and cache does the FixMyStreet container use?

Postgres 13.11 and memcached 1.6. The application service depends on Postgres with the `service_healthy` condition and on memcached with `service_started`, and the Postgres healthcheck runs `pg_isready -U postgres` every five seconds.

### What licence is FixMyStreet released under?

A custom licence that GitHub cannot classify, with the terms in the `LICENSE.txt` file in the repository root. It is not one of the standard permissive open source licences, so read it before reuse.

## Sources

- [Issues](https://github.com/mysociety/fixmystreet/issues)
- [mysociety/fixmystreet on GitHub](https://github.com/mysociety/fixmystreet)
- [Project website](http://fixmystreet.org/)
- [README](https://github.com/mysociety/fixmystreet/blob/master/README.md)
- [Releases](https://github.com/mysociety/fixmystreet/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/mysociety-fixmystreet
