diff --git a/config/.env.sample b/config/.env.sample index b45ee2f..f6f4c49 100644 --- a/config/.env.sample +++ b/config/.env.sample @@ -1,20 +1,21 @@ # Leave it empty if you use SSH keys SSH_PASSWD= -# Domain to server directly, with Let's Encrypt certificates -DOMAIN_LE=test.openfreemap.org +# Direct subdomain, using Let's Encrypt certificates +DOMAIN_LE=le.openfreemap.org # Let's Encrypt account email LE_EMAIL= -# Domain via CloudFlare, using origin certificates +# CloudFlare subdomain, using origin certificates # Please put ofm_cf.key and ofm_cf.cert files in config/certs DOMAIN_CF=tiles.openfreemap.org # Skip the full planet download, useful for testing (true/false) SKIP_PLANET=false + # --- Let's Encrypt DNS related variables, not needed for self-hosting -DOMAIN_LEDNS = rr.openfreemap.org +DOMAIN_LEDNS = direct.openfreemap.org diff --git a/init-server.py b/init-server.py index 61456a1..156c10d 100755 --- a/init-server.py +++ b/init-server.py @@ -12,6 +12,7 @@ from ssh_lib.tasks import ( run_http_host_sync, setup_ledns_writer, upload_http_host_config, + upload_http_host_files, ) from ssh_lib.utils import ( sudo_cmd, @@ -112,12 +113,8 @@ def ledns_writer(hostname, user, port): def debug(hostname, user, port): c = get_connection(hostname, user, port) - prepare_shared(c) upload_http_host_config(c) - - prepare_http_host(c) - - run_http_host_sync(c) + upload_http_host_files(c) sudo_cmd(c, '/data/ofm/venv/bin/python -u /data/ofm/http_host/bin/host_manager.py nginx-sync') diff --git a/scripts/http_host/http_host_lib/__init__.py b/scripts/http_host/http_host_lib/__init__.py index 7aebcc1..5280a29 100644 --- a/scripts/http_host/http_host_lib/__init__.py +++ b/scripts/http_host/http_host_lib/__init__.py @@ -9,6 +9,7 @@ DEFAULT_ASSETS_DIR = Path('/data/ofm/http_host/assets') MNT_DIR = Path('/mnt/ofm') OFM_CONFIG_DIR = Path('/data/ofm/config') +HTTP_HOST_BIN_DIR = Path('/data/ofm/http_host/bin') CERTS_DIR = Path('/data/nginx/certs') diff --git a/scripts/http_host/http_host_lib/nginx.py b/scripts/http_host/http_host_lib/nginx.py index 9acb695..b72990e 100644 --- a/scripts/http_host/http_host_lib/nginx.py +++ b/scripts/http_host/http_host_lib/nginx.py @@ -7,6 +7,7 @@ from http_host_lib import ( CERTS_DIR, DEFAULT_RUNS_DIR, HOST_CONFIG, + HTTP_HOST_BIN_DIR, MNT_DIR, NGINX_DIR, OFM_CONFIG_DIR, @@ -18,6 +19,7 @@ def write_nginx_config(): domain_cf = HOST_CONFIG['domain_cf'] domain_le = HOST_CONFIG['domain_le'] + domain_ledns = HOST_CONFIG['domain_ledns'] # processing Cloudflare config if domain_cf: @@ -30,6 +32,21 @@ def write_nginx_config(): domain=domain_cf, ) + # processing Cloudflare config + if domain_ledns: + if not (OFM_CONFIG_DIR / 'rclone.conf').is_file(): + sys.exit('rclone.conf missing') + + # download the ledns certificate from bucket using rclone + write_ledns_reader_script(domain_ledns) + subprocess.run(['bash', HTTP_HOST_BIN_DIR / 'ledns_reader.sh'], check=True) + + curl_text_mix += create_nginx_conf( + template_path=NGINX_DIR / 'ledns.conf', + local='ofm_ledns', + domain=domain_ledns, + ) + # processing Let's Encrypt config if domain_le: le_cert = CERTS_DIR / 'ofm_le.cert' @@ -59,6 +76,7 @@ def write_nginx_config(): HOST_CONFIG['le_email'], '--agree-tos', '--cert-name=ofm_le', + # '--staging', '--deploy-hook', 'nginx -t && service nginx reload', '-d', @@ -215,3 +233,15 @@ def create_latest_locations(*, local: str, domain: str) -> str: """ return location_str + + +def write_ledns_reader_script(domain_ledns): + script = f""" +#!/usr/bin/env bash +export RCLONE_CONFIG=/data/ofm/config/rclone.conf +rclone copyto -v "remote:ofm-private/ledns/{domain_ledns}/ofm_ledns.cert" /data/nginx/certs/ofm_ledns.cert +rclone copyto -v "remote:ofm-private/ledns/{domain_ledns}/ofm_ledns.key" /data/nginx/certs/ofm_ledns.key + """.strip() + + with open(HTTP_HOST_BIN_DIR / 'ledns_reader.sh', 'w') as fp: + fp.write(script) diff --git a/scripts/http_host/http_host_lib/nginx/ledns.conf b/scripts/http_host/http_host_lib/nginx/ledns.conf new file mode 100644 index 0000000..7b65346 --- /dev/null +++ b/scripts/http_host/http_host_lib/nginx/ledns.conf @@ -0,0 +1,38 @@ +server { + server_name __LOCAL__ __DOMAIN__; + + # ssl: https://ssl-config.mozilla.org / intermediate config + + listen 80; + listen 443 ssl; + listen [::]:443 ssl; + http2 on; + + ssl_certificate /data/nginx/certs/ofm_ledns.cert; + ssl_certificate_key /data/nginx/certs/ofm_ledns.key; + + ssl_session_timeout 1d; + ssl_session_cache shared:MozSSL:10m; # about 40000 sessions + ssl_session_tickets off; + + ssl_dhparam /etc/nginx/ffdhe2048.txt; + + # intermediate configuration + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305; + ssl_prefer_server_ciphers off; + + # access log disabled by default + #access_log /data/ofm/http_host/logs_nginx/ledns-access.log access_json buffer=32k; + access_log off; + + error_log /data/ofm/http_host/logs_nginx/ledns-error.log; + + __LOCATION_BLOCKS__ + + # catch-all block to deny all other requests + location / { + deny all; + error_log /data/ofm/http_host/logs_nginx/__LOCAL__-error.log error; + } +} diff --git a/ssh_lib/tasks.py b/ssh_lib/tasks.py index acce64a..5547048 100644 --- a/ssh_lib/tasks.py +++ b/ssh_lib/tasks.py @@ -26,6 +26,7 @@ def prepare_shared(c): pkg_upgrade(c) pkg_base(c) + rclone(c) kernel_tweaks_ofm(c) @@ -49,7 +50,6 @@ def prepare_venv(c): def prepare_tile_gen(c): planetiler(c) - rclone(c) for file in [ 'extract_btrfs.sh', @@ -95,6 +95,7 @@ def prepare_tile_gen(c): def upload_http_host_config(c): domain_le = dotenv_val('DOMAIN_LE').lower() domain_cf = dotenv_val('DOMAIN_CF').lower() + domain_ledns = dotenv_val('DOMAIN_LEDNS').lower() skip_planet = dotenv_val('SKIP_PLANET').lower() == 'true' le_email = dotenv_val('LE_EMAIL').lower() @@ -116,6 +117,7 @@ def upload_http_host_config(c): host_config = { 'domain_le': domain_le, 'domain_cf': domain_cf, + 'domain_ledns': domain_ledns, 'skip_planet': skip_planet, 'le_email': le_email, } @@ -124,6 +126,15 @@ def upload_http_host_config(c): print(host_config_str) put_str(c, '/data/ofm/config/http_host.json', host_config_str) + if domain_ledns: + assert (CONFIG_DIR / 'rclone.conf').exists() + put( + c, + CONFIG_DIR / 'rclone.conf', + f'{REMOTE_CONFIG}/rclone.conf', + permissions=400, + ) + def prepare_http_host(c): nginx(c) @@ -137,7 +148,7 @@ def prepare_http_host(c): c.sudo('mkdir -p /data/ofm/http_host/logs_nginx') c.sudo('chown nginx:nginx /data/ofm/http_host/logs_nginx') - upload_https_host_files(c) + upload_http_host_files(c) upload_certificates(c) c.sudo('/data/ofm/venv/bin/pip install -e /data/ofm/http_host/bin') @@ -151,7 +162,7 @@ def run_http_host_sync(c): sudo_cmd(c, '/data/ofm/venv/bin/python -u /data/ofm/http_host/bin/host_manager.py sync') -def upload_https_host_files(c): +def upload_http_host_files(c): c.sudo(f'mkdir -p {HTTP_HOST_BIN}') put_dir(c, SCRIPTS_DIR / 'http_host', HTTP_HOST_BIN, file_permissions='755')