Merge pull request #3339 from lonvia/python-frontend-as-default

Switch to Python frontend as the default
This commit is contained in:
Sarah Hoffmann
2024-02-20 10:17:21 +01:00
committed by GitHub
17 changed files with 319 additions and 254 deletions

View File

@@ -11,7 +11,7 @@ jobs:
with: with:
submodules: true submodules: true
- uses: actions/cache@v3 - uses: actions/cache@v4
with: with:
path: | path: |
data/country_osm_grid.sql.gz data/country_osm_grid.sql.gz
@@ -27,7 +27,7 @@ jobs:
mv nominatim-src.tar.bz2 Nominatim mv nominatim-src.tar.bz2 Nominatim
- name: 'Upload Artifact' - name: 'Upload Artifact'
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: full-source name: full-source
path: nominatim-src.tar.bz2 path: nominatim-src.tar.bz2
@@ -43,40 +43,28 @@ jobs:
ubuntu: 20 ubuntu: 20
postgresql: '9.6' postgresql: '9.6'
postgis: '2.5' postgis: '2.5'
php: '7.3'
lua: '5.1' lua: '5.1'
- flavour: ubuntu-20 - flavour: ubuntu-20
ubuntu: 20 ubuntu: 20
postgresql: 13 postgresql: 13
postgis: 3 postgis: 3
php: '7.4'
lua: '5.3' lua: '5.3'
- flavour: ubuntu-22 - flavour: ubuntu-22
ubuntu: 22 ubuntu: 22
postgresql: 15 postgresql: 15
postgis: 3 postgis: 3
php: '8.1'
lua: '5.3' lua: '5.3'
runs-on: ubuntu-${{ matrix.ubuntu }}.04 runs-on: ubuntu-${{ matrix.ubuntu }}.04
steps: steps:
- uses: actions/download-artifact@v3 - uses: actions/download-artifact@v4
with: with:
name: full-source name: full-source
- name: Unpack Nominatim - name: Unpack Nominatim
run: tar xf nominatim-src.tar.bz2 run: tar xf nominatim-src.tar.bz2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
tools: phpunit:9, phpcs, composer
ini-values: opcache.jit=disable
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/setup-python@v4 - uses: actions/setup-python@v4
with: with:
python-version: 3.7 python-version: 3.7
@@ -119,20 +107,11 @@ jobs:
run: pip3 install -U pylint run: pip3 install -U pylint
if: matrix.flavour != 'oldstuff' if: matrix.flavour != 'oldstuff'
- name: PHP linting
run: phpcs --report-width=120 .
working-directory: Nominatim
if: matrix.flavour != 'oldstuff'
- name: Python linting - name: Python linting
run: python3 -m pylint nominatim run: python3 -m pylint nominatim
working-directory: Nominatim working-directory: Nominatim
if: matrix.flavour != 'oldstuff' if: matrix.flavour != 'oldstuff'
- name: PHP unit tests
run: phpunit ./
working-directory: Nominatim/test/php
- name: Python unit tests - name: Python unit tests
run: python3 -m pytest test/python run: python3 -m pytest test/python
working-directory: Nominatim working-directory: Nominatim
@@ -156,7 +135,7 @@ jobs:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
steps: steps:
- uses: actions/download-artifact@v3 - uses: actions/download-artifact@v4
with: with:
name: full-source name: full-source
@@ -185,16 +164,16 @@ jobs:
- name: BDD tests (legacy tokenizer) - name: BDD tests (legacy tokenizer)
run: | run: |
python3 -m behave -DREMOVE_TEMPLATE=1 -DBUILDDIR=$GITHUB_WORKSPACE/build -DTOKENIZER=legacy --format=progress3 python3 -m behave -DREMOVE_TEMPLATE=1 -DBUILDDIR=$GITHUB_WORKSPACE/build -DAPI_ENGINE=php -DTOKENIZER=legacy --format=progress3
working-directory: Nominatim/test/bdd working-directory: Nominatim/test/bdd
python-api-test: php-test:
needs: create-archive needs: create-archive
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
steps: steps:
- uses: actions/download-artifact@v3 - uses: actions/download-artifact@v4
with: with:
name: full-source name: full-source
@@ -206,6 +185,23 @@ jobs:
postgresql-version: 15 postgresql-version: 15
postgis-version: 3 postgis-version: 3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.1
tools: phpunit:9, phpcs, composer
ini-values: opcache.jit=disable
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: PHP linting
run: phpcs --report-width=120 .
working-directory: Nominatim
- name: PHP unit tests
run: phpunit ./
working-directory: Nominatim/test/php
- uses: ./Nominatim/.github/actions/build-nominatim - uses: ./Nominatim/.github/actions/build-nominatim
with: with:
flavour: 'ubuntu-22' flavour: 'ubuntu-22'
@@ -213,12 +209,9 @@ jobs:
- name: Install test prerequsites - name: Install test prerequsites
run: sudo apt-get install -y -qq python3-behave run: sudo apt-get install -y -qq python3-behave
- name: Install Python webservers - name: BDD tests (php)
run: pip3 install starlette asgi_lifespan httpx
- name: BDD tests (starlette)
run: | run: |
python3 -m behave -DREMOVE_TEMPLATE=1 -DBUILDDIR=$GITHUB_WORKSPACE/build -DAPI_ENGINE=starlette --format=progress3 python3 -m behave -DREMOVE_TEMPLATE=1 -DBUILDDIR=$GITHUB_WORKSPACE/build -DAPI_ENGINE=php --format=progress3
working-directory: Nominatim/test/bdd working-directory: Nominatim/test/bdd
@@ -268,7 +261,7 @@ jobs:
OS: ${{ matrix.name }} OS: ${{ matrix.name }}
INSTALL_MODE: ${{ matrix.install_mode }} INSTALL_MODE: ${{ matrix.install_mode }}
- uses: actions/download-artifact@v3 - uses: actions/download-artifact@v4
with: with:
name: full-source name: full-source
path: /home/nominatim path: /home/nominatim
@@ -355,7 +348,7 @@ jobs:
needs: create-archive needs: create-archive
steps: steps:
- uses: actions/download-artifact@v3 - uses: actions/download-artifact@v4
with: with:
name: full-source name: full-source
@@ -392,5 +385,4 @@ jobs:
NOMINATIM_DATABASE_DSN="pgsql:host=127.0.0.1;dbname=nominatim;user=osm-import;password=osm-import" nominatim import --continue import-from-file --osm-file test.pbf NOMINATIM_DATABASE_DSN="pgsql:host=127.0.0.1;dbname=nominatim;user=osm-import;password=osm-import" nominatim import --continue import-from-file --osm-file test.pbf
- name: Check full import - name: Check full import
run: | run: nominatim admin --check-database
nominatim admin --check-database

View File

@@ -82,13 +82,14 @@ endif()
# Setting PHP binary variable as to command line (prevailing) or auto detect # Setting PHP binary variable as to command line (prevailing) or auto detect
if (BUILD_API OR BUILD_IMPORTER) if (BUILD_API)
if (NOT PHP_BIN) if (NOT PHP_BIN)
find_program (PHP_BIN php) find_program (PHP_BIN php)
endif() endif()
# sanity check if PHP binary exists # sanity check if PHP binary exists
if (NOT EXISTS ${PHP_BIN}) if (NOT EXISTS ${PHP_BIN})
message(FATAL_ERROR "PHP binary not found. Install php or provide location with -DPHP_BIN=/path/php ") message(WARNING "PHP binary not found. Only Python frontend can be used.")
set(PHP_BIN "")
else() else()
message (STATUS "Using PHP binary " ${PHP_BIN}) message (STATUS "Using PHP binary " ${PHP_BIN})
endif() endif()
@@ -226,7 +227,11 @@ if (BUILD_IMPORTER)
PATTERN "paths.py" EXCLUDE PATTERN "paths.py" EXCLUDE
PATTERN __pycache__ EXCLUDE) PATTERN __pycache__ EXCLUDE)
configure_file(${PROJECT_SOURCE_DIR}/cmake/paths-py.tmpl paths-py.installed) if (EXISTS ${PHP_BIN})
configure_file(${PROJECT_SOURCE_DIR}/cmake/paths-py.tmpl paths-py.installed)
else()
configure_file(${PROJECT_SOURCE_DIR}/cmake/paths-py-no-php.tmpl paths-py.installed)
endif()
install(FILES ${PROJECT_BINARY_DIR}/paths-py.installed install(FILES ${PROJECT_BINARY_DIR}/paths-py.installed
DESTINATION ${NOMINATIM_LIBDIR}/lib-python/nominatim DESTINATION ${NOMINATIM_LIBDIR}/lib-python/nominatim
RENAME paths.py) RENAME paths.py)
@@ -254,7 +259,7 @@ if (BUILD_MODULE)
DESTINATION ${NOMINATIM_LIBDIR}/module) DESTINATION ${NOMINATIM_LIBDIR}/module)
endif() endif()
if (BUILD_API) if (BUILD_API AND EXISTS ${PHP_BIN})
install(DIRECTORY lib-php DESTINATION ${NOMINATIM_LIBDIR}) install(DIRECTORY lib-php DESTINATION ${NOMINATIM_LIBDIR})
endif() endif()

2
Vagrantfile vendored
View File

@@ -38,7 +38,7 @@ Vagrant.configure("2") do |config|
lv.memory = 2048 lv.memory = 2048
lv.nested = true lv.nested = true
if ENV['CHECKOUT'] != 'y' then if ENV['CHECKOUT'] != 'y' then
override.vm.synced_folder ".", "/home/vagrant/Nominatim", type: 'nfs' override.vm.synced_folder ".", "/home/vagrant/Nominatim", type: 'nfs', nfs_udp: false
end end
end end

View File

@@ -0,0 +1,15 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# This file is part of Nominatim. (https://nominatim.org)
#
# Copyright (C) 2022 by the Nominatim developer community.
# For a full list of authors see the git log.
"""
Path settings for extra data used by Nominatim (installed version).
"""
from pathlib import Path
PHPLIB_DIR = None
SQLLIB_DIR = (Path('@NOMINATIM_LIBDIR@') / 'lib-sql').resolve()
DATA_DIR = Path('@NOMINATIM_DATADIR@').resolve()
CONFIG_DIR = Path('@NOMINATIM_CONFIGDIR@').resolve()

View File

@@ -268,27 +268,10 @@ nominatim reverse --lat 51 --lon 45
``` ```
If you want to run Nominatim as a service, you need to make a choice between If you want to run Nominatim as a service, you need to make a choice between
running the traditional PHP frontend or the new experimental Python frontend. running the modern Python frontend and the legacy PHP frontend.
Make sure you have installed the right packages as per Make sure you have installed the right packages as per
[Installation](Installation.md#software). [Installation](Installation.md#software).
#### Testing the PHP frontend
You can run a small test server with the PHP frontend like this:
```sh
nominatim serve
```
Go to `http://localhost:8088/status.php` and you should see the message `OK`.
You can also run a search query, e.g. `http://localhost:8088/search.php?q=Berlin`
or, for reverse-only installations a reverse query,
e.g. `http://localhost:8088/reverse.php?lat=27.1750090510034&lon=78.04209025`.
Do not use this test server in production.
To run Nominatim via webservers like Apache or nginx, please continue reading
[Deploy the PHP frontend](Deployment-PHP.md).
#### Testing the Python frontend #### Testing the Python frontend
To run the test server against the Python frontend, you must choose a To run the test server against the Python frontend, you must choose a
@@ -296,10 +279,10 @@ web framework to use, either starlette or falcon. Make sure the appropriate
packages are installed. Then run packages are installed. Then run
``` sh ``` sh
nominatim serve --engine falcon nominatim serve
``` ```
or or, if you prefer to use Starlette instead of Falcon as webserver,
``` sh ``` sh
nominatim serve --engine starlette nominatim serve --engine starlette
@@ -314,6 +297,24 @@ Do not use this test server in production.
To run Nominatim via webservers like Apache or nginx, please continue reading To run Nominatim via webservers like Apache or nginx, please continue reading
[Deploy the Python frontend](Deployment-Python.md). [Deploy the Python frontend](Deployment-Python.md).
#### Testing the PHP frontend
You can run a small test server with the PHP frontend like this:
```sh
nominatim serve --engine php
```
Go to `http://localhost:8088/status.php` and you should see the message `OK`.
You can also run a search query, e.g. `http://localhost:8088/search.php?q=Berlin`
or, for reverse-only installations a reverse query,
e.g. `http://localhost:8088/reverse.php?lat=27.1750090510034&lon=78.04209025`.
Do not use this test server in production.
To run Nominatim via webservers like Apache or nginx, please continue reading
[Deploy the PHP frontend](Deployment-PHP.md).
## Enabling search by category phrases ## Enabling search by category phrases

View File

@@ -55,23 +55,24 @@ For running Nominatim:
* [PyYaml](https://pyyaml.org/) (5.1+) * [PyYaml](https://pyyaml.org/) (5.1+)
* [datrie](https://github.com/pytries/datrie) * [datrie](https://github.com/pytries/datrie)
When running the PHP frontend:
* [PHP](https://php.net) (7.3+)
* PHP-pgsql
* PHP-intl (bundled with PHP)
For running continuous updates: For running continuous updates:
* [pyosmium](https://osmcode.org/pyosmium/) * [pyosmium](https://osmcode.org/pyosmium/)
For running the experimental Python frontend: For running the Python frontend:
* one of the following web frameworks: * one of the following web frameworks:
* [falcon](https://falconframework.org/) (3.0+) * [falcon](https://falconframework.org/) (3.0+)
* [starlette](https://www.starlette.io/) * [starlette](https://www.starlette.io/)
* [uvicorn](https://www.uvicorn.org/) * [uvicorn](https://www.uvicorn.org/)
For running the legacy PHP frontend:
* [PHP](https://php.net) (7.3+)
* PHP-pgsql
* PHP-intl (bundled with PHP)
For dependencies for running tests and building documentation, see For dependencies for running tests and building documentation, see
the [Development section](../develop/Development-Environment.md). the [Development section](../develop/Development-Environment.md).

View File

@@ -22,8 +22,8 @@ nav:
- 'Basic Installation': 'admin/Installation.md' - 'Basic Installation': 'admin/Installation.md'
- 'Import' : 'admin/Import.md' - 'Import' : 'admin/Import.md'
- 'Update' : 'admin/Update.md' - 'Update' : 'admin/Update.md'
- 'Deploy (PHP frontend)' : 'admin/Deployment-PHP.md'
- 'Deploy (Python frontend)' : 'admin/Deployment-Python.md' - 'Deploy (Python frontend)' : 'admin/Deployment-Python.md'
- 'Deploy (PHP frontend)' : 'admin/Deployment-PHP.md'
- 'Nominatim UI' : 'admin/Setup-Nominatim-UI.md' - 'Nominatim UI' : 'admin/Setup-Nominatim-UI.md'
- 'Advanced Installations' : 'admin/Advanced-Installations.md' - 'Advanced Installations' : 'admin/Advanced-Installations.md'
- 'Maintenance' : 'admin/Maintenance.md' - 'Maintenance' : 'admin/Maintenance.md'

View File

@@ -13,6 +13,7 @@ import datetime as dt
import textwrap import textwrap
import io import io
import re import re
import html
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy.ext.asyncio import AsyncConnection from sqlalchemy.ext.asyncio import AsyncConnection
@@ -227,7 +228,7 @@ class HTMLLogger(BaseLogger):
HtmlFormatter(nowrap=True, lineseparator='<br />')) HtmlFormatter(nowrap=True, lineseparator='<br />'))
self._write(f'<div class="highlight"><code class="lang-sql">{sqlstr}</code></div>') self._write(f'<div class="highlight"><code class="lang-sql">{sqlstr}</code></div>')
else: else:
self._write(f'<code class="lang-sql">{sqlstr}</code>') self._write(f'<code class="lang-sql">{html.escape(sqlstr)}</code>')
def _python_var(self, var: Any) -> str: def _python_var(self, var: Any) -> str:
@@ -235,7 +236,7 @@ class HTMLLogger(BaseLogger):
fmt = highlight(str(var), PythonLexer(), HtmlFormatter(nowrap=True)) fmt = highlight(str(var), PythonLexer(), HtmlFormatter(nowrap=True))
return f'<div class="highlight"><code class="lang-python">{fmt}</code></div>' return f'<div class="highlight"><code class="lang-python">{fmt}</code></div>'
return f'<code class="lang-python">{str(var)}</code>' return f'<code class="lang-python">{html.escape(str(var))}</code>'
def _write(self, text: str) -> None: def _write(self, text: str) -> None:

View File

@@ -159,13 +159,15 @@ class AdminServe:
group = parser.add_argument_group('Server arguments') group = parser.add_argument_group('Server arguments')
group.add_argument('--server', default='127.0.0.1:8088', group.add_argument('--server', default='127.0.0.1:8088',
help='The address the server will listen to.') help='The address the server will listen to.')
group.add_argument('--engine', default='php', group.add_argument('--engine', default='falcon',
choices=('php', 'falcon', 'starlette'), choices=('php', 'falcon', 'starlette'),
help='Webserver framework to run. (default: php)') help='Webserver framework to run. (default: falcon)')
def run(self, args: NominatimArgs) -> int: def run(self, args: NominatimArgs) -> int:
if args.engine == 'php': if args.engine == 'php':
if args.config.lib_dir.php is None:
raise UsageError("PHP frontend not configured.")
run_php_server(args.server, args.project_dir / 'website') run_php_server(args.server, args.project_dir / 'website')
else: else:
import uvicorn # pylint: disable=import-outside-toplevel import uvicorn # pylint: disable=import-outside-toplevel

View File

@@ -214,19 +214,20 @@ class ICUTokenizer(AbstractTokenizer):
return list(s[0].split('@')[0] for s in cur) return list(s[0].split('@')[0] for s in cur)
def _install_php(self, phpdir: Path, overwrite: bool = True) -> None: def _install_php(self, phpdir: Optional[Path], overwrite: bool = True) -> None:
""" Install the php script for the tokenizer. """ Install the php script for the tokenizer.
""" """
assert self.loader is not None if phpdir is not None:
php_file = self.data_dir / "tokenizer.php" assert self.loader is not None
php_file = self.data_dir / "tokenizer.php"
if not php_file.exists() or overwrite: if not php_file.exists() or overwrite:
php_file.write_text(dedent(f"""\ php_file.write_text(dedent(f"""\
<?php <?php
@define('CONST_Max_Word_Frequency', 10000000); @define('CONST_Max_Word_Frequency', 10000000);
@define('CONST_Term_Normalization_Rules', "{self.loader.normalization_rules}"); @define('CONST_Term_Normalization_Rules', "{self.loader.normalization_rules}");
@define('CONST_Transliteration', "{self.loader.get_search_rules()}"); @define('CONST_Transliteration', "{self.loader.get_search_rules()}");
require_once('{phpdir}/tokenizer/icu_tokenizer.php');"""), encoding='utf-8') require_once('{phpdir}/tokenizer/icu_tokenizer.php');"""), encoding='utf-8')
def _save_config(self) -> None: def _save_config(self) -> None:

View File

@@ -269,15 +269,16 @@ class LegacyTokenizer(AbstractTokenizer):
def _install_php(self, config: Configuration, overwrite: bool = True) -> None: def _install_php(self, config: Configuration, overwrite: bool = True) -> None:
""" Install the php script for the tokenizer. """ Install the php script for the tokenizer.
""" """
php_file = self.data_dir / "tokenizer.php" if config.lib_dir.php is not None:
php_file = self.data_dir / "tokenizer.php"
if not php_file.exists() or overwrite: if not php_file.exists() or overwrite:
php_file.write_text(dedent(f"""\ php_file.write_text(dedent(f"""\
<?php <?php
@define('CONST_Max_Word_Frequency', {config.MAX_WORD_FREQUENCY}); @define('CONST_Max_Word_Frequency', {config.MAX_WORD_FREQUENCY});
@define('CONST_Term_Normalization_Rules', "{config.TERM_NORMALIZATION}"); @define('CONST_Term_Normalization_Rules', "{config.TERM_NORMALIZATION}");
require_once('{config.lib_dir.php}/tokenizer/legacy_tokenizer.php'); require_once('{config.lib_dir.php}/tokenizer/legacy_tokenizer.php');
"""), encoding='utf-8') """), encoding='utf-8')
def _init_db_tables(self, config: Configuration) -> None: def _init_db_tables(self, config: Configuration) -> None:

View File

@@ -213,6 +213,10 @@ def _quote_php_variable(var_type: Type[Any], config: Configuration,
def setup_website(basedir: Path, config: Configuration, conn: Connection) -> None: def setup_website(basedir: Path, config: Configuration, conn: Connection) -> None:
""" Create the website script stubs. """ Create the website script stubs.
""" """
if config.lib_dir.php is None:
LOG.info("Python frontend does not require website setup. Skipping.")
return
if not basedir.exists(): if not basedir.exists():
LOG.info('Creating website directory.') LOG.info('Creating website directory.')
basedir.mkdir() basedir.mkdir()

View File

@@ -28,7 +28,7 @@ userconfig = {
'SERVER_MODULE_PATH' : None, 'SERVER_MODULE_PATH' : None,
'TOKENIZER' : None, # Test with a custom tokenizer 'TOKENIZER' : None, # Test with a custom tokenizer
'STYLE' : 'extratags', 'STYLE' : 'extratags',
'API_ENGINE': 'php', 'API_ENGINE': 'falcon',
'PHPCOV' : False, # set to output directory to enable code coverage 'PHPCOV' : False, # set to output directory to enable code coverage
} }

View File

@@ -243,7 +243,7 @@ def step_impl(context, fmt):
try: try:
tree = ET.fromstring(context.response.page) tree = ET.fromstring(context.response.page)
except Exception as ex: except Exception as ex:
assert False, f"Could not parse page:\n{context.response.page}" assert False, f"Could not parse page: {ex}\n{context.response.page}"
assert tree.tag == 'html' assert tree.tag == 'html'
body = tree.find('./body') body = tree.find('./body')

View File

@@ -63,7 +63,7 @@ def test_cli_add_data_tiger_data(cli_call, cli_tokenizer_mock, mock_func_factory
def test_cli_serve_php(cli_call, mock_func_factory): def test_cli_serve_php(cli_call, mock_func_factory):
func = mock_func_factory(nominatim.cli, 'run_php_server') func = mock_func_factory(nominatim.cli, 'run_php_server')
cli_call('serve') == 0 cli_call('serve', '--engine', 'php') == 0
assert func.called == 1 assert func.called == 1

View File

@@ -16,16 +16,16 @@ export DEBIAN_FRONTEND=noninteractive #DOCS:
# Make sure all packages are up-to-date by running: # Make sure all packages are up-to-date by running:
# #
sudo apt update -qq sudo apt-get update -qq
# Now you can install all packages needed for Nominatim: # Now you can install all packages needed for Nominatim:
sudo apt install -y build-essential cmake g++ libboost-dev libboost-system-dev \ sudo apt-get install -y build-essential cmake g++ libboost-dev libboost-system-dev \
libboost-filesystem-dev libexpat1-dev zlib1g-dev \ libboost-filesystem-dev libexpat1-dev zlib1g-dev \
libbz2-dev libpq-dev liblua5.3-dev lua5.3 lua-dkjson \ libbz2-dev libpq-dev liblua5.3-dev lua5.3 lua-dkjson \
nlohmann-json3-dev postgresql-12-postgis-3 \ nlohmann-json3-dev postgresql-12-postgis-3 \
postgresql-contrib-12 postgresql-12-postgis-3-scripts \ postgresql-contrib-12 postgresql-12-postgis-3-scripts \
php-cli php-pgsql php-intl libicu-dev python3-dotenv \ libicu-dev python3-dotenv \
python3-psycopg2 python3-psutil python3-jinja2 python3-pip \ python3-psycopg2 python3-psutil python3-jinja2 python3-pip \
python3-icu python3-datrie python3-yaml git python3-icu python3-datrie python3-yaml git
@@ -133,45 +133,107 @@ fi #DOCS:
# Nominatim is now ready to use. You can continue with # Nominatim is now ready to use. You can continue with
# [importing a database from OSM data](../admin/Import.md). If you want to set up # [importing a database from OSM data](../admin/Import.md). If you want to set up
# a webserver first, continue reading. # the API frontend first, continue reading.
# #
# Setting up the Python frontend
# ==============================
#
# Some of the Python packages in Ubuntu are too old. Therefore run the
# frontend from a Python virtualenv with current packages.
#
# To set up the virtualenv, run:
#DOCS:```sh
sudo apt-get install -y virtualenv
virtualenv $USERHOME/nominatim-venv
$USERHOME/nominatim-venv/bin/pip install SQLAlchemy PyICU psycopg[binary] \
psycopg2-binary python-dotenv PyYAML falcon uvicorn gunicorn
#DOCS:```
# Next you need to create a systemd job that runs Nominatim on gunicorn.
# First create a systemd job that manages the socket file:
#DOCS:```sh
sudo tee /etc/systemd/system/nominatim.socket << EOFSOCKETSYSTEMD
[Unit]
Description=Gunicorn socket for Nominatim
[Socket]
ListenStream=/run/nominatim.sock
SocketUser=www-data
[Install]
WantedBy=multi-user.target
EOFSOCKETSYSTEMD
#DOCS:```
# Then create the service for Nominatim itself.
#DOCS:```sh
sudo tee /etc/systemd/system/nominatim.service << EOFNOMINATIMSYSTEMD
[Unit]
Description=Nominatim running as a gunicorn application
After=network.target
Requires=nominatim.socket
[Service]
Type=simple
Environment="PYTHONPATH=/usr/local/lib/nominatim/lib-python/"
User=www-data
Group=www-data
WorkingDirectory=$USERHOME/nominatim-project
ExecStart=$USERHOME/nominatim-venv/bin/gunicorn -b unix:/run/nominatim.sock -w 4 -k uvicorn.workers.UvicornWorker nominatim.server.falcon.server:run_wsgi
ExecReload=/bin/kill -s HUP \$MAINPID
StandardOutput=append:/var/log/gunicorn-nominatim.log
StandardError=inherit
PrivateTmp=true
TimeoutStopSec=5
KillMode=mixed
[Install]
WantedBy=multi-user.target
EOFNOMINATIMSYSTEMD
#DOCS:```
# Activate the services:
if [ "x$NOSYSTEMD" != "xyes" ]; then #DOCS:
sudo systemctl daemon-reload
sudo systemctl enable nominatim.socket
sudo systemctl start nominatim.socket
sudo systemctl enable nominatim.service
fi #DOCS:
# Setting up a webserver # Setting up a webserver
# ====================== # ======================
# #
# The webserver should serve the php scripts from the website directory of your # The webserver is only needed as a proxy between the public interface
# [project directory](../admin/Import.md#creating-the-project-directory). # and the gunicorn service.
# This directory needs to exist when being configured. #
# Therefore set up a project directory and create a website directory: # The frontend will need configuration information from the project
# directory, which will be populated later
# [during the import process](../admin/Import.md#creating-the-project-directory)
# Already create the project directory itself now:
mkdir $USERHOME/nominatim-project mkdir $USERHOME/nominatim-project
mkdir $USERHOME/nominatim-project/website
# The import process will populate the directory later.
#
# Option 1: Using Apache # Option 1: Using Apache
# ---------------------- # ----------------------
# #
if [ "x$2" == "xinstall-apache" ]; then #DOCS: if [ "x$2" == "xinstall-apache" ]; then #DOCS:
# # First install apache itself and enable the proxy module:
# Apache has a PHP module that can be used to serve Nominatim. To install them
# run:
sudo apt install -y apache2 libapache2-mod-php sudo apt-get install -y apache2
sudo a2enmod proxy_http
# You need to create an alias to the website directory in your apache # To set up proxying for Apache add the following configuration:
# configuration. Add a separate nominatim configuration to your webserver:
#DOCS:```sh #DOCS:```sh
sudo tee /etc/apache2/conf-available/nominatim.conf << EOFAPACHECONF sudo tee /etc/apache2/conf-available/nominatim.conf << EOFAPACHECONF
<Directory "$USERHOME/nominatim-project/website"> ProxyPass /nominatim "unix:/run/nominatim.sock|http://localhost/"
Options FollowSymLinks MultiViews
AddType text/html .php
DirectoryIndex search.php
Require all granted
</Directory>
Alias /nominatim $USERHOME/nominatim-project/website
EOFAPACHECONF EOFAPACHECONF
#DOCS:``` #DOCS:```
@@ -196,33 +258,9 @@ fi #DOCS:
# #
if [ "x$2" == "xinstall-nginx" ]; then #DOCS: if [ "x$2" == "xinstall-nginx" ]; then #DOCS:
# Nginx has no native support for php scripts. You need to set up php-fpm for # First install nginx itself:
# this purpose. First install nginx and php-fpm:
sudo apt install -y nginx php-fpm sudo apt-get install -y nginx
# You need to configure php-fpm to listen on a Unix socket.
#DOCS:```sh
sudo tee /etc/php/7.4/fpm/pool.d/www.conf << EOF_PHP_FPM_CONF
[www]
; Replace the tcp listener and add the unix socket
listen = /var/run/php-fpm-nominatim.sock
; Ensure that the daemon runs as the correct user
listen.owner = www-data
listen.group = www-data
listen.mode = 0666
; Unix user of FPM processes
user = www-data
group = www-data
; Choose process manager type (static, dynamic, ondemand)
pm = ondemand
pm.max_children = 5
EOF_PHP_FPM_CONF
#DOCS:```
# Then create a Nginx configuration to forward http requests to that socket. # Then create a Nginx configuration to forward http requests to that socket.
@@ -233,45 +271,26 @@ server {
listen [::]:80 default_server; listen [::]:80 default_server;
root $USERHOME/nominatim-project/website; root $USERHOME/nominatim-project/website;
index search.php index.html; index /search;
location / {
try_files \$uri \$uri/ @php;
}
location @php { location /nominatim/ {
fastcgi_param SCRIPT_FILENAME "\$document_root\$uri.php"; proxy_set_header Host \$http_host;
fastcgi_param PATH_TRANSLATED "\$document_root\$uri.php"; proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
fastcgi_param QUERY_STRING \$args; proxy_set_header X-Forwarded-Proto \$scheme;
fastcgi_pass unix:/var/run/php-fpm-nominatim.sock; proxy_redirect off;
fastcgi_index index.php; proxy_pass http://unix:/run/nominatim.sock:/;
include fastcgi_params;
}
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
if (!-f \$document_root\$fastcgi_script_name) {
return 404;
}
fastcgi_pass unix:/var/run/php-fpm-nominatim.sock;
fastcgi_index search.php;
include fastcgi.conf;
} }
} }
EOF_NGINX_CONF EOF_NGINX_CONF
#DOCS:``` #DOCS:```
# If you have some errors, make sure that php-fpm-nominatim.sock is well under
# /var/run/ and not under /var/run/php. Otherwise change the Nginx configuration
# to /var/run/php/php-fpm-nominatim.sock.
#
# Enable the configuration and restart Nginx # Enable the configuration and restart Nginx
# #
if [ "x$NOSYSTEMD" == "xyes" ]; then #DOCS: if [ "x$NOSYSTEMD" == "xyes" ]; then #DOCS:
sudo /usr/sbin/php-fpm7.4 --nodaemonize --fpm-config /etc/php/7.4/fpm/php-fpm.conf & #DOCS:
sudo /usr/sbin/nginx & #DOCS: sudo /usr/sbin/nginx & #DOCS:
else #DOCS: else #DOCS:
sudo systemctl restart php7.4-fpm nginx sudo systemctl restart nginx
fi #DOCS: fi #DOCS:
# The Nominatim API is now available at `http://localhost/`. # The Nominatim API is now available at `http://localhost/`.

View File

@@ -16,19 +16,20 @@ export DEBIAN_FRONTEND=noninteractive #DOCS:
# Make sure all packages are up-to-date by running: # Make sure all packages are up-to-date by running:
# #
sudo apt update -qq sudo apt-get update -qq
# Now you can install all packages needed for Nominatim: # Now you can install all packages needed for Nominatim:
sudo apt install -y build-essential cmake g++ libboost-dev libboost-system-dev \ sudo apt-get install -y build-essential cmake g++ libboost-dev libboost-system-dev \
libboost-filesystem-dev libexpat1-dev zlib1g-dev \ libboost-filesystem-dev libexpat1-dev zlib1g-dev \
libbz2-dev libpq-dev liblua5.3-dev lua5.3 lua-dkjson \ libbz2-dev libpq-dev liblua5.3-dev lua5.3 lua-dkjson \
nlohmann-json3-dev postgresql-14-postgis-3 \ nlohmann-json3-dev postgresql-14-postgis-3 \
postgresql-contrib-14 postgresql-14-postgis-3-scripts \ postgresql-contrib-14 postgresql-14-postgis-3-scripts \
php-cli php-pgsql php-intl libicu-dev python3-dotenv \ libicu-dev python3-dotenv \
python3-psycopg2 python3-psutil python3-jinja2 \ python3-psycopg2 python3-psutil python3-jinja2 \
python3-icu python3-datrie python3-sqlalchemy \ python3-sqlalchemy python3-asyncpg \
python3-asyncpg python3-yaml git python3-icu python3-datrie python3-yaml git
# #
# System Configuration # System Configuration
@@ -128,20 +129,89 @@ fi #DOCS:
# Nominatim is now ready to use. You can continue with # Nominatim is now ready to use. You can continue with
# [importing a database from OSM data](../admin/Import.md). If you want to set up # [importing a database from OSM data](../admin/Import.md). If you want to set up
# a webserver first, continue reading. # the API frontend first, continue reading.
# #
# Setting up the Python frontend
# ==============================
#
# Some of the Python packages in Ubuntu are too old. Therefore run the
# frontend from a Python virtualenv with current packages.
#
# To set up the virtualenv, run:
#DOCS:```sh
sudo apt-get install -y virtualenv
virtualenv $USERHOME/nominatim-venv
$USERHOME/nominatim-venv/bin/pip install SQLAlchemy PyICU psycopg[binary] \
psycopg2-binary python-dotenv PyYAML falcon uvicorn gunicorn
#DOCS:```
# Next you need to create a systemd job that runs Nominatim on gunicorn.
# First create a systemd job that manages the socket file:
#DOCS:```sh
sudo tee /etc/systemd/system/nominatim.socket << EOFSOCKETSYSTEMD
[Unit]
Description=Gunicorn socket for Nominatim
[Socket]
ListenStream=/run/nominatim.sock
SocketUser=www-data
[Install]
WantedBy=multi-user.target
EOFSOCKETSYSTEMD
#DOCS:```
# Then create the service for Nominatim itself.
#DOCS:```sh
sudo tee /etc/systemd/system/nominatim.service << EOFNOMINATIMSYSTEMD
[Unit]
Description=Nominatim running as a gunicorn application
After=network.target
Requires=nominatim.socket
[Service]
Type=simple
Environment="PYTHONPATH=/usr/local/lib/nominatim/lib-python/"
User=www-data
Group=www-data
WorkingDirectory=$USERHOME/nominatim-project
ExecStart=$USERHOME/nominatim-venv/bin/gunicorn -b unix:/run/nominatim.sock -w 4 -k uvicorn.workers.UvicornWorker nominatim.server.falcon.server:run_wsgi
ExecReload=/bin/kill -s HUP \$MAINPID
StandardOutput=append:/var/log/gunicorn-nominatim.log
StandardError=inherit
PrivateTmp=true
TimeoutStopSec=5
KillMode=mixed
[Install]
WantedBy=multi-user.target
EOFNOMINATIMSYSTEMD
#DOCS:```
# Activate the services:
if [ "x$NOSYSTEMD" != "xyes" ]; then #DOCS:
sudo systemctl daemon-reload
sudo systemctl enable nominatim.socket
sudo systemctl start nominatim.socket
sudo systemctl enable nominatim.service
fi #DOCS:
# Setting up a webserver # Setting up a webserver
# ====================== # ======================
# #
# The webserver should serve the php scripts from the website directory of your # The webserver is only needed as a proxy between the public interface
# [project directory](../admin/Import.md#creating-the-project-directory). # and the gunicorn service.
# This directory needs to exist when being configured. #
# Therefore set up a project directory and create a website directory: # The frontend will need configuration information from the project
# directory, which will be populated later
# [during the import process](../admin/Import.md#creating-the-project-directory)
# Already create the project directory itself now:
mkdir $USERHOME/nominatim-project mkdir $USERHOME/nominatim-project
mkdir $USERHOME/nominatim-project/website
# The import process will populate the directory later.
# #
# Option 1: Using Apache # Option 1: Using Apache
@@ -149,24 +219,18 @@ fi #DOCS:
# #
if [ "x$2" == "xinstall-apache" ]; then #DOCS: if [ "x$2" == "xinstall-apache" ]; then #DOCS:
# #
# Apache has a PHP module that can be used to serve Nominatim. To install them # First install apache itself and enable the proxy module:
# run:
sudo apt install -y apache2 libapache2-mod-php sudo apt-get install -y apache2
sudo a2enmod proxy_http
# You need to create an alias to the website directory in your apache #
# configuration. Add a separate nominatim configuration to your webserver: # To set up proxying for Apache add the following configuration:
#DOCS:```sh #DOCS:```sh
sudo tee /etc/apache2/conf-available/nominatim.conf << EOFAPACHECONF sudo tee /etc/apache2/conf-available/nominatim.conf << EOFAPACHECONF
<Directory "$USERHOME/nominatim-project/website">
Options FollowSymLinks MultiViews
AddType text/html .php
DirectoryIndex search.php
Require all granted
</Directory>
Alias /nominatim $USERHOME/nominatim-project/website ProxyPass /nominatim "unix:/run/nominatim.sock|http://localhost/"
EOFAPACHECONF EOFAPACHECONF
#DOCS:``` #DOCS:```
@@ -174,7 +238,10 @@ EOFAPACHECONF
# Then enable the configuration and restart apache # Then enable the configuration and restart apache
# #
sudo a2enconf nominatim #DOCS:```sh
sudo a2enconf nominatim
#DOCS:```
if [ "x$NOSYSTEMD" == "xyes" ]; then #DOCS: if [ "x$NOSYSTEMD" == "xyes" ]; then #DOCS:
sudo apache2ctl start #DOCS: sudo apache2ctl start #DOCS:
else #DOCS: else #DOCS:
@@ -191,33 +258,10 @@ fi #DOCS:
# #
if [ "x$2" == "xinstall-nginx" ]; then #DOCS: if [ "x$2" == "xinstall-nginx" ]; then #DOCS:
# Nginx has no native support for php scripts. You need to set up php-fpm for # First install nginx itself:
# this purpose. First install nginx and php-fpm:
sudo apt install -y nginx php-fpm sudo apt-get install -y nginx
# You need to configure php-fpm to listen on a Unix socket.
#DOCS:```sh
sudo tee /etc/php/8.1/fpm/pool.d/www.conf << EOF_PHP_FPM_CONF
[www]
; Replace the tcp listener and add the unix socket
listen = /var/run/php-fpm-nominatim.sock
; Ensure that the daemon runs as the correct user
listen.owner = www-data
listen.group = www-data
listen.mode = 0666
; Unix user of FPM processes
user = www-data
group = www-data
; Choose process manager type (static, dynamic, ondemand)
pm = ondemand
pm.max_children = 5
EOF_PHP_FPM_CONF
#DOCS:```
# Then create a Nginx configuration to forward http requests to that socket. # Then create a Nginx configuration to forward http requests to that socket.
@@ -228,49 +272,28 @@ server {
listen [::]:80 default_server; listen [::]:80 default_server;
root $USERHOME/nominatim-project/website; root $USERHOME/nominatim-project/website;
index search.php index.html; index /search;
location / {
try_files \$uri \$uri/ @php;
}
location @php { location /nominatim/ {
fastcgi_param SCRIPT_FILENAME "\$document_root\$uri.php"; proxy_set_header Host \$http_host;
fastcgi_param PATH_TRANSLATED "\$document_root\$uri.php"; proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
fastcgi_param QUERY_STRING \$args; proxy_set_header X-Forwarded-Proto \$scheme;
fastcgi_pass unix:/var/run/php-fpm-nominatim.sock; proxy_redirect off;
fastcgi_index index.php; proxy_pass http://unix:/run/nominatim.sock:/;
include fastcgi_params;
}
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
if (!-f \$document_root\$fastcgi_script_name) {
return 404;
}
fastcgi_pass unix:/var/run/php-fpm-nominatim.sock;
fastcgi_index search.php;
include fastcgi.conf;
} }
} }
EOF_NGINX_CONF EOF_NGINX_CONF
#DOCS:``` #DOCS:```
# If you have some errors, make sure that php-fpm-nominatim.sock is well under
# /var/run/ and not under /var/run/php. Otherwise change the Nginx configuration
# to /var/run/php/php-fpm-nominatim.sock.
#
# Enable the configuration and restart Nginx # Enable the configuration and restart Nginx
# #
if [ "x$NOSYSTEMD" == "xyes" ]; then #DOCS: if [ "x$NOSYSTEMD" == "xyes" ]; then #DOCS:
sudo /usr/sbin/php-fpm8.1 --nodaemonize --fpm-config /etc/php/8.1/fpm/php-fpm.conf & #DOCS:
sudo /usr/sbin/nginx & #DOCS: sudo /usr/sbin/nginx & #DOCS:
else #DOCS: else #DOCS:
sudo systemctl restart php8.1-fpm nginx sudo systemctl restart nginx
fi #DOCS: fi #DOCS:
# The Nominatim API is now available at `http://localhost/`. # The Nominatim API is now available at `http://localhost/nominatim/`.
fi #DOCS: fi #DOCS: