diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..8d917ba063 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,73 @@ +# This file excludes paths from the Docker build context. +# +# By default, Docker's build context includes all files (and folders) in the +# current directory. Even if a file isn't copied into the container it is still sent to +# the Docker daemon. +# +# There are multiple reasons to exclude files from the build context: +# +# 1. Prevent nested folders from being copied into the container (ex: exclude +# /assets/node_modules when copying /assets) +# 2. Reduce the size of the build context and improve build time (ex. /build, /deps, /doc) +# 3. Avoid sending files containing sensitive information +# +# More information on using .dockerignore is available here: +# https://docs.docker.com/engine/reference/builder/#dockerignore-file + +.dockerignore + +# Ignore git, but keep git HEAD and refs to access current commit hash if needed: +# +# $ cat .git/HEAD | awk '{print ".git/"$2}' | xargs cat +# d0b8727759e1e0e7aa3d41707d12376e373d5ecc +.git +!.git/HEAD +!.git/refs + +# Common development/test artifacts +/cover/ +/doc/ +/test/ +/tmp/ +.elixir_ls +plausible-report.xml +.env +.idea +*.iml +*.log +*.code-workspace +.vscode + +# Mix artifacts +/_build/ +/deps/ +*.ez + +# Generated on crash by the VM +erl_crash.dump + +# If NPM crashes, it generates a log, let's ignore it too. +npm-debug.log + +# Static artifacts - These should be fetched and built inside the Docker image +/assets/node_modules/ +/tracker/node_modules/ +/priv/static/cache_manifest.json +/priv/static/css +/priv/static/js +/priv/version.json + +# Auto-generated tracker files +/priv/tracker/js/*.js + +# Dializer +/priv/plts/*.plt +/priv/plts/*.plt.hash + +# Geolocation databases +/priv/geodb/*.mmdb +/priv/geodb/*.mmdb.gz + +# Docker volumes +.clickhouse_db_vol* +plausible_db* diff --git a/.github/workflows/build-public-images.yml b/.github/workflows/build-public-images.yml index ab2a024d3e..0d12f6331b 100644 --- a/.github/workflows/build-public-images.yml +++ b/.github/workflows/build-public-images.yml @@ -48,7 +48,7 @@ jobs: build-args: | MIX_ENV=small BUILD_METADATA=${{ steps.meta.outputs.json }} - ERL_FLAGS=+JPperf true + ERL_FLAGS=+JMsingle true - name: Image digest run: echo ${{ steps.docker_build.outputs.digest }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 72b16e29bf..d202ff7cf1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,7 @@ All notable changes to this project will be documented in this file. - Allow custom event timeseries in stats API plausible/analytics#3505 - Fixes for sites with UTF characters in domain plausible/analytics#3560 - Fix crash when using special characters in filter plausible/analytics#3634 +- Allow running the container with arbitrary UID plausible/analytics#2986 ## v2.0.0 - 2023-07-12 diff --git a/Dockerfile b/Dockerfile index 555a380660..1411c7b44e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -64,18 +64,15 @@ ENV LANG=C.UTF-8 ARG MIX_ENV=small ENV MIX_ENV=$MIX_ENV -RUN apk upgrade --no-cache +RUN adduser -S -H -u 999 -G nogroup plausible -g 'Plausible Analytics' +RUN apk upgrade --no-cache RUN apk add --no-cache openssl ncurses libstdc++ libgcc ca-certificates -COPY ./rel/docker-entrypoint.sh /entrypoint.sh +COPY --from=buildcontainer --chmod=a+rX /app/_build/${MIX_ENV}/rel/plausible /app +COPY --chmod=755 ./rel/docker-entrypoint.sh /entrypoint.sh -RUN chmod a+x /entrypoint.sh && \ - adduser -h /app -u 1000 -s /bin/sh -D plausibleuser - -COPY --from=buildcontainer /app/_build/${MIX_ENV}/rel/plausible /app -RUN chown -R plausibleuser:plausibleuser /app -USER plausibleuser +USER 999 WORKDIR /app ENV LISTEN_IP=0.0.0.0 ENTRYPOINT ["/entrypoint.sh"] diff --git a/config/runtime.exs b/config/runtime.exs index 844e9a2694..f70928b240 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -229,7 +229,7 @@ ip_geolocation_db = get_var_from_path_or_env(config_dir, "IP_GEOLOCATION_DB", ge geonames_source_file = get_var_from_path_or_env(config_dir, "GEONAMES_SOURCE_FILE") maxmind_license_key = get_var_from_path_or_env(config_dir, "MAXMIND_LICENSE_KEY") maxmind_edition = get_var_from_path_or_env(config_dir, "MAXMIND_EDITION", "GeoLite2-City") -maxmind_cache_dir = get_var_from_path_or_env(config_dir, "PERSISTENT_CACHE_DIR") +persistent_cache_dir = get_var_from_path_or_env(config_dir, "PERSISTENT_CACHE_DIR") if System.get_env("DISABLE_AUTH") do Logger.warning("DISABLE_AUTH env var is no longer supported") @@ -637,7 +637,7 @@ geo_opts = [ license_key: maxmind_license_key, edition: maxmind_edition, - cache_dir: maxmind_cache_dir, + cache_dir: persistent_cache_dir, async: true ] @@ -689,9 +689,7 @@ else traces_exporter: :none end -config :tzdata, - :data_dir, - get_var_from_path_or_env(config_dir, "STORAGE_DIR", Application.app_dir(:tzdata, "priv")) +config :tzdata, :data_dir, Path.join(persistent_cache_dir || System.tmp_dir!(), "tzdata_data") # Temporarily disable tzdata auto-updating config :tzdata, :autoupdate, :disabled diff --git a/lib/plausible/geo.ex b/lib/plausible/geo.ex index bd245a3b5c..cb351f82f4 100644 --- a/lib/plausible/geo.ex +++ b/lib/plausible/geo.ex @@ -22,6 +22,9 @@ defmodule Plausible.Geo do * `:edition` - the name of the MaxMind database to be downloaded from MaxMind servers. Defaults to `GeoLite2-City`. + * `:cache_dir` - if set, the downloaded .mmdb files are cached there across + restarts. + * `:async` - when used, configures the database loading to run asynchronously. @@ -42,17 +45,19 @@ defmodule Plausible.Geo do cond do license_key = opts[:license_key] -> edition = opts[:edition] || "GeoLite2-City" + maxmind_opts = [license_key: license_key] - if is_binary(opts[:cache_dir]) do - :ok = - :locus.start_loader(@db, {:maxmind, edition}, - license_key: license_key, + loader_opts = + if is_binary(opts[:cache_dir]) do + [ database_cache_file: String.to_charlist(Path.join(opts[:cache_dir], edition <> ".mmdb.gz")) - ) - else - :ok = :locus.start_loader(@db, {:maxmind, edition}, license_key: license_key) - end + ] + else + [:no_cache] + end + + :ok = :locus.start_loader(@db, {:maxmind, edition}, maxmind_opts ++ loader_opts) path = opts[:path] -> :ok = :locus.start_loader(@db, path)