diff --git a/.env.sample b/.env.sample index 2e8a17e..5b88fc0 100644 --- a/.env.sample +++ b/.env.sample @@ -6,3 +6,59 @@ DOMAIN=umap.example.com #EXTRA_DOMAINS=', `www.umap.example.com`' LETS_ENCRYPT_ENV=production + +SECRET_SECRET_KEY_VERSION=v1 # length=100 charset=hex + +SITE_URL=https://$DOMAIN +SITE_NAME=My UMap Server +SITE_DESCRIPTION=Welcome to my map of the world. No borders, no nations. +#UMAP_HELP_URL=http://mysite.com/documentation +#UMAP_HOME_FEED="highlighted" + +## Account/Permissions +#ENABLE_ACCOUNT_LOGIN=1 +#UMAP_ALLOW_ANONYMOUS=1 +#UMAP_ALLOW_EDIT_PROFILE=0 +#UMAP_DEFAULT_EDIT_STATUS=3 +#UMAP_DEFAULT_SHARE_STATUS=3 + +## Language/Localization +#USE_I18N=false +#LANGUAGE_CODE="it" +#LEAFLET_LONGITUDE="15" +#LEAFLET_LATITUDE="15" +#LEAFLET_ZOOM="5" + +#UMAP_DEMO_SITE=1 +#UMAP_READONLY=1 + +#UMAP_MAPS_PER_PAGE=10 +#UMAP_MAPS_PER_SEARCH=10 +#UMAP_MAPS_PER_PAGE_OWNER=10 +#UMAP_LABEL_KEYS='["name", "title"]' +#DEBUG=true +#UMAP_GZIP=1 +#SHORT_SITE_URL= +#UMAP_KEEP_VERSIONS=10 + +# OPENROUTESERVICE_APIKEY=WIP + +## Email Settings +#DEFAULT_FROM_EMAIL = "youradmin@email.org" +#EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" +#EMAIL_HOST = "smtp.provider.org" +#EMAIL_PORT = 456 +#EMAIL_HOST_USER = "username" +#EMAIL_HOST_PASSWORD = "xxxx" +#EMAIL_USE_TLS = True +#EMAIL_USE_SSL = True + +## OpenStreetMaps OAuth +# WIP +#SOCIAL_AUTH_OPENSTREETMAP_OAUTH2_KEY, SOCIAL_AUTH_OPENSTREETMAP_OAUTH2_SECRET + +## General OAuth +# WIP +#https://python-social-auth.readthedocs.io/en/latest/configuration/django.html +#USER_DISPLAY_NAME= +#USER_URL_FIELD= \ No newline at end of file diff --git a/abra.sh b/abra.sh index 13b5452..beb290c 100755 --- a/abra.sh +++ b/abra.sh @@ -1,2 +1,6 @@ # Set any config versions here # Docs: https://docs.coopcloud.tech/maintainers/handbook/#manage-configs + +export CONFIG_VERSION=v1 +export NGINX_VERSION=v1 +export NGINX_UMAP_VERSION=v1 \ No newline at end of file diff --git a/compose.yml b/compose.yml index 5e77224..263e073 100644 --- a/compose.yml +++ b/compose.yml @@ -1,39 +1,116 @@ --- services: - app: - image: nginx:1.27.5 + proxy: + image: nginx:1.29.4 + deploy: + labels: + - "traefik.enable=true" + - "traefik.docker.network=proxy" + - "traefik.http.services.${STACK_NAME}.loadbalancer.server.port=80" + - "traefik.http.routers.${STACK_NAME}.rule=Host(`${DOMAIN}`${EXTRA_DOMAINS})" + - "traefik.http.routers.${STACK_NAME}.entrypoints=web-secure" + - "traefik.http.routers.${STACK_NAME}.tls.certresolver=${LETS_ENCRYPT_ENV}" + ## Edit the following line if you are using one, but not both, "Redirect" sections below + #- "traefik.http.routers.${STACK_NAME}.middlewares=${STACK_NAME}-redirectscheme,${STACK_NAME}-redirecthostname" + ## Redirect from EXTRA_DOMAINS to DOMAIN + # - "traefik.http.middlewares.${STACK_NAME}-redirecthostname.redirectregex.regex=^http[s]?://([^/]*)/(.*)" + # - "traefik.http.middlewares.${STACK_NAME}-redirecthostname.redirectregex.replacement=https://${DOMAIN}/$${2}" + # - "traefik.http.middlewares.${STACK_NAME}-redirecthostname.redirectregex.permanent=true" + ## Redirect HTTP to HTTPS + # - "traefik.http.middlewares.${STACK_NAME}-redirectscheme.redirectscheme.scheme=https" + # - "traefik.http.middlewares.${STACK_NAME}-redirectscheme.redirectscheme.permanent=true" + volumes: + - static:/static:ro + - data:/data:ro + configs: + - source: nginx + target: /etc/nginx/nginx.conf + mode: 0600 + - source: nginx_umap + target: /etc/nginx/snippets/umap.conf + mode: 0600 networks: - proxy + - umap + + + umap: + image: umap/umap:3.5.0 + networks: + - umap deploy: restart_policy: condition: on-failure labels: - - "traefik.enable=true" - - "traefik.http.services.${STACK_NAME}.loadbalancer.server.port=80" - - "traefik.http.routers.${STACK_NAME}.rule=Host(`${DOMAIN}`${EXTRA_DOMAINS})" - - "traefik.http.routers.${STACK_NAME}.entrypoints=web-secure" - - "traefik.http.routers.${STACK_NAME}.tls.certresolver=${LETS_ENCRYPT_ENV}" - ## Edit the following line if you are using one, but not both, "Redirect" sections below - #- "traefik.http.routers.${STACK_NAME}.middlewares=${STACK_NAME}-redirectscheme,${STACK_NAME}-redirecthostname" - ## Redirect from EXTRA_DOMAINS to DOMAIN - # - "traefik.http.middlewares.${STACK_NAME}-redirecthostname.redirectregex.regex=^http[s]?://([^/]*)/(.*)" - # - "traefik.http.middlewares.${STACK_NAME}-redirecthostname.redirectregex.replacement=https://${DOMAIN}/$${2}" - # - "traefik.http.middlewares.${STACK_NAME}-redirecthostname.redirectregex.permanent=true" - ## Redirect HTTP to HTTPS - # - "traefik.http.middlewares.${STACK_NAME}-redirectscheme.redirectscheme.scheme=https" - # - "traefik.http.middlewares.${STACK_NAME}-redirectscheme.redirectscheme.permanent=true" ## When you're ready for release, run "abra recipe sync " to set this - - "coop-cloud.${STACK_NAME}.version=" + - "coop-cloud.${STACK_NAME}.version=0.0.1+2.9.3" ## Enable backups: https://docs.coopcloud.tech/maintainers/handbook/#how-do-i-configure-backuprestore # - "backupbot.backup=true" # - "backupbot.backup.path=/some/path" + environment: + DATABASE_URL: postgis://postgres@db/postgres + STATIC_ROOT: /srv/umap/static + MEDIA_ROOT: /srv/umap/uploads + REALTIME_ENABLED: 1 + REDIS_URL: redis://redis:6379 + ALLOWED_HOSTS: $DOMAIN + volumes: + - data:/srv/umap/uploads + - static:/srv/umap/static + configs: + - source: config + target: /etc/umap/umap.conf + mode: 0600 + secrets: + - secret_key +# healthcheck: +# test: ["CMD", "curl", "-f", "http://localhost:9000"] +# interval: 30s +# timeout: 10s +# retries: 10 +# start_period: 1m + db: + image: postgis/postgis:14-3.4-alpine + networks: + - umap + environment: + - POSTGRES_HOST_AUTH_METHOD=trust + volumes: + - db:/var/lib/postgresql/data + + redis: + image: redis:8.4.0 + command: ["redis-server"] healthcheck: - test: ["CMD", "curl", "-f", "http://localhost"] - interval: 30s - timeout: 10s - retries: 10 - start_period: 1m + test: ["CMD-SHELL", "redis-cli ping | grep PONG"] + networks: + - umap + +volumes: + data: + static: + db: + +secrets: + secret_key: + external: true + name: ${STACK_NAME}_secret_key_${SECRET_SECRET_KEY_VERSION} + +configs: + config: + name: ${STACK_NAME}_config_${CONFIG_VERSION} + file: ./umap.conf.tmpl + template_driver: golang + nginx: + name: ${STACK_NAME}_nginx_${NGINX_VERSION} + file: ./nginx.conf.tmpl + template_driver: golang + nginx_umap: + name: ${STACK_NAME}_nginx_umap_${NGINX_UMAP_VERSION} + file: ./nginx-umap.conf + template_driver: golang networks: + umap: proxy: external: true diff --git a/nginx-umap.conf b/nginx-umap.conf new file mode 100644 index 0000000..9b7b870 --- /dev/null +++ b/nginx-umap.conf @@ -0,0 +1,67 @@ +# Static file serving +location /static/ { + alias /static/; + gzip on; + gzip_vary on; + gzip_proxied any; + gzip_types text/plain application/javascript application/x-javascript text/javascript text/xml text/css; + expires 365d; + access_log /dev/null; +} + +# Geojson files +location /uploads/ { + alias /data/; + expires 30d; +} + +location /favicon.ico { + alias /static/favicon.ico; +} + +# X-Accel-Redirect +location /internal/ { + internal; + gzip_vary on; + gzip_static on; + add_header X-DataLayer-Version $upstream_http_x_datalayer_version; + alias /data/; +} + +# Ajax proxy +location ~ ^/proxy/(.*) { + internal; + add_header X-Proxy-Cache $upstream_cache_status always; + proxy_cache_background_update on; + proxy_cache_use_stale updating; + proxy_cache ajax_proxy; + proxy_cache_valid 1m; # Default. Umap will override using X-Accel-Expires + set $target_url $1; + # URL is encoded, so we need a few hack to clean it back. + if ( $target_url ~ (.+)%3A%2F%2F(.+) ){ # fix :// between scheme and destination + set $target_url $1://$2; + } + if ( $target_url ~ (.+?)%3A(.*) ){ # fix : between destination and port + set $target_url $1:$2; + } + if ( $target_url ~ (.+?)%2F(.*) ){ # fix / after port, the rest will be decoded by proxy_pass + set $target_url $1/$2; + } + resolver 8.8.8.8; + add_header X-Proxy-Target $target_url; # For debugging + proxy_pass_request_headers off; + proxy_set_header Content-Type $http_content_type; + proxy_set_header Content-Encoding $http_content_encoding; + proxy_set_header Content-Length $http_content_length; + proxy_read_timeout 10s; + proxy_connect_timeout 5s; + proxy_ssl_server_name on; + proxy_pass $target_url; + proxy_intercept_errors on; + error_page 301 302 307 = @handle_proxy_redirect; +} +location @handle_proxy_redirect { + resolver 8.8.8.8; + set $saved_redirect_location '$upstream_http_location'; + proxy_pass $saved_redirect_location; +} diff --git a/nginx.conf.tmpl b/nginx.conf.tmpl new file mode 100644 index 0000000..ab5149f --- /dev/null +++ b/nginx.conf.tmpl @@ -0,0 +1,47 @@ +events { + worker_connections 1024; # Adjust this to your needs +} + + + +http { + proxy_cache_path /tmp/nginx_ajax_proxy_cache levels=1:2 keys_zone=ajax_proxy:10m inactive=60m; + proxy_cache_key "$uri$is_args$args"; + + map $http_upgrade $connection_upgrade { + default upgrade; + '' close; + } + + types { + application/javascript mjs; + } + + include mime.types; + default_type application/octet-stream; + sendfile on; + keepalive_timeout 65; + + # Server block + server { + listen 80; + server_name localhost; + + include "/etc/nginx/snippets/umap.conf"; + + # Proxy pass to ASGI server + location / { + proxy_pass http://umap:8000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + proxy_redirect off; + proxy_buffering off; + } + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log warn; + } +} diff --git a/umap.conf.tmpl b/umap.conf.tmpl new file mode 100644 index 0000000..cbb8185 --- /dev/null +++ b/umap.conf.tmpl @@ -0,0 +1,2 @@ +SECRET_KEY='{{ secret "secret_key" }}' +ALLOWED_HOSTS=[ '{{ env "DOMAIN" }}{{ env "EXTRA_DOMAINS" }}' ] \ No newline at end of file