From: Sarah Hoffmann Date: Tue, 20 Feb 2024 09:17:21 +0000 (+0100) Subject: Merge pull request #3339 from lonvia/python-frontend-as-default X-Git-Tag: v4.4.0~14 X-Git-Url: https://git.openstreetmap.org/nominatim.git/commitdiff_plain/5afd96d210ed0ad14a5d00f832f6e6a28558e733?hp=19360a95522828c733e4ab174da9a9147ae308bf Merge pull request #3339 from lonvia/python-frontend-as-default Switch to Python frontend as the default --- diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index e3d7b4a6..910114d7 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -11,7 +11,7 @@ jobs: with: submodules: true - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: | data/country_osm_grid.sql.gz @@ -27,7 +27,7 @@ jobs: mv nominatim-src.tar.bz2 Nominatim - name: 'Upload Artifact' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: full-source path: nominatim-src.tar.bz2 @@ -43,40 +43,28 @@ jobs: ubuntu: 20 postgresql: '9.6' postgis: '2.5' - php: '7.3' lua: '5.1' - flavour: ubuntu-20 ubuntu: 20 postgresql: 13 postgis: 3 - php: '7.4' lua: '5.3' - flavour: ubuntu-22 ubuntu: 22 postgresql: 15 postgis: 3 - php: '8.1' lua: '5.3' runs-on: ubuntu-${{ matrix.ubuntu }}.04 steps: - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: full-source - name: Unpack Nominatim 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 with: python-version: 3.7 @@ -119,20 +107,11 @@ jobs: run: pip3 install -U pylint if: matrix.flavour != 'oldstuff' - - name: PHP linting - run: phpcs --report-width=120 . - working-directory: Nominatim - if: matrix.flavour != 'oldstuff' - - name: Python linting run: python3 -m pylint nominatim working-directory: Nominatim if: matrix.flavour != 'oldstuff' - - name: PHP unit tests - run: phpunit ./ - working-directory: Nominatim/test/php - - name: Python unit tests run: python3 -m pytest test/python working-directory: Nominatim @@ -156,7 +135,7 @@ jobs: runs-on: ubuntu-20.04 steps: - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: full-source @@ -185,16 +164,16 @@ jobs: - name: BDD tests (legacy tokenizer) 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 - python-api-test: + php-test: needs: create-archive runs-on: ubuntu-22.04 steps: - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: full-source @@ -206,6 +185,23 @@ jobs: postgresql-version: 15 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 with: flavour: 'ubuntu-22' @@ -213,12 +209,9 @@ jobs: - name: Install test prerequsites run: sudo apt-get install -y -qq python3-behave - - name: Install Python webservers - run: pip3 install starlette asgi_lifespan httpx - - - name: BDD tests (starlette) + - name: BDD tests (php) 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 @@ -268,7 +261,7 @@ jobs: OS: ${{ matrix.name }} INSTALL_MODE: ${{ matrix.install_mode }} - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: full-source path: /home/nominatim @@ -355,7 +348,7 @@ jobs: needs: create-archive steps: - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: 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 - name: Check full import - run: | - nominatim admin --check-database + run: nominatim admin --check-database diff --git a/CMakeLists.txt b/CMakeLists.txt index 536b21bc..6bd99967 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,13 +82,14 @@ endif() # 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) find_program (PHP_BIN php) endif() # sanity check if PHP binary exists 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() message (STATUS "Using PHP binary " ${PHP_BIN}) endif() @@ -226,7 +227,11 @@ if (BUILD_IMPORTER) PATTERN "paths.py" 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 DESTINATION ${NOMINATIM_LIBDIR}/lib-python/nominatim RENAME paths.py) @@ -254,7 +259,7 @@ if (BUILD_MODULE) DESTINATION ${NOMINATIM_LIBDIR}/module) endif() -if (BUILD_API) +if (BUILD_API AND EXISTS ${PHP_BIN}) install(DIRECTORY lib-php DESTINATION ${NOMINATIM_LIBDIR}) endif() diff --git a/Vagrantfile b/Vagrantfile index 57e64c2c..7f5f2459 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -38,7 +38,7 @@ Vagrant.configure("2") do |config| lv.memory = 2048 lv.nested = true 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 diff --git a/cmake/paths-py-no-php.tmpl b/cmake/paths-py-no-php.tmpl new file mode 100644 index 00000000..36856bf3 --- /dev/null +++ b/cmake/paths-py-no-php.tmpl @@ -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() diff --git a/docs/admin/Import.md b/docs/admin/Import.md index 0fd5ec29..b31066d3 100644 --- a/docs/admin/Import.md +++ b/docs/admin/Import.md @@ -268,18 +268,26 @@ nominatim reverse --lat 51 --lon 45 ``` 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 [Installation](Installation.md#software). -#### Testing the PHP frontend +#### Testing the Python frontend -You can run a small test server with the PHP frontend like this: +To run the test server against the Python frontend, you must choose a +web framework to use, either starlette or falcon. Make sure the appropriate +packages are installed. Then run -```sh +``` sh nominatim serve ``` +or, if you prefer to use Starlette instead of Falcon as webserver, + +``` sh +nominatim serve --engine starlette +``` + 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, @@ -287,22 +295,14 @@ 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 - -To run the test server against the Python frontend, you must choose a -web framework to use, either starlette or falcon. Make sure the appropriate -packages are installed. Then run +[Deploy the Python frontend](Deployment-Python.md). -``` sh -nominatim serve --engine falcon -``` +#### Testing the PHP frontend -or +You can run a small test server with the PHP frontend like this: -``` sh -nominatim serve --engine starlette +```sh +nominatim serve --engine php ``` Go to `http://localhost:8088/status.php` and you should see the message `OK`. @@ -312,7 +312,8 @@ 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 Python frontend](Deployment-Python.md). +[Deploy the PHP frontend](Deployment-PHP.md). + ## Enabling search by category phrases diff --git a/docs/admin/Installation.md b/docs/admin/Installation.md index 89e56c6e..ef6bd081 100644 --- a/docs/admin/Installation.md +++ b/docs/admin/Installation.md @@ -55,23 +55,24 @@ For running Nominatim: * [PyYaml](https://pyyaml.org/) (5.1+) * [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: * [pyosmium](https://osmcode.org/pyosmium/) -For running the experimental Python frontend: +For running the Python frontend: * one of the following web frameworks: * [falcon](https://falconframework.org/) (3.0+) * [starlette](https://www.starlette.io/) * [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 the [Development section](../develop/Development-Environment.md). diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index f332640f..74465d1a 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -22,8 +22,8 @@ nav: - 'Basic Installation': 'admin/Installation.md' - 'Import' : 'admin/Import.md' - 'Update' : 'admin/Update.md' - - 'Deploy (PHP frontend)' : 'admin/Deployment-PHP.md' - 'Deploy (Python frontend)' : 'admin/Deployment-Python.md' + - 'Deploy (PHP frontend)' : 'admin/Deployment-PHP.md' - 'Nominatim UI' : 'admin/Setup-Nominatim-UI.md' - 'Advanced Installations' : 'admin/Advanced-Installations.md' - 'Maintenance' : 'admin/Maintenance.md' diff --git a/nominatim/api/logging.py b/nominatim/api/logging.py index e16e0bd2..2d9a487a 100644 --- a/nominatim/api/logging.py +++ b/nominatim/api/logging.py @@ -13,6 +13,7 @@ import datetime as dt import textwrap import io import re +import html import sqlalchemy as sa from sqlalchemy.ext.asyncio import AsyncConnection @@ -227,7 +228,7 @@ class HTMLLogger(BaseLogger): HtmlFormatter(nowrap=True, lineseparator='
')) self._write(f'
{sqlstr}
') else: - self._write(f'{sqlstr}') + self._write(f'{html.escape(sqlstr)}') def _python_var(self, var: Any) -> str: @@ -235,7 +236,7 @@ class HTMLLogger(BaseLogger): fmt = highlight(str(var), PythonLexer(), HtmlFormatter(nowrap=True)) return f'
{fmt}
' - return f'{str(var)}' + return f'{html.escape(str(var))}' def _write(self, text: str) -> None: diff --git a/nominatim/cli.py b/nominatim/cli.py index 88a60782..720a8ece 100644 --- a/nominatim/cli.py +++ b/nominatim/cli.py @@ -159,13 +159,15 @@ class AdminServe: group = parser.add_argument_group('Server arguments') group.add_argument('--server', default='127.0.0.1:8088', help='The address the server will listen to.') - group.add_argument('--engine', default='php', + group.add_argument('--engine', default='falcon', choices=('php', 'falcon', 'starlette'), - help='Webserver framework to run. (default: php)') + help='Webserver framework to run. (default: falcon)') def run(self, args: NominatimArgs) -> int: 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') else: import uvicorn # pylint: disable=import-outside-toplevel diff --git a/nominatim/tokenizer/icu_tokenizer.py b/nominatim/tokenizer/icu_tokenizer.py index 5a90edf5..84b4b924 100644 --- a/nominatim/tokenizer/icu_tokenizer.py +++ b/nominatim/tokenizer/icu_tokenizer.py @@ -214,19 +214,20 @@ class ICUTokenizer(AbstractTokenizer): 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. """ - assert self.loader is not None - php_file = self.data_dir / "tokenizer.php" - - if not php_file.exists() or overwrite: - php_file.write_text(dedent(f"""\ - None: diff --git a/nominatim/tokenizer/legacy_tokenizer.py b/nominatim/tokenizer/legacy_tokenizer.py index 2d28a8b2..f3a00839 100644 --- a/nominatim/tokenizer/legacy_tokenizer.py +++ b/nominatim/tokenizer/legacy_tokenizer.py @@ -269,15 +269,16 @@ class LegacyTokenizer(AbstractTokenizer): def _install_php(self, config: Configuration, overwrite: bool = True) -> None: """ Install the php script for the tokenizer. """ - php_file = self.data_dir / "tokenizer.php" - - if not php_file.exists() or overwrite: - php_file.write_text(dedent(f"""\ - None: diff --git a/nominatim/tools/refresh.py b/nominatim/tools/refresh.py index 43e5b1eb..008fc714 100644 --- a/nominatim/tools/refresh.py +++ b/nominatim/tools/refresh.py @@ -213,6 +213,10 @@ def _quote_php_variable(var_type: Type[Any], config: Configuration, def setup_website(basedir: Path, config: Configuration, conn: Connection) -> None: """ 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(): LOG.info('Creating website directory.') basedir.mkdir() diff --git a/test/bdd/environment.py b/test/bdd/environment.py index 664b5ac7..460f3569 100644 --- a/test/bdd/environment.py +++ b/test/bdd/environment.py @@ -28,7 +28,7 @@ userconfig = { 'SERVER_MODULE_PATH' : None, 'TOKENIZER' : None, # Test with a custom tokenizer 'STYLE' : 'extratags', - 'API_ENGINE': 'php', + 'API_ENGINE': 'falcon', 'PHPCOV' : False, # set to output directory to enable code coverage } diff --git a/test/bdd/steps/steps_api_queries.py b/test/bdd/steps/steps_api_queries.py index 3d3b16c7..aa1b43b8 100644 --- a/test/bdd/steps/steps_api_queries.py +++ b/test/bdd/steps/steps_api_queries.py @@ -243,7 +243,7 @@ def step_impl(context, fmt): try: tree = ET.fromstring(context.response.page) 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' body = tree.find('./body') diff --git a/test/python/cli/test_cli.py b/test/python/cli/test_cli.py index 93e86108..d455f35e 100644 --- a/test/python/cli/test_cli.py +++ b/test/python/cli/test_cli.py @@ -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): func = mock_func_factory(nominatim.cli, 'run_php_server') - cli_call('serve') == 0 + cli_call('serve', '--engine', 'php') == 0 assert func.called == 1 diff --git a/vagrant/Install-on-Ubuntu-20.sh b/vagrant/Install-on-Ubuntu-20.sh index 720e80c8..57361ec7 100755 --- a/vagrant/Install-on-Ubuntu-20.sh +++ b/vagrant/Install-on-Ubuntu-20.sh @@ -16,16 +16,16 @@ export DEBIAN_FRONTEND=noninteractive #DOCS: # 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: - 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 \ libbz2-dev libpq-dev liblua5.3-dev lua5.3 lua-dkjson \ nlohmann-json3-dev postgresql-12-postgis-3 \ 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-icu python3-datrie python3-yaml git @@ -133,45 +133,107 @@ fi #DOCS: # 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 -# 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 # ====================== # -# The webserver should serve the php scripts from the website directory of your -# [project directory](../admin/Import.md#creating-the-project-directory). -# This directory needs to exist when being configured. -# Therefore set up a project directory and create a website directory: +# The webserver is only needed as a proxy between the public interface +# and the gunicorn service. +# +# 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/website -# The import process will populate the directory later. -# # Option 1: Using Apache # ---------------------- # if [ "x$2" == "xinstall-apache" ]; then #DOCS: -# -# Apache has a PHP module that can be used to serve Nominatim. To install them -# run: +# First install apache itself and enable the proxy module: - 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 sudo tee /etc/apache2/conf-available/nominatim.conf << EOFAPACHECONF - - Options FollowSymLinks MultiViews - AddType text/html .php - DirectoryIndex search.php - Require all granted - - -Alias /nominatim $USERHOME/nominatim-project/website +ProxyPass /nominatim "unix:/run/nominatim.sock|http://localhost/" EOFAPACHECONF #DOCS:``` @@ -196,33 +258,9 @@ fi #DOCS: # if [ "x$2" == "xinstall-nginx" ]; then #DOCS: -# Nginx has no native support for php scripts. You need to set up php-fpm for -# this purpose. First install nginx and php-fpm: - - sudo apt install -y nginx php-fpm +# First install nginx itself: -# 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:``` + sudo apt-get install -y nginx # Then create a Nginx configuration to forward http requests to that socket. @@ -233,45 +271,26 @@ server { listen [::]:80 default_server; root $USERHOME/nominatim-project/website; - index search.php index.html; - location / { - try_files \$uri \$uri/ @php; - } - - location @php { - fastcgi_param SCRIPT_FILENAME "\$document_root\$uri.php"; - fastcgi_param PATH_TRANSLATED "\$document_root\$uri.php"; - fastcgi_param QUERY_STRING \$args; - fastcgi_pass unix:/var/run/php-fpm-nominatim.sock; - fastcgi_index index.php; - 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; + index /search; + + location /nominatim/ { + proxy_set_header Host \$http_host; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto \$scheme; + proxy_redirect off; + proxy_pass http://unix:/run/nominatim.sock:/; } } EOF_NGINX_CONF #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 # 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: else #DOCS: - sudo systemctl restart php7.4-fpm nginx + sudo systemctl restart nginx fi #DOCS: # The Nominatim API is now available at `http://localhost/`. diff --git a/vagrant/Install-on-Ubuntu-22.sh b/vagrant/Install-on-Ubuntu-22.sh index 174b8a77..ae0c0dea 100755 --- a/vagrant/Install-on-Ubuntu-22.sh +++ b/vagrant/Install-on-Ubuntu-22.sh @@ -16,19 +16,20 @@ export DEBIAN_FRONTEND=noninteractive #DOCS: # 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: - 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 \ libbz2-dev libpq-dev liblua5.3-dev lua5.3 lua-dkjson \ nlohmann-json3-dev postgresql-14-postgis-3 \ 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-icu python3-datrie python3-sqlalchemy \ - python3-asyncpg python3-yaml git + python3-sqlalchemy python3-asyncpg \ + python3-icu python3-datrie python3-yaml git + # # System Configuration @@ -128,20 +129,89 @@ fi #DOCS: # 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 -# 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 # ====================== # -# The webserver should serve the php scripts from the website directory of your -# [project directory](../admin/Import.md#creating-the-project-directory). -# This directory needs to exist when being configured. -# Therefore set up a project directory and create a website directory: +# The webserver is only needed as a proxy between the public interface +# and the gunicorn service. +# +# 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/website - -# The import process will populate the directory later. # # Option 1: Using Apache @@ -149,24 +219,18 @@ fi #DOCS: # if [ "x$2" == "xinstall-apache" ]; then #DOCS: # -# Apache has a PHP module that can be used to serve Nominatim. To install them -# run: +# First install apache itself and enable the proxy module: - 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 sudo tee /etc/apache2/conf-available/nominatim.conf << EOFAPACHECONF - - Options FollowSymLinks MultiViews - AddType text/html .php - DirectoryIndex search.php - Require all granted - - -Alias /nominatim $USERHOME/nominatim-project/website + +ProxyPass /nominatim "unix:/run/nominatim.sock|http://localhost/" EOFAPACHECONF #DOCS:``` @@ -174,7 +238,10 @@ EOFAPACHECONF # Then enable the configuration and restart apache # - sudo a2enconf nominatim +#DOCS:```sh +sudo a2enconf nominatim +#DOCS:``` + if [ "x$NOSYSTEMD" == "xyes" ]; then #DOCS: sudo apache2ctl start #DOCS: else #DOCS: @@ -191,33 +258,10 @@ fi #DOCS: # if [ "x$2" == "xinstall-nginx" ]; then #DOCS: -# Nginx has no native support for php scripts. You need to set up php-fpm for -# this purpose. First install nginx and php-fpm: +# First install nginx itself: - 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. @@ -228,49 +272,28 @@ server { listen [::]:80 default_server; root $USERHOME/nominatim-project/website; - index search.php index.html; - location / { - try_files \$uri \$uri/ @php; - } - - location @php { - fastcgi_param SCRIPT_FILENAME "\$document_root\$uri.php"; - fastcgi_param PATH_TRANSLATED "\$document_root\$uri.php"; - fastcgi_param QUERY_STRING \$args; - fastcgi_pass unix:/var/run/php-fpm-nominatim.sock; - fastcgi_index index.php; - 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; + index /search; + + location /nominatim/ { + proxy_set_header Host \$http_host; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto \$scheme; + proxy_redirect off; + proxy_pass http://unix:/run/nominatim.sock:/; } } EOF_NGINX_CONF #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 # 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: else #DOCS: - sudo systemctl restart php8.1-fpm nginx + sudo systemctl restart nginx fi #DOCS: -# The Nominatim API is now available at `http://localhost/`. - - +# The Nominatim API is now available at `http://localhost/nominatim/`. fi #DOCS: