From ddf5e6254a4e7099ba965de0e79dbd74e51c143d Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 21 Jun 2019 05:46:21 +0300 Subject: [PATCH 01/56] Fix nginx webroot method config --- installation/pleroma.nginx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/installation/pleroma.nginx b/installation/pleroma.nginx index 7425da33f..7fc4aeea5 100644 --- a/installation/pleroma.nginx +++ b/installation/pleroma.nginx @@ -14,7 +14,6 @@ server { listen 80; listen [::]:80; - return 301 https://$server_name$request_uri; # Uncomment this if you need to use the 'webroot' method with certbot. Make sure # that the directory exists and that it is accessible by the webserver. If you followed @@ -23,8 +22,11 @@ server { # to get the certificate, and then uncomment it. # # location ~ /\.well-known/acme-challenge { - # root /var/lib/letsencrypt/.well-known/acme-challenge; + # alias /var/lib/letsencrypt/.well-known/acme-challenge; # } + location / { + return 301 https://$server_name$request_uri; + } } # Enable SSL session caching for improved performance From 7e35bdbd3c51771532f77b58829c6f0e2dcd08ca Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 21 Jun 2019 05:46:47 +0300 Subject: [PATCH 02/56] Copy the nginx config to the release directory --- mix.exs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mix.exs b/mix.exs index 9fdf6e83a..dc2df01a2 100644 --- a/mix.exs +++ b/mix.exs @@ -37,7 +37,7 @@ def project do pleroma: [ include_executables_for: [:unix], applications: [ex_syslogger: :load, syslog: :load], - steps: [:assemble, ©_files/1] + steps: [:assemble, ©_files/1, ©_nginx_config/1] ] ] ] @@ -48,6 +48,11 @@ def copy_files(%{path: target_path} = release) do release end + def copy_nginx_config(%{path: target_path} = release) do + File.cp!("./installation/pleroma.nginx", Path.join([target_path, "installation", "pleroma.nginx"])) + release + end + # Configuration for the OTP application. # # Type `mix help compile.app` for more information. From dd238887743cba24b8fa1971ae0a4f806a212f13 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 21 Jun 2019 05:48:13 +0300 Subject: [PATCH 03/56] OTP release install guide sceleton --- docs/installation/releases_en.md | 188 +++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 docs/installation/releases_en.md diff --git a/docs/installation/releases_en.md b/docs/installation/releases_en.md new file mode 100644 index 000000000..c0eafa75a --- /dev/null +++ b/docs/installation/releases_en.md @@ -0,0 +1,188 @@ +# Installing on Linux using OTP releases + +## Pre-requisites +* A machine running Linux with GNU (e.g. Debian, Ubuntu) or musl (e.g. Alpine) libc and `x86_64`, `aarch64` or `armv7l` CPU, you have root access to. If you are not sure if it's compatible see [Detecting flavour section](#detecting-flavour) below +* A (sub)domain pointed to the machine + +You will be running commands as root. If you aren't root already, please elevate your priviledges by executing `sudo su`/`su`. + +While in theory OTP releases are possbile to install on any compatible machine, for the sake of simplicity this guide focuses only on Debian/Ubuntu/Alpine. + +### Detecting flavour + +Paste the following into the shell: +```sh +arch="$(arch)";if [ "$arch" = "x86_64" ];then arch="amd64";elif [ "$arch" = "armv7l" ];then arch="arm";elif [ "$arch" = "aarch64" ];then arch="arm64";else echo "Unsupported arch: $arch">&2;exit 1;fi;if getconf GNU_LIBC_VERSION>/dev/null;then libc_postfix="";elif [ "$(ldd 2>&1|head -c 9)" = "musl libc" ];then libc_postfix="-musl";elif [ "$(find /lib/libc.musl*|wc -l)" ];then libc_postfix="-musl";else echo "Unsupported libc">&2;exit 1;fi;echo "$arch$libc_postfix" +``` + +If your platform is supported the output will contain the flavour string, you will need it later. If not, this just means that we don't build releases for your platform, you can still try the regular install. + +### Installing the required packages + +Other than things bundled in the OTP release Pleroma depends on: +* curl (to download the release build) +* unzip (needed to unpack release builds) +* ncurses (ERTS won't run without it) +* PostgreSQL (also utilizes extensions in postgresql-contrib) +* nginx (could be swapped with another webserver but this guide covers only it) +* certbot (for Let's Encrypt certificates, could be swapped with another ACME client, but this guide covers only it) + +Debian/Ubuntu: +```sh +apt install curl unzip ncurses postgresql posqtgresql-contrib nginx certbot +``` +Alpine: +```sh +apk add curl unzip ncurses postgresql posqtgresql-contrib nginx certbot +``` + +## Setup +### Configuring PostgreSQL +#### (Optional) Installing RUM indexes +RUM indexes are an alternative indexing scheme that is not included in PostgreSQL by default. You can read more about them on the [Configuration page](config.html#rum-indexing-for-full-text-search). They are completely optional and most of the time are not worth it, especially if you are running a single user instance (unless you absolutely need ordered search results). + +Debian/Ubuntu: +```sh +apt install postgresql-rum +``` +Alpine: +```sh +apk install gcc make +git clone https://github.com/postgrespro/rum /tmp/rum +cd /tmp/rum +make USE_PGXS=1 +make USE_PGXS=1 install +make USE_PGXS=1 installcheck +cd +rm -r /tmp/rum +``` +#### (Optional) Performance configuration +For optimal performance, you may use [PGTune](https://pgtune.leopard.in.ua), don't forget to restart postgresql after editing the configuration + +Debian/Ubuntu: +```sh +systemctl restart postgresql +``` +Alpine: +```sh +rc-service postgresql restart +``` +### Installing Pleroma +```sh +# Create the Pleroma user +adduser -S -s /bin/false -h /opt/pleroma -H pleroma + +# Set the flavour environment variable to the string you got in Detecting flavour section. +# For example if the flavour is `arm64-musl` the command will be +export FLAVOUR="arm64-musl" + +# Clone the release build into a temporary directory and unpack it +su pleroma -s $SHELL -lc " +echo '$FLAVOUR' +curl 'https://git.pleroma.social/api/v4/projects/2/jobs/artifacts/master/download?job=$FLAVOUR' -o /tmp/pleroma.zip +unzip /tmp/pleroma.zip -d /tmp/ +" + +# Move the release to the home directory and delete temporary files +su pleroma -s $SHELL -lc " +mv /tmp/release/* /opt/pleroma +rmdir /tmp/release +rm /tmp/pleroma.zip +" +# Create uploads directory and set proper permissions (skip if planning to use a remote uploader) +# Note: It does not have to be `/var/lib/pleroma/uploads`, the config generator will ask about the upload directory later + +mkdir -p /var/lib/pleroma/uploads +chown -R pleroma:pleroma /var/lib/pleroma + +# Create custom public files directory (custom emojis, frontend bundle overrides, robots.txt, etc.) +# Note: It does not have to be `/var/lib/pleroma/static`, the config generator will ask about the custom public files directory later +mkdir -p /var/lib/pleroma/static +chown -R pleroma:pleroma /var/lib/pleroma + +# Create a config directory +mkdir -p /etc/pleroma +chown -R pleroma:pleroma /etc/pleroma + +# Run the config generator +su pleroma -s $SHELL -lc "./bin/pleroma_ctl instance gen --output /etc/pleroma/config.exs --output-psql /tmp/setup_db.psql" + +# Create the postgres database +psql -U postgres -d postgres -f /tmp/setup_db.psql + +# Create the database schema +./bin/pleroma_ctl create +./bin/pleroma_ctl migrate + +# Start the instance to verify that everything is working as expected +./bin/pleroma daemon + +# Wait for about 20 seconds and query the instance endpoint, if it shows your uri, name and email correctly, you are configured correctly +sleep 20 && curl http://localhost:4000/api/v1/instance + +# Stop the instance +./bin/pleroma stop +``` + +### Setting up nginx and getting Let's Encrypt SSL certificaties + +```sh +# Get a Let's Encrypt certificate +certbot certonly --standalone --preferred-challenges http -d yourinstance.tld + +# Copy the Pleroma nginx configuration to the nginx folder +# The location of nginx configs is dependent on the distro + +# For Debian/Ubuntu: +cp /opt/pleroma/installation/pleroma.nginx /etc/nginx/sites-available/pleroma.nginx +ln -s /etc/nginx/sites-available/pleroma.nginx /etc/nginx/sites-enabled/pleroma.nginx +# For Alpine +cp /opt/pleroma/installation/pleroma.nginx /etc/nginx/conf.d/pleroma.conf +# If your distro does not have either of those you can append +# `include /etc/nginx/pleroma.conf` to the end of the http section in /etc/nginx/nginx.conf and +cp /opt/pleroma/installation/pleroma.nginx /etc/nginx/pleroma.conf + +# Edit the nginx config replacing example.tld with your (sub)domain +$EDITOR path-to-the-config + +# Verify that the config is valid +nginx -t + +# Start nginx +# For Debian/Ubuntu: +systemctl start nginx +# For Alpine +rc-service nginx start +``` + +At this point if you open your (sub)domain in a browser you should see a 502 error, that's because pleroma is not started yet. + +### Setting up a system service +Debian/Ubuntu: +```sh +# Copy the service into a proper directory +cp /opt/pleroma/installation/pleroma.service /etc/systemd/system/pleroma.service + +# Start pleroma and enable it on boot +systemctl start pleroma +systemctl enable pleroma +``` +Alpine: +```sh +# Copy the service into a proper directory +cp /opt/pleroma/installation/init.d/pleroma /etc/init.d/pleroma + +# Start pleroma and enable it on boot +rc-service pleroma start +rc-update add pleroma +``` + +If everything worked, you should see Pleroma-FE when visiting your domain. If that didn't happen, try reviewing the installation steps, starting Pleroma in the foreground and seeing if there are any errrors. + +Still doesn't work? Feel free to contact us on [#pleroma on freenode](https://webchat.freenode.net/?channels=%23pleroma) or via matrix at , you can also [file an issue on our Gitlab](https://git.pleroma.social/pleroma/pleroma/issues/new) + +## Post installation + +### Setting up auto-renew Let's Encrypt certificate +### Running Mix tasks +### Updating From 267f6bedd885a00a94f8d383a6793d34b018762a Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 21 Jun 2019 05:57:46 +0300 Subject: [PATCH 04/56] Formatting --- mix.exs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mix.exs b/mix.exs index dc2df01a2..bd8a10c66 100644 --- a/mix.exs +++ b/mix.exs @@ -49,7 +49,11 @@ def copy_files(%{path: target_path} = release) do end def copy_nginx_config(%{path: target_path} = release) do - File.cp!("./installation/pleroma.nginx", Path.join([target_path, "installation", "pleroma.nginx"])) + File.cp!( + "./installation/pleroma.nginx", + Path.join([target_path, "installation", "pleroma.nginx"]) + ) + release end From d3d98beaad9127517c7ad8d027f052a23807772b Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 21 Jun 2019 06:04:39 +0300 Subject: [PATCH 05/56] Correct package names for Debian --- docs/installation/releases_en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation/releases_en.md b/docs/installation/releases_en.md index c0eafa75a..4645f7aff 100644 --- a/docs/installation/releases_en.md +++ b/docs/installation/releases_en.md @@ -29,7 +29,7 @@ Other than things bundled in the OTP release Pleroma depends on: Debian/Ubuntu: ```sh -apt install curl unzip ncurses postgresql posqtgresql-contrib nginx certbot +apt install curl unzip libncurses5 postgresql postgresql-contrib nginx certbot ``` Alpine: ```sh From f9515a36112c8f6a8a40dbda234aaa6bb5de3827 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 21 Jun 2019 06:14:02 +0300 Subject: [PATCH 06/56] Add a note about RUM indexes package on Debian/Ubuntu --- docs/installation/releases_en.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/installation/releases_en.md b/docs/installation/releases_en.md index 4645f7aff..39749b40b 100644 --- a/docs/installation/releases_en.md +++ b/docs/installation/releases_en.md @@ -41,9 +41,9 @@ apk add curl unzip ncurses postgresql posqtgresql-contrib nginx certbot #### (Optional) Installing RUM indexes RUM indexes are an alternative indexing scheme that is not included in PostgreSQL by default. You can read more about them on the [Configuration page](config.html#rum-indexing-for-full-text-search). They are completely optional and most of the time are not worth it, especially if you are running a single user instance (unless you absolutely need ordered search results). -Debian/Ubuntu: +Debian/Ubuntu (available only on Buster/19.04): ```sh -apt install postgresql-rum +apt install postgresql-11-rum ``` Alpine: ```sh From 4669a56aa37bf02aa6564ef53758879e3a58a6b2 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 21 Jun 2019 06:22:34 +0300 Subject: [PATCH 07/56] Add notes on RUM indexes --- docs/installation/releases_en.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/installation/releases_en.md b/docs/installation/releases_en.md index 39749b40b..918ae83e1 100644 --- a/docs/installation/releases_en.md +++ b/docs/installation/releases_en.md @@ -110,10 +110,17 @@ su pleroma -s $SHELL -lc "./bin/pleroma_ctl instance gen --output /etc/pleroma/c # Create the postgres database psql -U postgres -d postgres -f /tmp/setup_db.psql +# If you have installed RUM indexes add +# `config :pleroma, :database, rum_enabled: true` +# to the end of /etc/pleroma/config.exs before proceeding + # Create the database schema ./bin/pleroma_ctl create ./bin/pleroma_ctl migrate +# If you have installed RUM indexes also run +./bin/pleroma_ctl migrate --migrations-path priv/repo/optional_migrations/rum_indexing/ + # Start the instance to verify that everything is working as expected ./bin/pleroma daemon From 16e9304cecc420b9dbdb17f0db13a9a0010ad6cf Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 21 Jun 2019 06:32:34 +0300 Subject: [PATCH 08/56] Change to long adduser options because the short ones only work on busybox --- docs/installation/releases_en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation/releases_en.md b/docs/installation/releases_en.md index 918ae83e1..df1b02231 100644 --- a/docs/installation/releases_en.md +++ b/docs/installation/releases_en.md @@ -70,7 +70,7 @@ rc-service postgresql restart ### Installing Pleroma ```sh # Create the Pleroma user -adduser -S -s /bin/false -h /opt/pleroma -H pleroma +adduser --system --shell /bin/false --home /opt/pleroma pleroma # Set the flavour environment variable to the string you got in Detecting flavour section. # For example if the flavour is `arm64-musl` the command will be From e824025c52bec84a44bc4307407071daa99e805f Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 21 Jun 2019 06:37:38 +0300 Subject: [PATCH 09/56] Remove a useless echo --- docs/installation/releases_en.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/installation/releases_en.md b/docs/installation/releases_en.md index df1b02231..e1a2e97e6 100644 --- a/docs/installation/releases_en.md +++ b/docs/installation/releases_en.md @@ -78,7 +78,6 @@ export FLAVOUR="arm64-musl" # Clone the release build into a temporary directory and unpack it su pleroma -s $SHELL -lc " -echo '$FLAVOUR' curl 'https://git.pleroma.social/api/v4/projects/2/jobs/artifacts/master/download?job=$FLAVOUR' -o /tmp/pleroma.zip unzip /tmp/pleroma.zip -d /tmp/ " From 4bec121798218f8abf8d2915fa7c26ccb23a4f4a Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 21 Jun 2019 06:39:03 +0300 Subject: [PATCH 10/56] Do not set ownership group in chown commands --- docs/installation/releases_en.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/installation/releases_en.md b/docs/installation/releases_en.md index e1a2e97e6..9fbb4b26e 100644 --- a/docs/installation/releases_en.md +++ b/docs/installation/releases_en.md @@ -92,16 +92,16 @@ rm /tmp/pleroma.zip # Note: It does not have to be `/var/lib/pleroma/uploads`, the config generator will ask about the upload directory later mkdir -p /var/lib/pleroma/uploads -chown -R pleroma:pleroma /var/lib/pleroma +chown -R pleroma /var/lib/pleroma # Create custom public files directory (custom emojis, frontend bundle overrides, robots.txt, etc.) # Note: It does not have to be `/var/lib/pleroma/static`, the config generator will ask about the custom public files directory later mkdir -p /var/lib/pleroma/static -chown -R pleroma:pleroma /var/lib/pleroma +chown -R pleroma /var/lib/pleroma # Create a config directory mkdir -p /etc/pleroma -chown -R pleroma:pleroma /etc/pleroma +chown -R pleroma /etc/pleroma # Run the config generator su pleroma -s $SHELL -lc "./bin/pleroma_ctl instance gen --output /etc/pleroma/config.exs --output-psql /tmp/setup_db.psql" From 89fead9250a5bd9b6712a285e8a827f1aec69615 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 21 Jun 2019 06:42:04 +0300 Subject: [PATCH 11/56] Default DB configuration to false and set the default database name to `pleroma` instead of `pleroma_dev` --- lib/mix/tasks/pleroma/instance.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mix/tasks/pleroma/instance.ex b/lib/mix/tasks/pleroma/instance.ex index 2c4e414cf..9e26c066b 100644 --- a/lib/mix/tasks/pleroma/instance.ex +++ b/lib/mix/tasks/pleroma/instance.ex @@ -112,12 +112,12 @@ def run(["gen" | rest]) do options, :db_configurable, "Do you want to store the configuration in the database (allows controlling it from admin-fe)? (y/n)", - "y" + "n" ) === "y" dbhost = get_option(options, :dbhost, "What is the hostname of your database?", "localhost") - dbname = get_option(options, :dbname, "What is the name of your database?", "pleroma_dev") + dbname = get_option(options, :dbname, "What is the name of your database?", "pleroma") dbuser = get_option( From 8b170b96c7c9ae727bdfe2d6856375b183f56180 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 21 Jun 2019 16:59:48 +0000 Subject: [PATCH 12/56] Apply suggestion to docs/installation/releases_en.md --- docs/installation/releases_en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation/releases_en.md b/docs/installation/releases_en.md index 9fbb4b26e..352dc3dfc 100644 --- a/docs/installation/releases_en.md +++ b/docs/installation/releases_en.md @@ -118,7 +118,7 @@ psql -U postgres -d postgres -f /tmp/setup_db.psql ./bin/pleroma_ctl migrate # If you have installed RUM indexes also run -./bin/pleroma_ctl migrate --migrations-path priv/repo/optional_migrations/rum_indexing/ +# ./bin/pleroma_ctl migrate --migrations-path priv/repo/optional_migrations/rum_indexing/ # Start the instance to verify that everything is working as expected ./bin/pleroma daemon From de77d7621a781cf409663a8d5e931227e3b2cf82 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 21 Jun 2019 16:59:56 +0000 Subject: [PATCH 13/56] Apply suggestion to docs/installation/releases_en.md --- docs/installation/releases_en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation/releases_en.md b/docs/installation/releases_en.md index 352dc3dfc..48fffa6e2 100644 --- a/docs/installation/releases_en.md +++ b/docs/installation/releases_en.md @@ -24,7 +24,7 @@ Other than things bundled in the OTP release Pleroma depends on: * unzip (needed to unpack release builds) * ncurses (ERTS won't run without it) * PostgreSQL (also utilizes extensions in postgresql-contrib) -* nginx (could be swapped with another webserver but this guide covers only it) +* nginx (could be swapped with another reverse proxy but this guide covers only it) * certbot (for Let's Encrypt certificates, could be swapped with another ACME client, but this guide covers only it) Debian/Ubuntu: From 743bd648832eb1fd6033c3484059c08f88af40f3 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 21 Jun 2019 17:00:12 +0000 Subject: [PATCH 14/56] Apply suggestion to docs/installation/releases_en.md --- docs/installation/releases_en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation/releases_en.md b/docs/installation/releases_en.md index 48fffa6e2..c682a8d61 100644 --- a/docs/installation/releases_en.md +++ b/docs/installation/releases_en.md @@ -15,7 +15,7 @@ Paste the following into the shell: arch="$(arch)";if [ "$arch" = "x86_64" ];then arch="amd64";elif [ "$arch" = "armv7l" ];then arch="arm";elif [ "$arch" = "aarch64" ];then arch="arm64";else echo "Unsupported arch: $arch">&2;exit 1;fi;if getconf GNU_LIBC_VERSION>/dev/null;then libc_postfix="";elif [ "$(ldd 2>&1|head -c 9)" = "musl libc" ];then libc_postfix="-musl";elif [ "$(find /lib/libc.musl*|wc -l)" ];then libc_postfix="-musl";else echo "Unsupported libc">&2;exit 1;fi;echo "$arch$libc_postfix" ``` -If your platform is supported the output will contain the flavour string, you will need it later. If not, this just means that we don't build releases for your platform, you can still try the regular install. +If your platform is supported the output will contain the flavour string, you will need it later. If not, this just means that we don't build releases for your platform, you can still try installing from source. ### Installing the required packages From ee4e7c6570dd959fe5c65fc5e18967af5a870735 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 22 Jun 2019 02:07:05 +0300 Subject: [PATCH 15/56] Remove the getting started steps from pleroma.instance gen task They are not compatible with every platform, different for OTP releases and may become outdated. We are better off just telling people to refer to the installation guides for their particular platform --- lib/mix/tasks/pleroma/instance.ex | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/lib/mix/tasks/pleroma/instance.ex b/lib/mix/tasks/pleroma/instance.ex index 9b14871c9..7022d173d 100644 --- a/lib/mix/tasks/pleroma/instance.ex +++ b/lib/mix/tasks/pleroma/instance.ex @@ -186,28 +186,16 @@ def run(["gen" | rest]) do dbpass: dbpass ) - shell_info( - "Writing config to #{config_path}. You should rename it to config/prod.secret.exs or config/dev.secret.exs." - ) + shell_info("Writing config to #{config_path}.") File.write(config_path, result_config) - shell_info("Writing #{psql_path}.") + shell_info("Writing the postgres script to #{psql_path}.") File.write(psql_path, result_psql) write_robots_txt(indexable, template_dir) shell_info( - "\n" <> - """ - To get started: - 1. Verify the contents of the generated files. - 2. Run `sudo -u postgres psql -f #{escape_sh_path(psql_path)}`. - """ <> - if config_path in ["config/dev.secret.exs", "config/prod.secret.exs"] do - "" - else - "3. Run `mv #{escape_sh_path(config_path)} 'config/prod.secret.exs'`." - end + "\n All files successfully written! Refer to the installation instructions for your platform for next steps" ) else shell_error( From d1d648b0ecfb0924d7921796d7edef9512e030b0 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 22 Jun 2019 02:09:45 +0300 Subject: [PATCH 16/56] Correct the psql command --- docs/installation/releases_en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation/releases_en.md b/docs/installation/releases_en.md index c682a8d61..10d8879af 100644 --- a/docs/installation/releases_en.md +++ b/docs/installation/releases_en.md @@ -107,7 +107,7 @@ chown -R pleroma /etc/pleroma su pleroma -s $SHELL -lc "./bin/pleroma_ctl instance gen --output /etc/pleroma/config.exs --output-psql /tmp/setup_db.psql" # Create the postgres database -psql -U postgres -d postgres -f /tmp/setup_db.psql +su postgres -s $SHELL -lc "psql -f /tmp/setup_db.psql" # If you have installed RUM indexes add # `config :pleroma, :database, rum_enabled: true` From 23608149bc72d740e6259e460e43ff276583516d Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 22 Jun 2019 02:20:55 +0300 Subject: [PATCH 17/56] Execute migration commands as the pleroma user and add a note about the need to uncomment the RUM command --- docs/installation/releases_en.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/installation/releases_en.md b/docs/installation/releases_en.md index 10d8879af..31e3ac30d 100644 --- a/docs/installation/releases_en.md +++ b/docs/installation/releases_en.md @@ -114,20 +114,20 @@ su postgres -s $SHELL -lc "psql -f /tmp/setup_db.psql" # to the end of /etc/pleroma/config.exs before proceeding # Create the database schema -./bin/pleroma_ctl create -./bin/pleroma_ctl migrate +su pleroma -s $SHELL -lc "./bin/pleroma_ctl create" +su pleroma -s $SHELL -lc "./bin/pleroma_ctl migrate" -# If you have installed RUM indexes also run -# ./bin/pleroma_ctl migrate --migrations-path priv/repo/optional_migrations/rum_indexing/ +# If you have installed RUM indexes uncommend and run +# su pleroma -s $SHELL -lc "./bin/pleroma_ctl migrate --migrations-path priv/repo/optional_migrations/rum_indexing/" # Start the instance to verify that everything is working as expected -./bin/pleroma daemon +su pleroma -s $SHELL -lc "./bin/pleroma daemon" # Wait for about 20 seconds and query the instance endpoint, if it shows your uri, name and email correctly, you are configured correctly sleep 20 && curl http://localhost:4000/api/v1/instance # Stop the instance -./bin/pleroma stop +su pleroma -s $SHELL -lc "./bin/pleroma stop" ``` ### Setting up nginx and getting Let's Encrypt SSL certificaties From 120f84c83dcebb9b46cb158b9e1f4af9cf0aee28 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 22 Jun 2019 04:35:17 +0300 Subject: [PATCH 18/56] Executing create is unnecessary after the postgres script is executed --- docs/installation/releases_en.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/installation/releases_en.md b/docs/installation/releases_en.md index 31e3ac30d..5ccd50c47 100644 --- a/docs/installation/releases_en.md +++ b/docs/installation/releases_en.md @@ -114,7 +114,6 @@ su postgres -s $SHELL -lc "psql -f /tmp/setup_db.psql" # to the end of /etc/pleroma/config.exs before proceeding # Create the database schema -su pleroma -s $SHELL -lc "./bin/pleroma_ctl create" su pleroma -s $SHELL -lc "./bin/pleroma_ctl migrate" # If you have installed RUM indexes uncommend and run From 38a803a1f86b459d193aa234d00b1af3895edab1 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 22 Jun 2019 05:00:41 +0300 Subject: [PATCH 19/56] Add a systemd service for OTP releases --- rel/files/installation/pleroma.service | 36 ++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 rel/files/installation/pleroma.service diff --git a/rel/files/installation/pleroma.service b/rel/files/installation/pleroma.service new file mode 100644 index 000000000..e47cf58dc --- /dev/null +++ b/rel/files/installation/pleroma.service @@ -0,0 +1,36 @@ +[Unit] +Description=Pleroma social network +After=network.target postgresql.service nginx.service + +[Service] +KillMode=process +Restart=on-failure + +; Name of the user that runs the Pleroma service. +User=pleroma + +; Make sure that all paths fit your installation. +; Path to the home directory of the user running the Pleroma service. +Environment="HOME=/opt/pleroma" +; Path to the folder containing the Pleroma installation. +WorkingDirectory=/opt/pleroma +; Path to the Pleroma binary. +ExecStart=/opt/pleroma/bin/pleroma start +ExecStop=/opt/pleroma/bin/pleroma stop + +; Some security directives. +; Use private /tmp and /var/tmp folders inside a new file system namespace, which are discarded after the process stops. +PrivateTmp=true +; The /home, /root, and /run/user folders can not be accessed by this service anymore. If your Pleroma user has its home folder in one of the restricted places, or use one of these folders as its working directory, you have to set this to false. +ProtectHome=true +; Mount /usr, /boot, and /etc as read-only for processes invoked by this service. +ProtectSystem=full +; Sets up a new /dev mount for the process and only adds API pseudo devices like /dev/null, /dev/zero or /dev/random but not physical devices. Disabled by default because it may not work on devices like the Raspberry Pi. +PrivateDevices=false +; Ensures that the service process and all its children can never gain new privileges through execve(). +NoNewPrivileges=true +; Drops the sysadmin capability from the daemon. +CapabilityBoundingSet=~CAP_SYS_ADMIN + +[Install] +WantedBy=multi-user.target From 1d2332ce79c374f4958b5d554ea96d382e9806fb Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 22 Jun 2019 05:20:36 +0300 Subject: [PATCH 20/56] Use uname -m instead of arch for more portability --- docs/installation/releases_en.md | 2 +- rel/files/bin/pleroma_ctl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/installation/releases_en.md b/docs/installation/releases_en.md index 5ccd50c47..7dde26771 100644 --- a/docs/installation/releases_en.md +++ b/docs/installation/releases_en.md @@ -12,7 +12,7 @@ While in theory OTP releases are possbile to install on any compatible machine, Paste the following into the shell: ```sh -arch="$(arch)";if [ "$arch" = "x86_64" ];then arch="amd64";elif [ "$arch" = "armv7l" ];then arch="arm";elif [ "$arch" = "aarch64" ];then arch="arm64";else echo "Unsupported arch: $arch">&2;exit 1;fi;if getconf GNU_LIBC_VERSION>/dev/null;then libc_postfix="";elif [ "$(ldd 2>&1|head -c 9)" = "musl libc" ];then libc_postfix="-musl";elif [ "$(find /lib/libc.musl*|wc -l)" ];then libc_postfix="-musl";else echo "Unsupported libc">&2;exit 1;fi;echo "$arch$libc_postfix" +arch="$(uname -m)";if [ "$arch" = "x86_64" ];then arch="amd64";elif [ "$arch" = "armv7l" ];then arch="arm";elif [ "$arch" = "aarch64" ];then arch="arm64";else echo "Unsupported arch: $arch">&2;exit 1;fi;if getconf GNU_LIBC_VERSION>/dev/null;then libc_postfix="";elif [ "$(ldd 2>&1|head -c 9)" = "musl libc" ];then libc_postfix="-musl";elif [ "$(find /lib/libc.musl*|wc -l)" ];then libc_postfix="-musl";else echo "Unsupported libc">&2;exit 1;fi;echo "$arch$libc_postfix" ``` If your platform is supported the output will contain the flavour string, you will need it later. If not, this just means that we don't build releases for your platform, you can still try installing from source. diff --git a/rel/files/bin/pleroma_ctl b/rel/files/bin/pleroma_ctl index b0e1874a9..9c67b209b 100755 --- a/rel/files/bin/pleroma_ctl +++ b/rel/files/bin/pleroma_ctl @@ -2,7 +2,7 @@ # XXX: This should be removed when elixir's releases get custom command support detect_flavour() { - arch="$(arch)" + arch="$(uname -m)" if [ "$arch" = "x86_64" ]; then arch="amd64" elif [ "$arch" = "armv7l" ]; then From dd05dc65d31d5d54662e7c5d81ed393ae25d14dd Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 22 Jun 2019 08:30:32 +0300 Subject: [PATCH 21/56] Do not exit on fail in the one-liner because it closes ssh connection and fix dependencies for alpine --- docs/installation/releases_en.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/installation/releases_en.md b/docs/installation/releases_en.md index 7dde26771..31b639d32 100644 --- a/docs/installation/releases_en.md +++ b/docs/installation/releases_en.md @@ -12,7 +12,7 @@ While in theory OTP releases are possbile to install on any compatible machine, Paste the following into the shell: ```sh -arch="$(uname -m)";if [ "$arch" = "x86_64" ];then arch="amd64";elif [ "$arch" = "armv7l" ];then arch="arm";elif [ "$arch" = "aarch64" ];then arch="arm64";else echo "Unsupported arch: $arch">&2;exit 1;fi;if getconf GNU_LIBC_VERSION>/dev/null;then libc_postfix="";elif [ "$(ldd 2>&1|head -c 9)" = "musl libc" ];then libc_postfix="-musl";elif [ "$(find /lib/libc.musl*|wc -l)" ];then libc_postfix="-musl";else echo "Unsupported libc">&2;exit 1;fi;echo "$arch$libc_postfix" +arch="$(uname -m)";if [ "$arch" = "x86_64" ];then arch="amd64";elif [ "$arch" = "armv7l" ];then arch="arm";elif [ "$arch" = "aarch64" ];then arch="arm64";else echo "Unsupported arch: $arch">&2;fi;if getconf GNU_LIBC_VERSION>/dev/null;then libc_postfix="";elif [ "$(ldd 2>&1|head -c 9)" = "musl libc" ];then libc_postfix="-musl";elif [ "$(find /lib/libc.musl*|wc -l)" ];then libc_postfix="-musl";else echo "Unsupported libc">&2;fi;echo "$arch$libc_postfix" ``` If your platform is supported the output will contain the flavour string, you will need it later. If not, this just means that we don't build releases for your platform, you can still try installing from source. @@ -33,7 +33,9 @@ apt install curl unzip libncurses5 postgresql postgresql-contrib nginx certbot ``` Alpine: ```sh -apk add curl unzip ncurses postgresql posqtgresql-contrib nginx certbot +echo "http://nl.alpinelinux.org/alpine/latest-stable/community" >> /etc/apk/repositories +apk update +apk add curl unzip ncurses postgresql postgresql-contrib nginx certbot ``` ## Setup From 50e3cf9d5e4c957f4a979bbeed29787209bdfa13 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 22 Jun 2019 08:31:02 +0300 Subject: [PATCH 22/56] Correct a typo in the apk command --- docs/installation/releases_en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation/releases_en.md b/docs/installation/releases_en.md index 31b639d32..9c108c4ff 100644 --- a/docs/installation/releases_en.md +++ b/docs/installation/releases_en.md @@ -49,7 +49,7 @@ apt install postgresql-11-rum ``` Alpine: ```sh -apk install gcc make +apk add gcc make git clone https://github.com/postgrespro/rum /tmp/rum cd /tmp/rum make USE_PGXS=1 From 177faf15c24453fc67bb5bedc6189055e686e2a3 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 22 Jun 2019 08:36:36 +0300 Subject: [PATCH 23/56] Correct dependencies for RUM on alpine and remove installcheck --- docs/installation/releases_en.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/installation/releases_en.md b/docs/installation/releases_en.md index 9c108c4ff..ce46d0d29 100644 --- a/docs/installation/releases_en.md +++ b/docs/installation/releases_en.md @@ -49,12 +49,11 @@ apt install postgresql-11-rum ``` Alpine: ```sh -apk add gcc make +apk add gcc make git postgresql-dev musl-dev git clone https://github.com/postgrespro/rum /tmp/rum cd /tmp/rum make USE_PGXS=1 make USE_PGXS=1 install -make USE_PGXS=1 installcheck cd rm -r /tmp/rum ``` From bb40c33dd65aaeafaf3b74f4557deb75b0da8e93 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 22 Jun 2019 13:24:33 +0300 Subject: [PATCH 24/56] Add an OpenRC service for OTP releases --- rel/files/installation/init.d/pleroma | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100755 rel/files/installation/init.d/pleroma diff --git a/rel/files/installation/init.d/pleroma b/rel/files/installation/init.d/pleroma new file mode 100755 index 000000000..de007c5e3 --- /dev/null +++ b/rel/files/installation/init.d/pleroma @@ -0,0 +1,18 @@ +#!/sbin/openrc-run + +# Requires OpenRC >= 0.35 +directory=/opt/pleroma + +command=/opt/pleroma/bin/pleroma +command_args="start" +command_user=pleroma +command_background=1 + +# Ask process to terminate within 30 seconds, otherwise kill it +retry="SIGTERM/30/SIGKILL/5" + +pidfile="/var/run/pleroma.pid" + +depend() { + need nginx postgresql +} From e00e4c0e7a43aaa5c4be43e105712101167f4cbd Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 22 Jun 2019 13:40:37 +0300 Subject: [PATCH 25/56] Add a warning about OTP releases on Alpine 3.10 --- docs/installation/releases_en.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/installation/releases_en.md b/docs/installation/releases_en.md index ce46d0d29..e8bdf007d 100644 --- a/docs/installation/releases_en.md +++ b/docs/installation/releases_en.md @@ -32,8 +32,10 @@ Debian/Ubuntu: apt install curl unzip libncurses5 postgresql postgresql-contrib nginx certbot ``` Alpine: + +**Warning:** There has been some changes to musl on Alpine 3.10 which need an Elixir rebuild. Since the build machines are running Alpine 3.9 running the builds on 3.10 will likely fail with "dlsym: Resource temporarily unavailable". If you have not updated yet, replace `latest-stable` with `v3.9` in `/etc/apk/repositories`. If you have, try downgrading `musl` to `1.1.20-r3` ```sh -echo "http://nl.alpinelinux.org/alpine/latest-stable/community" >> /etc/apk/repositories +echo "http://nl.alpinelinux.org/alpine/v3.9/community" >> /etc/apk/repositories apk update apk add curl unzip ncurses postgresql postgresql-contrib nginx certbot ``` @@ -149,7 +151,7 @@ cp /opt/pleroma/installation/pleroma.nginx /etc/nginx/conf.d/pleroma.conf cp /opt/pleroma/installation/pleroma.nginx /etc/nginx/pleroma.conf # Edit the nginx config replacing example.tld with your (sub)domain -$EDITOR path-to-the-config +$EDITOR path-to-nginx-config # Verify that the config is valid nginx -t From c013d3f3c89a638e20e786a528be598cfa225af7 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 22 Jun 2019 20:26:59 +0300 Subject: [PATCH 26/56] Fix the webroot method in the nginx config --- installation/pleroma.nginx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/installation/pleroma.nginx b/installation/pleroma.nginx index 7fc4aeea5..de380a6ca 100644 --- a/installation/pleroma.nginx +++ b/installation/pleroma.nginx @@ -22,7 +22,7 @@ server { # to get the certificate, and then uncomment it. # # location ~ /\.well-known/acme-challenge { - # alias /var/lib/letsencrypt/.well-known/acme-challenge; + # root /var/lib/letsencrypt/; # } location / { return 301 https://$server_name$request_uri; From 7a4c4518b8cdff5684f3287f373e3e6acf72293c Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 22 Jun 2019 21:18:34 +0300 Subject: [PATCH 27/56] Remove a note about needing to add RUM to config manually, as it is now in the config generator --- docs/installation/releases_en.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/installation/releases_en.md b/docs/installation/releases_en.md index e8bdf007d..7f53aedb8 100644 --- a/docs/installation/releases_en.md +++ b/docs/installation/releases_en.md @@ -112,10 +112,6 @@ su pleroma -s $SHELL -lc "./bin/pleroma_ctl instance gen --output /etc/pleroma/c # Create the postgres database su postgres -s $SHELL -lc "psql -f /tmp/setup_db.psql" -# If you have installed RUM indexes add -# `config :pleroma, :database, rum_enabled: true` -# to the end of /etc/pleroma/config.exs before proceeding - # Create the database schema su pleroma -s $SHELL -lc "./bin/pleroma_ctl migrate" From 9d487ba57949a4102aa2eb67b26842f1c0ef418c Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sun, 23 Jun 2019 02:42:47 +0300 Subject: [PATCH 28/56] Add docs about SSL certificate auto-renew --- docs/installation/releases_en.md | 52 ++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/docs/installation/releases_en.md b/docs/installation/releases_en.md index 7f53aedb8..30fbf5177 100644 --- a/docs/installation/releases_en.md +++ b/docs/installation/releases_en.md @@ -140,7 +140,7 @@ certbot certonly --standalone --preferred-challenges http -d yourinstance.tld # For Debian/Ubuntu: cp /opt/pleroma/installation/pleroma.nginx /etc/nginx/sites-available/pleroma.nginx ln -s /etc/nginx/sites-available/pleroma.nginx /etc/nginx/sites-enabled/pleroma.nginx -# For Alpine +# For Alpine: cp /opt/pleroma/installation/pleroma.nginx /etc/nginx/conf.d/pleroma.conf # If your distro does not have either of those you can append # `include /etc/nginx/pleroma.conf` to the end of the http section in /etc/nginx/nginx.conf and @@ -155,7 +155,7 @@ nginx -t # Start nginx # For Debian/Ubuntu: systemctl start nginx -# For Alpine +# For Alpine: rc-service nginx start ``` @@ -188,5 +188,53 @@ Still doesn't work? Feel free to contact us on [#pleroma on freenode](https://we ## Post installation ### Setting up auto-renew Let's Encrypt certificate +```sh +# Create the directory for webroot challenges +mkdir -p /var/lib/letsencrypt + +# Uncomment the webroot method +$EDITOR path-to-nginx-config + +# Verify that the config is valid +nginx -t +``` +Debian/Ubuntu: +```sh +# Restart nginx +systemctl restart nginx + +# Ensure the webroot menthod and post hook is working +certbot renew --cert-name yourinstance.tld --webroot -w /var/lib/letsencrypt/ --dry-run --post-hook 'systemctl nginx reload' + +# Add it to the daily cron +echo '#!/bin/sh +certbot renew --cert-name yourinstance.tld --webroot -w /var/lib/letsencrypt/ --dry-run --post-hook "systemctl reload nginx" +' > /etc/cron.daily/renew-pleroma-cert +chmod +x /etc/cron.daily/renew-pleroma-cert + +# If everything worked the output should contain /etc/cron.daily/renew-pleroma-cert +run-parts --test /etc/cron.daily +``` +Alpine: +```sh +# Restart nginx +rc-service nginx restart + +# Start the cron daemon and make it start on boot +rc-service crond start +rc-update add crond + +# Ensure the webroot menthod and post hook is working +certbot renew --cert-name yourinstance.tld --webroot -w /var/lib/letsencrypt/ --dry-run --post-hook 'rc-service nginx reload' + +# Add it to the daily cron +echo '#!/bin/sh +certbot renew --cert-name yourinstance.tld --webroot -w /var/lib/letsencrypt/ --dry-run --post-hook "rc-service nginx reload" +' > /etc/periodic/daily/renew-pleroma-cert +chmod +x /etc/periodic/daily/renew-pleroma-cert + +# If everything worked this should output /etc/periodic/daily/renew-pleroma-cert +run-parts --test /etc/periodic/daily +``` ### Running Mix tasks ### Updating From 18eabca9789cdb96c77279aa4cff5b34e558c803 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sun, 23 Jun 2019 02:55:43 +0300 Subject: [PATCH 29/56] Add a section about updating --- docs/installation/releases_en.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/installation/releases_en.md b/docs/installation/releases_en.md index 30fbf5177..6c05f4cd9 100644 --- a/docs/installation/releases_en.md +++ b/docs/installation/releases_en.md @@ -238,3 +238,12 @@ run-parts --test /etc/periodic/daily ``` ### Running Mix tasks ### Updating +Generally, doing the following is enough: +```sh +# Download the new release +su pleroma -s $SHELL -lc "./bin/pleroma_ctl update" + +# Migrate the database, you are advised to stop the instance before doing that +su pleroma -s $SHELL -lc "./bin/pleroma_ctl migrate" +``` +But you should **always check the release notes/changelog** in case there are config deprecations, special update steps, etc. From 299cefa2bdbbde171501c5fa516e37b5e9733953 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sun, 23 Jun 2019 03:05:02 +0300 Subject: [PATCH 30/56] Add a section on executing mix tasks --- docs/installation/releases_en.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/installation/releases_en.md b/docs/installation/releases_en.md index 6c05f4cd9..b9ac1b955 100644 --- a/docs/installation/releases_en.md +++ b/docs/installation/releases_en.md @@ -236,7 +236,13 @@ chmod +x /etc/periodic/daily/renew-pleroma-cert # If everything worked this should output /etc/periodic/daily/renew-pleroma-cert run-parts --test /etc/periodic/daily ``` -### Running Mix tasks +### Running mix tasks +Throughout the wiki and guides there is a lot of references to mix tasks. Since `mix` is a build tool, you can't just call `mix pleroma.task`, instead you should call `pleroma_ctl` stripping pleroma/ecto namespace. + +So for example, if the task is `mix pleroma.user set admin --admin`, you should run it like this: +```sh +su pleroma -s $SHELL -lc "./bin/pleroma_ctl user set admin --admin" +``` ### Updating Generally, doing the following is enough: ```sh From 997e766929172eddade2416c9e915806a402a8d1 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sun, 23 Jun 2019 07:39:23 +0300 Subject: [PATCH 31/56] Remove sudo in the nginx config command example --- installation/pleroma.nginx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/installation/pleroma.nginx b/installation/pleroma.nginx index de380a6ca..e3c70de54 100644 --- a/installation/pleroma.nginx +++ b/installation/pleroma.nginx @@ -17,7 +17,7 @@ server { # Uncomment this if you need to use the 'webroot' method with certbot. Make sure # that the directory exists and that it is accessible by the webserver. If you followed - # the guide, you already ran 'sudo mkdir -p /var/lib/letsencrypt' to create the folder. + # the guide, you already ran 'mkdir -p /var/lib/letsencrypt' to create the folder. # You may need to load this file with the ssl server block commented out, run certbot # to get the certificate, and then uncomment it. # From 66e92dc0ca9fe50dad5a758cf2b16543bff03c2e Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sun, 23 Jun 2019 07:43:45 +0300 Subject: [PATCH 32/56] Add a Further Reading section to the OTP install guide --- docs/installation/releases_en.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/installation/releases_en.md b/docs/installation/releases_en.md index b9ac1b955..e9d913604 100644 --- a/docs/installation/releases_en.md +++ b/docs/installation/releases_en.md @@ -253,3 +253,10 @@ su pleroma -s $SHELL -lc "./bin/pleroma_ctl update" su pleroma -s $SHELL -lc "./bin/pleroma_ctl migrate" ``` But you should **always check the release notes/changelog** in case there are config deprecations, special update steps, etc. + +## Further reading +* [Configuration](config.html) +* [Pleroma's base config.exs](https://git.pleroma.social/pleroma/pleroma/blob/master/config/config.exs) +* [Hardening your instance](hardening.html) +* [Pleroma Clients](clients.html) +* [Emoji pack manager](Mix.Tasks.Pleroma.Emoji.html) From 1d3c5e434df83ce2da1b1c67090192b115b4e905 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sun, 23 Jun 2019 07:44:10 +0300 Subject: [PATCH 33/56] releases_en.md -> otp_en.md --- docs/installation/{releases_en.md => otp_en.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/installation/{releases_en.md => otp_en.md} (100%) diff --git a/docs/installation/releases_en.md b/docs/installation/otp_en.md similarity index 100% rename from docs/installation/releases_en.md rename to docs/installation/otp_en.md From 40a62839ffeb5358e600d3bbc5fab4843afdc1af Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sun, 23 Jun 2019 08:35:35 +0300 Subject: [PATCH 34/56] Use build-base instead of individual packages --- docs/installation/otp_en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation/otp_en.md b/docs/installation/otp_en.md index e9d913604..667d3cef7 100644 --- a/docs/installation/otp_en.md +++ b/docs/installation/otp_en.md @@ -51,7 +51,7 @@ apt install postgresql-11-rum ``` Alpine: ```sh -apk add gcc make git postgresql-dev musl-dev +apk add git build-base postgresql-dev git clone https://github.com/postgrespro/rum /tmp/rum cd /tmp/rum make USE_PGXS=1 From 7fc226e0fe6d446b0e6614f9a531f6747b1bb34c Mon Sep 17 00:00:00 2001 From: rinpatch Date: Mon, 24 Jun 2019 02:50:28 +0300 Subject: [PATCH 35/56] Remove the warning about alpine as the issue is now solved --- docs/installation/otp_en.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/installation/otp_en.md b/docs/installation/otp_en.md index 667d3cef7..fa71f23e1 100644 --- a/docs/installation/otp_en.md +++ b/docs/installation/otp_en.md @@ -33,9 +33,8 @@ apt install curl unzip libncurses5 postgresql postgresql-contrib nginx certbot ``` Alpine: -**Warning:** There has been some changes to musl on Alpine 3.10 which need an Elixir rebuild. Since the build machines are running Alpine 3.9 running the builds on 3.10 will likely fail with "dlsym: Resource temporarily unavailable". If you have not updated yet, replace `latest-stable` with `v3.9` in `/etc/apk/repositories`. If you have, try downgrading `musl` to `1.1.20-r3` ```sh -echo "http://nl.alpinelinux.org/alpine/v3.9/community" >> /etc/apk/repositories +echo "http://nl.alpinelinux.org/alpine/latest-stable/community" >> /etc/apk/repositories apk update apk add curl unzip ncurses postgresql postgresql-contrib nginx certbot ``` From 5b76c3141f7945f76b8f3f84990cce8332152f71 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Mon, 24 Jun 2019 10:08:33 +0300 Subject: [PATCH 36/56] Use supervise-daemon(8) for the alpine service --- rel/files/installation/init.d/pleroma | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rel/files/installation/init.d/pleroma b/rel/files/installation/init.d/pleroma index de007c5e3..dea1db26c 100755 --- a/rel/files/installation/init.d/pleroma +++ b/rel/files/installation/init.d/pleroma @@ -1,5 +1,7 @@ #!/sbin/openrc-run +supervisor=supervise-daemon + # Requires OpenRC >= 0.35 directory=/opt/pleroma @@ -14,5 +16,6 @@ retry="SIGTERM/30/SIGKILL/5" pidfile="/var/run/pleroma.pid" depend() { - need nginx postgresql + want nginx + need postgresql } From 687f0aee51ad5ed4483317febe47be3f0685992c Mon Sep 17 00:00:00 2001 From: rinpatch Date: Mon, 24 Jun 2019 11:51:02 +0300 Subject: [PATCH 37/56] Basic skeleton of "Switching a from-source install to OTP releases" --- .../migrating_from_source_otp_en.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 docs/installation/migrating_from_source_otp_en.md diff --git a/docs/installation/migrating_from_source_otp_en.md b/docs/installation/migrating_from_source_otp_en.md new file mode 100644 index 000000000..2f7a450d6 --- /dev/null +++ b/docs/installation/migrating_from_source_otp_en.md @@ -0,0 +1,18 @@ +# Switching a from-source install to OTP releases +## Why would one want to switch? +Benefits of OTP releases over from-source installs include: +* Less space used. OTP releases come without source code, build tools, have docs and debug symbols stripped from the compiled bytecode and do not cointain tests (100mb because of all the fixtures) and docs. +* Minimal system dependencies. Excluding the database and reverse proxy, all you need to download and run a release is `curl`, `unzip` and `ncurses`. Because Erlang runtime and Elixir are shipped with Pleroma, one can use the latest BEAM optimizations and Pleroma features, without having to worry about outdated system repos or a missing `erlang-*` package. +* Potentially less bugs and better performance. This extends on the previous point, because we have control over exactly what gets shipped, we can tweak the VM arguments and forget about weird bugs due to Erlang/Elixir version mismatches. +* Faster and less bug-prone mix tasks. On a from-source install one has to wait untill a new Pleroma node is started for each mix task and they execute outside of the instance context (for example if you deleted a user via a mix task, the instance will have no knowledge of that and continue to display status count and follows before the cache expires). Mix tasks in OTP releases are executed by calling into a running instance via RPC, which solves both of these problems. + +### Sounds great, how do I switch? +Currently we support Linux machines with GNU (e.g. Debian, Ubuntu) or musl (e.g. Alpine) libc and `x86_64`, `aarch64` or `armv7l` CPUs. If you are unsure you can check the [Detecting flavour](otp_en.html#detecting-flavour) section in OTP install guide. If your platform is supported, proceed with the guide, if not check the [My platform is not supported](#my-platform-is-not-supported) section. +### I don't think it is worth the effort, can I stay on a from-source install? +Yes, currently there are no plans to deprecate them. +### My platform is not supported +If you believe your platform is a popular choice for running Pleroma instances, or has the potential to become one you can [file an issue on our Gitlab](https://git.pleroma.social/pleroma/pleroma/issues/new). If not, guides on how to build and update releases by yourself will be available soon. +## Moving uploads/instance static directory +## Moving emoji +## Moving the config +## Installing the release From 57d18b06ab2b763922a7894aece982adf97c139e Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 25 Jun 2019 04:55:41 +0300 Subject: [PATCH 38/56] Remove the useless specification of test size and make the main points bold --- docs/installation/migrating_from_source_otp_en.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/installation/migrating_from_source_otp_en.md b/docs/installation/migrating_from_source_otp_en.md index 2f7a450d6..ab140767e 100644 --- a/docs/installation/migrating_from_source_otp_en.md +++ b/docs/installation/migrating_from_source_otp_en.md @@ -1,10 +1,10 @@ # Switching a from-source install to OTP releases ## Why would one want to switch? Benefits of OTP releases over from-source installs include: -* Less space used. OTP releases come without source code, build tools, have docs and debug symbols stripped from the compiled bytecode and do not cointain tests (100mb because of all the fixtures) and docs. -* Minimal system dependencies. Excluding the database and reverse proxy, all you need to download and run a release is `curl`, `unzip` and `ncurses`. Because Erlang runtime and Elixir are shipped with Pleroma, one can use the latest BEAM optimizations and Pleroma features, without having to worry about outdated system repos or a missing `erlang-*` package. -* Potentially less bugs and better performance. This extends on the previous point, because we have control over exactly what gets shipped, we can tweak the VM arguments and forget about weird bugs due to Erlang/Elixir version mismatches. -* Faster and less bug-prone mix tasks. On a from-source install one has to wait untill a new Pleroma node is started for each mix task and they execute outside of the instance context (for example if you deleted a user via a mix task, the instance will have no knowledge of that and continue to display status count and follows before the cache expires). Mix tasks in OTP releases are executed by calling into a running instance via RPC, which solves both of these problems. +* **Less space used.** OTP releases come without source code, build tools, have docs and debug symbols stripped from the compiled bytecode and do not cointain tests and docs. +* **Minimal system dependencies.** Excluding the database and reverse proxy, all you need to download and run a release is `curl`, `unzip` and `ncurses`. Because Erlang runtime and Elixir are shipped with Pleroma, one can use the latest BEAM optimizations and Pleroma features, without having to worry about outdated system repos or a missing `erlang-*` package. +* **Potentially less bugs and better performance.** This extends on the previous point, because we have control over exactly what gets shipped, we can tweak the VM arguments and forget about weird bugs due to Erlang/Elixir version mismatches. +* **Faster and less bug-prone mix tasks.** On a from-source install one has to wait untill a new Pleroma node is started for each mix task and they execute outside of the instance context (for example if you deleted a user via a mix task, the instance will have no knowledge of that and continue to display status count and follows before the cache expires). Mix tasks in OTP releases are executed by calling into a running instance via RPC, which solves both of these problems. ### Sounds great, how do I switch? Currently we support Linux machines with GNU (e.g. Debian, Ubuntu) or musl (e.g. Alpine) libc and `x86_64`, `aarch64` or `armv7l` CPUs. If you are unsure you can check the [Detecting flavour](otp_en.html#detecting-flavour) section in OTP install guide. If your platform is supported, proceed with the guide, if not check the [My platform is not supported](#my-platform-is-not-supported) section. From 44aa895b78f7b37372df4b2ec2e4ba1177516a28 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 25 Jun 2019 05:50:25 +0300 Subject: [PATCH 39/56] Add a note that OTP releases don't contain revision history --- docs/installation/migrating_from_source_otp_en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation/migrating_from_source_otp_en.md b/docs/installation/migrating_from_source_otp_en.md index ab140767e..33e1eaaf0 100644 --- a/docs/installation/migrating_from_source_otp_en.md +++ b/docs/installation/migrating_from_source_otp_en.md @@ -1,7 +1,7 @@ # Switching a from-source install to OTP releases ## Why would one want to switch? Benefits of OTP releases over from-source installs include: -* **Less space used.** OTP releases come without source code, build tools, have docs and debug symbols stripped from the compiled bytecode and do not cointain tests and docs. +* **Less space used.** OTP releases come without source code, build tools, have docs and debug symbols stripped from the compiled bytecode and do not cointain tests, docs, revision history. * **Minimal system dependencies.** Excluding the database and reverse proxy, all you need to download and run a release is `curl`, `unzip` and `ncurses`. Because Erlang runtime and Elixir are shipped with Pleroma, one can use the latest BEAM optimizations and Pleroma features, without having to worry about outdated system repos or a missing `erlang-*` package. * **Potentially less bugs and better performance.** This extends on the previous point, because we have control over exactly what gets shipped, we can tweak the VM arguments and forget about weird bugs due to Erlang/Elixir version mismatches. * **Faster and less bug-prone mix tasks.** On a from-source install one has to wait untill a new Pleroma node is started for each mix task and they execute outside of the instance context (for example if you deleted a user via a mix task, the instance will have no knowledge of that and continue to display status count and follows before the cache expires). Mix tasks in OTP releases are executed by calling into a running instance via RPC, which solves both of these problems. From e404335af8fc214b84f9fe633830ba549bd322f7 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 26 Jun 2019 11:34:58 +0300 Subject: [PATCH 40/56] Add all the remaining sections to Switching to OTP releases --- .../migrating_from_source_otp_en.md | 137 +++++++++++++++++- 1 file changed, 130 insertions(+), 7 deletions(-) diff --git a/docs/installation/migrating_from_source_otp_en.md b/docs/installation/migrating_from_source_otp_en.md index 33e1eaaf0..0f790b4df 100644 --- a/docs/installation/migrating_from_source_otp_en.md +++ b/docs/installation/migrating_from_source_otp_en.md @@ -2,17 +2,140 @@ ## Why would one want to switch? Benefits of OTP releases over from-source installs include: * **Less space used.** OTP releases come without source code, build tools, have docs and debug symbols stripped from the compiled bytecode and do not cointain tests, docs, revision history. -* **Minimal system dependencies.** Excluding the database and reverse proxy, all you need to download and run a release is `curl`, `unzip` and `ncurses`. Because Erlang runtime and Elixir are shipped with Pleroma, one can use the latest BEAM optimizations and Pleroma features, without having to worry about outdated system repos or a missing `erlang-*` package. +* **Minimal system dependencies.** Excluding the database and reverse proxy, only `curl`, `unzip` and `ncurses` are needed to download and run the release. Because Erlang runtime and Elixir are shipped with Pleroma, one can use the latest BEAM optimizations and Pleroma features, without having to worry about outdated system repos or a missing `erlang-*` package. * **Potentially less bugs and better performance.** This extends on the previous point, because we have control over exactly what gets shipped, we can tweak the VM arguments and forget about weird bugs due to Erlang/Elixir version mismatches. -* **Faster and less bug-prone mix tasks.** On a from-source install one has to wait untill a new Pleroma node is started for each mix task and they execute outside of the instance context (for example if you deleted a user via a mix task, the instance will have no knowledge of that and continue to display status count and follows before the cache expires). Mix tasks in OTP releases are executed by calling into a running instance via RPC, which solves both of these problems. +* **Faster and less bug-prone mix tasks.** On a from-source install one has to wait untill a new Pleroma node is started for each mix task and they execute outside of the instance context (for example if a user was deleted via a mix task, the instance will have no knowledge of that and continue to display status count and follows before the cache expires). Mix tasks in OTP releases are executed by calling into a running instance via RPC, which solves both of these problems. ### Sounds great, how do I switch? -Currently we support Linux machines with GNU (e.g. Debian, Ubuntu) or musl (e.g. Alpine) libc and `x86_64`, `aarch64` or `armv7l` CPUs. If you are unsure you can check the [Detecting flavour](otp_en.html#detecting-flavour) section in OTP install guide. If your platform is supported, proceed with the guide, if not check the [My platform is not supported](#my-platform-is-not-supported) section. +Currently we support Linux machines with GNU (e.g. Debian, Ubuntu) or musl (e.g. Alpine) libc and `x86_64`, `aarch64` or `armv7l` CPUs. If you are unsure, check the [Detecting flavour](otp_en.html#detecting-flavour) section in OTP install guide. If your platform is supported, proceed with the guide, if not check the [My platform is not supported](#my-platform-is-not-supported) section. ### I don't think it is worth the effort, can I stay on a from-source install? Yes, currently there are no plans to deprecate them. + ### My platform is not supported -If you believe your platform is a popular choice for running Pleroma instances, or has the potential to become one you can [file an issue on our Gitlab](https://git.pleroma.social/pleroma/pleroma/issues/new). If not, guides on how to build and update releases by yourself will be available soon. -## Moving uploads/instance static directory -## Moving emoji -## Moving the config +If you think your platform is a popular choice for running Pleroma instances, or has the potential to become one, you can [file an issue on our Gitlab](https://git.pleroma.social/pleroma/pleroma/issues/new). If not, guides on how to build and update releases by yourself will be available soon. +## Pre-requisites +You will be running commands as root. If you aren't root already, please elevate your priviledges by executing `sudo su`/`su`. + +The system needs to have `curl` and `unzip` installed for downloading and unpacking release builds. + +Debian/Ubuntu: +```sh +apt install curl unzip +``` +Alpine: +``` +apk add curl unzip + +``` +## Moving content out of the application directory +When using OTP releases the application directory changes with every version so it would be a bother to keep content there (and also dangerous unless `--no-rm` option is used when updating). Fortunately almost all paths in Pleroma are configurable, so it is possible to move them out of there. + +Pleroma should be stopped before proceeding. + +### Moving uploads/custom public files directory +```sh +# Create uploads directory and set proper permissions (skip if using a remote uploader) +# Note: It does not have to be `/var/lib/pleroma/uploads`, you can configure it to be something else later +mkdir -p /var/lib/pleroma/uploads +chown -R pleroma /var/lib/pleroma + +# Create custom public files directory +# Note: It does not have to be `/var/lib/pleroma/static`, you can configure it to be something else later +mkdir -p /var/lib/pleroma/static +chown -R pleroma /var/lib/pleroma + +# If you use the local uploader with default settings your uploads should be located in `~pleroma/uploads` +mv ~pleroma/uploads /var/lib/pleroma/uploads + +# If you have created the custom public files directory with default settings it should be located in `~pleroma/instance/static` +mv ~pleroma/instance/static /var/lib/pleroma/static +``` + +### Moving emoji +Assuming you have all emojis in subdirectories of `priv/static/emoji` moving them can be done with +```sh +mkdir /var/lib/pleroma/static/emoji +ls -d ~pleroma/priv/static/emoji/*/ | xargs -i sh -c 'mv "{}" "/var/lib/pleroma/static/emoji/$(basename {})"' +``` + +But, if for some reason you have custom emojis in the root directory you should copy the whole directory instead. +```sh +mv ~pleroma/priv/static/emoji /var/lib/pleroma/static/emoji +``` +and then copy custom emojis to `/var/lib/pleroma/static/emoji/custom`. + +This is needed because storing custom emojis in the root directory is deprecated, but if you just move them to `/var/lib/pleroma/static/emoji/custom` it will break emoji urls on old posts. + +Note that globs have been replaced with `pack_extensions`, so if your emojis are not in png/gif you should [modify the default value](config.html#emoji). + +### Moving the config +```sh +# Create the config directory +# The default path for Pleroma config is /etc/pleroma/config.exs +# but it can be set via PLEROMA_CONFIG_PATH environment variable +mkdir -p /etc/pleroma + +# Move the config file +mv ~pleroma/config/prod.secret.exs /etc/pleroma/config.exs + +# Change `use Mix.Config` at the top to `import Config` +$EDITOR /etc/pleroma/config.exs +``` ## Installing the release +```sh +# Delete all files in pleroma user's directory +rm -r ~pleroma/* + +# Clone the release build into a temporary directory and unpack it +su pleroma -s $SHELL -lc " +curl 'https://git.pleroma.social/api/v4/projects/2/jobs/artifacts/master/download?job=$FLAVOUR' -o /tmp/pleroma.zip +unzip /tmp/pleroma.zip -d /tmp/ +" + +# Move the release to the home directory and delete temporary files +su pleroma -s $SHELL -lc " +mv /tmp/release/* /opt/pleroma +rmdir /tmp/release +rm /tmp/pleroma.zip +" + +# Start the instance to verify that everything is working as expected +su pleroma -s $SHELL -lc "./bin/pleroma daemon" + +# Wait for about 20 seconds and query the instance endpoint, if it shows your uri, name and email correctly, you are configured correctly +sleep 20 && curl http://localhost:4000/api/v1/instance + +# Stop the instance +su pleroma -s $SHELL -lc "./bin/pleroma stop" +``` + +## Setting up a system service +OTP releases have different service files than from-source installs so they need to be copied over again. + +Debian/Ubuntu: +```sh +# Copy the service into a proper directory +cp ~pleroma/installation/pleroma.service /etc/systemd/system/pleroma.service + +# Reload service files +systemctl reload-daemon + +# Reenable pleroma to start on boot +systemctl reenable pleroma + +# Start pleroma +systemctl start pleroma +``` + +Alpine: +```sh +# Copy the service into a proper directory +cp -f ~pleroma/installation/init.d/pleroma /etc/init.d/pleroma + +# Start pleroma +rc-service pleroma start +``` +## Running mix tasks +Refer to [Running mix tasks](otp_en.html#running-mix-tasks) section from OTP release installation guide. +## Updating +Refer to [Updating](otp_en.html#updating) section from OTP release installation guide. From 825077a5b0dc0c90d93bc94ae83398c4f68d0003 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Wed, 26 Jun 2019 18:36:42 +0700 Subject: [PATCH 41/56] Add Idempotency plug --- lib/pleroma/plugs/idempotency_plug.ex | 82 +++++++++++++++++++ test/plugs/idempotency_plug_test.exs | 110 ++++++++++++++++++++++++++ 2 files changed, 192 insertions(+) create mode 100644 lib/pleroma/plugs/idempotency_plug.ex create mode 100644 test/plugs/idempotency_plug_test.exs diff --git a/lib/pleroma/plugs/idempotency_plug.ex b/lib/pleroma/plugs/idempotency_plug.ex new file mode 100644 index 000000000..442573d60 --- /dev/null +++ b/lib/pleroma/plugs/idempotency_plug.ex @@ -0,0 +1,82 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Plugs.IdempotencyPlug do + import Phoenix.Controller, only: [json: 2] + import Plug.Conn + + @behaviour Plug + + @impl true + def init(opts), do: opts + + # Sending idempotency keys in `GET` and `DELETE` requests has no effect and should be avoided, as these requests are idempotent by definition. + @impl true + def call(%{method: method} = conn, _) when method in ["POST", "PUT", "PATCH"] do + case get_req_header(conn, "idempotency-key") do + [key] -> process_request(conn, key) + _ -> conn + end + end + + def call(conn, _), do: conn + + def process_request(conn, key) do + case Cachex.get(:idempotency_cache, key) do + {:ok, nil} -> + cache_resposnse(conn, key) + + {atom, message} when atom in [:ignore, :error] -> + render_error(conn, message) + + {:ok, record} -> + send_cached(conn, key, record) + end + end + + defp cache_resposnse(conn, key) do + Plug.Conn.register_before_send(conn, fn conn -> + [request_id] = get_resp_header(conn, "x-request-id") + content_type = get_content_type(conn) + + record = {request_id, content_type, conn.status, conn.resp_body} + {:ok, _} = Cachex.put(:idempotency_cache, key, record) + + conn + |> put_resp_header("idempotency-key", key) + |> put_resp_header("x-original-request-id", request_id) + end) + end + + defp send_cached(conn, key, record) do + {request_id, content_type, status, body} = record + + conn + |> put_resp_header("idempotency-key", key) + |> put_resp_header("idempotent-replayed", "true") + |> put_resp_header("x-original-request-id", request_id) + |> put_resp_content_type(content_type) + |> send_resp(status, body) + |> halt() + end + + defp render_error(conn, message) do + conn + |> put_status(:unprocessable_entity) + |> json(%{error: message}) + |> halt() + end + + defp get_content_type(conn) do + [content_type] = get_resp_header(conn, "content-type") + + if String.contains?(content_type, ";") do + content_type + |> String.split(";") + |> hd() + else + content_type + end + end +end diff --git a/test/plugs/idempotency_plug_test.exs b/test/plugs/idempotency_plug_test.exs new file mode 100644 index 000000000..aebc463e9 --- /dev/null +++ b/test/plugs/idempotency_plug_test.exs @@ -0,0 +1,110 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Plugs.IdempotencyPlugTest do + use ExUnit.Case, async: true + use Plug.Test + + alias Pleroma.Plugs.IdempotencyPlug + alias Plug.Conn + + test "returns result from cache" do + key = "test1" + orig_request_id = "test1" + second_request_id = "test2" + body = "testing" + status = 200 + + :post + |> conn("/cofe") + |> put_req_header("idempotency-key", key) + |> Conn.put_resp_header("x-request-id", orig_request_id) + |> Conn.put_resp_content_type("application/json") + |> IdempotencyPlug.call([]) + |> Conn.send_resp(status, body) + + conn2 = + :post + |> conn("/cofe") + |> put_req_header("idempotency-key", key) + |> Conn.put_resp_header("x-request-id", second_request_id) + |> Conn.put_resp_content_type("application/json") + |> IdempotencyPlug.call([]) + + assert_raise Conn.AlreadySentError, fn -> + Conn.send_resp(conn2, :im_a_teapot, "no cofe") + end + + assert conn2.resp_body == body + assert conn2.status == status + + assert [^second_request_id] = Conn.get_resp_header(conn2, "x-request-id") + assert [^orig_request_id] = Conn.get_resp_header(conn2, "x-original-request-id") + assert [^key] = Conn.get_resp_header(conn2, "idempotency-key") + assert ["true"] = Conn.get_resp_header(conn2, "idempotent-replayed") + assert ["application/json; charset=utf-8"] = Conn.get_resp_header(conn2, "content-type") + end + + test "pass conn downstream if the cache not found" do + key = "test2" + orig_request_id = "test3" + body = "testing" + status = 200 + + conn = + :post + |> conn("/cofe") + |> put_req_header("idempotency-key", key) + |> Conn.put_resp_header("x-request-id", orig_request_id) + |> Conn.put_resp_content_type("application/json") + |> IdempotencyPlug.call([]) + |> Conn.send_resp(status, body) + + assert conn.resp_body == body + assert conn.status == status + + assert [] = Conn.get_resp_header(conn, "idempotent-replayed") + assert [^key] = Conn.get_resp_header(conn, "idempotency-key") + end + + test "passes conn downstream if idempotency is not present in headers" do + orig_request_id = "test4" + body = "testing" + status = 200 + + conn = + :post + |> conn("/cofe") + |> Conn.put_resp_header("x-request-id", orig_request_id) + |> Conn.put_resp_content_type("application/json") + |> IdempotencyPlug.call([]) + |> Conn.send_resp(status, body) + + assert [] = Conn.get_resp_header(conn, "idempotency-key") + end + + test "doesn't work with GET/DELETE" do + key = "test3" + body = "testing" + status = 200 + + conn = + :get + |> conn("/cofe") + |> put_req_header("idempotency-key", key) + |> IdempotencyPlug.call([]) + |> Conn.send_resp(status, body) + + assert [] = Conn.get_resp_header(conn, "idempotency-key") + + conn = + :delete + |> conn("/cofe") + |> put_req_header("idempotency-key", key) + |> IdempotencyPlug.call([]) + |> Conn.send_resp(status, body) + + assert [] = Conn.get_resp_header(conn, "idempotency-key") + end +end From 74132e371545c0c6090cfefa22c4ad3f5c505a40 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Wed, 26 Jun 2019 18:42:49 +0700 Subject: [PATCH 42/56] Enable IdempotencyPlug for the all API --- lib/pleroma/web/router.ex | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index c504116b6..055289dc5 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -27,6 +27,7 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Plugs.UserEnabledPlug) plug(Pleroma.Plugs.SetUserSessionIdPlug) plug(Pleroma.Plugs.EnsureUserKeyPlug) + plug(Pleroma.Plugs.IdempotencyPlug) end pipeline :authenticated_api do @@ -41,6 +42,7 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Plugs.UserEnabledPlug) plug(Pleroma.Plugs.SetUserSessionIdPlug) plug(Pleroma.Plugs.EnsureAuthenticatedPlug) + plug(Pleroma.Plugs.IdempotencyPlug) end pipeline :admin_api do @@ -57,6 +59,7 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Plugs.SetUserSessionIdPlug) plug(Pleroma.Plugs.EnsureAuthenticatedPlug) plug(Pleroma.Plugs.UserIsAdminPlug) + plug(Pleroma.Plugs.IdempotencyPlug) end pipeline :mastodon_html do From 0b8aeac0f3ff560442f412301acb581c2ef1684b Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Wed, 26 Jun 2019 18:49:14 +0700 Subject: [PATCH 43/56] Remove previous idempotency implementation from `post_status` --- .../mastodon_api/mastodon_api_controller.ex | 24 ++----------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 9b9eca2a1..d2f08d503 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -561,18 +561,13 @@ def post_status(%{assigns: %{user: user}} = conn, %{"status" => _} = params) do else params = Map.drop(params, ["scheduled_at"]) - case get_cached_status_or_post(conn, params) do - {:ignore, message} -> - conn - |> put_status(422) - |> json(%{error: message}) - + case CommonAPI.post(user, params) do {:error, message} -> conn |> put_status(422) |> json(%{error: message}) - {_, activity} -> + {:ok, activity} -> conn |> put_view(StatusView) |> try_render("status.json", %{activity: activity, for: user, as: :activity}) @@ -580,21 +575,6 @@ def post_status(%{assigns: %{user: user}} = conn, %{"status" => _} = params) do end end - defp get_cached_status_or_post(%{assigns: %{user: user}} = conn, params) do - idempotency_key = - case get_req_header(conn, "idempotency-key") do - [key] -> key - _ -> Ecto.UUID.generate() - end - - Cachex.fetch(:idempotency_cache, idempotency_key, fn _ -> - case CommonAPI.post(user, params) do - {:ok, activity} -> activity - {:error, message} -> {:ignore, message} - end - end) - end - def delete_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do with {:ok, %Activity{}} <- CommonAPI.delete(id, user) do json(conn, %{}) From 159630b21cba565e02716e06e9d4f8ad1bf5dab5 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Wed, 26 Jun 2019 19:19:07 +0700 Subject: [PATCH 44/56] Fix credo warning --- lib/pleroma/plugs/idempotency_plug.ex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/plugs/idempotency_plug.ex b/lib/pleroma/plugs/idempotency_plug.ex index 442573d60..7c06be9ea 100644 --- a/lib/pleroma/plugs/idempotency_plug.ex +++ b/lib/pleroma/plugs/idempotency_plug.ex @@ -11,7 +11,9 @@ defmodule Pleroma.Plugs.IdempotencyPlug do @impl true def init(opts), do: opts - # Sending idempotency keys in `GET` and `DELETE` requests has no effect and should be avoided, as these requests are idempotent by definition. + # Sending idempotency keys in `GET` and `DELETE` requests has no effect + # and should be avoided, as these requests are idempotent by definition. + @impl true def call(%{method: method} = conn, _) when method in ["POST", "PUT", "PATCH"] do case get_req_header(conn, "idempotency-key") do From 877f91c0c489a7c33a6078dab4d00ceffc4af659 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 26 Jun 2019 15:20:22 +0300 Subject: [PATCH 45/56] Do not assume ~pleroma == /opt/pleroma --- docs/installation/migrating_from_source_otp_en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation/migrating_from_source_otp_en.md b/docs/installation/migrating_from_source_otp_en.md index 0f790b4df..add71d6af 100644 --- a/docs/installation/migrating_from_source_otp_en.md +++ b/docs/installation/migrating_from_source_otp_en.md @@ -94,7 +94,7 @@ unzip /tmp/pleroma.zip -d /tmp/ # Move the release to the home directory and delete temporary files su pleroma -s $SHELL -lc " -mv /tmp/release/* /opt/pleroma +mv /tmp/release/* ~pleroma/ rmdir /tmp/release rm /tmp/pleroma.zip " From f5f1bb35c3736dd591f6689813c7fe95650e4bba Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 26 Jun 2019 15:24:06 +0300 Subject: [PATCH 46/56] Instructions on getting the flavour --- docs/installation/migrating_from_source_otp_en.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/installation/migrating_from_source_otp_en.md b/docs/installation/migrating_from_source_otp_en.md index add71d6af..46dc7b53b 100644 --- a/docs/installation/migrating_from_source_otp_en.md +++ b/docs/installation/migrating_from_source_otp_en.md @@ -82,10 +82,15 @@ mv ~pleroma/config/prod.secret.exs /etc/pleroma/config.exs $EDITOR /etc/pleroma/config.exs ``` ## Installing the release +Before proceeding, get the flavour from [Detecting flavour](otp_en.html#detecting-flavour) section in OTP installation guide. ```sh # Delete all files in pleroma user's directory rm -r ~pleroma/* +# Set the flavour environment variable to the string you got in Detecting flavour section. +# For example if the flavour is `arm64-musl` the command will be +export FLAVOUR="arm64-musl" + # Clone the release build into a temporary directory and unpack it su pleroma -s $SHELL -lc " curl 'https://git.pleroma.social/api/v4/projects/2/jobs/artifacts/master/download?job=$FLAVOUR' -o /tmp/pleroma.zip From 889a9c3a3f427f5fdf2708fd281c1218d08b8fd7 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 27 Jun 2019 01:53:36 +0700 Subject: [PATCH 47/56] Polish IdempotencyPlug --- lib/pleroma/plugs/idempotency_plug.ex | 8 ++++---- .../mastodon_api/mastodon_api_controller.ex | 2 +- test/plugs/idempotency_plug_test.exs | 18 +++++++++--------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/pleroma/plugs/idempotency_plug.ex b/lib/pleroma/plugs/idempotency_plug.ex index 7c06be9ea..e99c5d279 100644 --- a/lib/pleroma/plugs/idempotency_plug.ex +++ b/lib/pleroma/plugs/idempotency_plug.ex @@ -29,16 +29,16 @@ def process_request(conn, key) do {:ok, nil} -> cache_resposnse(conn, key) - {atom, message} when atom in [:ignore, :error] -> - render_error(conn, message) - {:ok, record} -> send_cached(conn, key, record) + + {atom, message} when atom in [:ignore, :error] -> + render_error(conn, message) end end defp cache_resposnse(conn, key) do - Plug.Conn.register_before_send(conn, fn conn -> + register_before_send(conn, fn conn -> [request_id] = get_resp_header(conn, "x-request-id") content_type = get_content_type(conn) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index d2f08d503..7cdba4cc0 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -564,7 +564,7 @@ def post_status(%{assigns: %{user: user}} = conn, %{"status" => _} = params) do case CommonAPI.post(user, params) do {:error, message} -> conn - |> put_status(422) + |> put_status(:unprocessable_entity) |> json(%{error: message}) {:ok, activity} -> diff --git a/test/plugs/idempotency_plug_test.exs b/test/plugs/idempotency_plug_test.exs index aebc463e9..ac1735f13 100644 --- a/test/plugs/idempotency_plug_test.exs +++ b/test/plugs/idempotency_plug_test.exs @@ -24,7 +24,7 @@ test "returns result from cache" do |> IdempotencyPlug.call([]) |> Conn.send_resp(status, body) - conn2 = + conn = :post |> conn("/cofe") |> put_req_header("idempotency-key", key) @@ -33,17 +33,17 @@ test "returns result from cache" do |> IdempotencyPlug.call([]) assert_raise Conn.AlreadySentError, fn -> - Conn.send_resp(conn2, :im_a_teapot, "no cofe") + Conn.send_resp(conn, :im_a_teapot, "no cofe") end - assert conn2.resp_body == body - assert conn2.status == status + assert conn.resp_body == body + assert conn.status == status - assert [^second_request_id] = Conn.get_resp_header(conn2, "x-request-id") - assert [^orig_request_id] = Conn.get_resp_header(conn2, "x-original-request-id") - assert [^key] = Conn.get_resp_header(conn2, "idempotency-key") - assert ["true"] = Conn.get_resp_header(conn2, "idempotent-replayed") - assert ["application/json; charset=utf-8"] = Conn.get_resp_header(conn2, "content-type") + assert [^second_request_id] = Conn.get_resp_header(conn, "x-request-id") + assert [^orig_request_id] = Conn.get_resp_header(conn, "x-original-request-id") + assert [^key] = Conn.get_resp_header(conn, "idempotency-key") + assert ["true"] = Conn.get_resp_header(conn, "idempotent-replayed") + assert ["application/json; charset=utf-8"] = Conn.get_resp_header(conn, "content-type") end test "pass conn downstream if the cache not found" do From c6705144a2758c76943ad7967da412572efcbc2d Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Thu, 27 Jun 2019 04:19:44 +0000 Subject: [PATCH 48/56] don't delete config settings on admin update --- docs/api/admin_api.md | 2 +- lib/mix/tasks/pleroma/config.ex | 16 ++++++++++++---- .../web/admin_api/admin_api_controller.ex | 2 +- test/tasks/config_test.exs | 2 +- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/docs/api/admin_api.md b/docs/api/admin_api.md index c05a353d7..4be0ab0f8 100644 --- a/docs/api/admin_api.md +++ b/docs/api/admin_api.md @@ -579,7 +579,7 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret ## `/api/pleroma/admin/config` ### Update config settings Module name can be passed as string, which starts with `Pleroma`, e.g. `"Pleroma.Upload"`. -Atom or boolean value can be passed with `:` in the beginning, e.g. `":true"`, `":upload"`. +Atom or boolean value can be passed with `:` in the beginning, e.g. `":true"`, `":upload"`. For keys it is not needed. Integer with `i:`, e.g. `"i:150"`. Tuple with more than 2 values with `{"tuple": ["first_val", Pleroma.Module, []]}`. `{"tuple": ["some_string", "Pleroma.Some.Module", []]}` will be converted to `{"some_string", Pleroma.Some.Module, []}`. diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index 4ed2c9789..faa605d9b 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -36,9 +36,11 @@ def run(["migrate_to_db"]) do end end - def run(["migrate_from_db", env]) do + def run(["migrate_from_db", env, delete?]) do start_pleroma() + delete? = if delete? == "true", do: true, else: false + if Pleroma.Config.get([:instance, :dynamic_configuration]) do config_path = "config/#{env}.exported_from_db.secret.exs" @@ -47,7 +49,11 @@ def run(["migrate_from_db", env]) do Repo.all(Config) |> Enum.each(fn config -> - mark = if String.starts_with?(config.key, "Pleroma."), do: ",", else: ":" + mark = + if String.starts_with?(config.key, "Pleroma.") or + String.starts_with?(config.key, "Ueberauth"), + do: ",", + else: ":" IO.write( file, @@ -56,8 +62,10 @@ def run(["migrate_from_db", env]) do }\r\n" ) - {:ok, _} = Repo.delete(config) - Mix.shell().info("#{config.key} deleted from DB.") + if delete? do + {:ok, _} = Repo.delete(config) + Mix.shell().info("#{config.key} deleted from DB.") + end end) File.close(file) diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 953a22ea0..498beb56a 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -388,7 +388,7 @@ def config_update(conn, %{"configs" => configs}) do |> Enum.reject(&is_nil(&1)) Pleroma.Config.TransferTask.load_and_update_env() - Mix.Tasks.Pleroma.Config.run(["migrate_from_db", Pleroma.Config.get(:env)]) + Mix.Tasks.Pleroma.Config.run(["migrate_from_db", Pleroma.Config.get(:env), "false"]) updated else [] diff --git a/test/tasks/config_test.exs b/test/tasks/config_test.exs index 9c9a31bf4..83a363356 100644 --- a/test/tasks/config_test.exs +++ b/test/tasks/config_test.exs @@ -51,7 +51,7 @@ test "settings are migrated to file and deleted from db", %{temp_file: temp_file value: [key: "valu2", key2: [Pleroma.Repo]] }) - Mix.Tasks.Pleroma.Config.run(["migrate_from_db", "temp"]) + Mix.Tasks.Pleroma.Config.run(["migrate_from_db", "temp", "true"]) assert Repo.all(Config) == [] assert File.exists?(temp_file) From 4f44732100a23475a645d9e7070ca0a17934ee49 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 27 Jun 2019 09:45:13 +0300 Subject: [PATCH 49/56] Add a note on what OTP releases are --- docs/installation/migrating_from_source_otp_en.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/installation/migrating_from_source_otp_en.md b/docs/installation/migrating_from_source_otp_en.md index 46dc7b53b..4d6f20ee0 100644 --- a/docs/installation/migrating_from_source_otp_en.md +++ b/docs/installation/migrating_from_source_otp_en.md @@ -1,4 +1,6 @@ # Switching a from-source install to OTP releases +## What are OTP releases? +OTP releases are as close as you can get to binary releases with Erlang/Elixir. The release is self-contained, and provides everything needed to boot it, it is easily administered via the provided shell script to open up a remote console, start/stop/restart the release, start in the background, send remote commands, and more. ## Why would one want to switch? Benefits of OTP releases over from-source installs include: * **Less space used.** OTP releases come without source code, build tools, have docs and debug symbols stripped from the compiled bytecode and do not cointain tests, docs, revision history. From ceebe95c2751fa03c65f60a9f5a01b00de4a5bce Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 27 Jun 2019 09:51:00 +0300 Subject: [PATCH 50/56] Add a deprecation warning to the readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 928f75dc7..c6b176f4b 100644 --- a/README.md +++ b/README.md @@ -15,9 +15,9 @@ For clients it supports both the [GNU Social API with Qvitter extensions](https: If you want to run your own server, feel free to contact us at @lain@pleroma.soykaf.com or in our dev chat at #pleroma on freenode or via matrix at . ## Installation +**Note:** The guide below may be outdated and in most cases shouldn't be used. Instead check out our [wiki](https://docs.pleroma.social) for platform-specific installation instructions, most likely [Installing on Linux using OTP releases](https://docs.pleroma.social/otp_en.html) is the guide you need. ### Docker - While we don’t provide docker files, other people have written very good ones. Take a look at or . ### Dependencies From e91f09cfe6ebc6619e0eac204a71bef9562b9396 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 27 Jun 2019 09:59:21 +0300 Subject: [PATCH 51/56] Add a note about OS/Distro packages in the readme --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index c6b176f4b..41d454a03 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,9 @@ If you want to run your own server, feel free to contact us at @lain@pleroma.soy ## Installation **Note:** The guide below may be outdated and in most cases shouldn't be used. Instead check out our [wiki](https://docs.pleroma.social) for platform-specific installation instructions, most likely [Installing on Linux using OTP releases](https://docs.pleroma.social/otp_en.html) is the guide you need. +### OS/Distro packages +Currently Pleroma is not packaged by any OS/Distros, but feel free to reach out to us at [#pleroma-dev on freenode](https://webchat.freenode.net/?channels=%23pleroma-dev) or via matrix at for assistance. If you want to change default options in your Pleroma package, please **discuss it with us first**. + ### Docker While we don’t provide docker files, other people have written very good ones. Take a look at or . From f8ec3e129f8496e6d86e3fe9dc69a1567e1e2768 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Thu, 27 Jun 2019 13:00:22 -0500 Subject: [PATCH 52/56] In my experience syslog tags are usually lowercase --- config/config.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.exs b/config/config.exs index d381a8dc2..e337f00aa 100644 --- a/config/config.exs +++ b/config/config.exs @@ -169,7 +169,7 @@ config :logger, :ex_syslogger, level: :debug, - ident: "Pleroma", + ident: "pleroma", format: "$metadata[$level] $message", metadata: [:request_id] From e64c758cea858823ff9e04a87defe1d476737236 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Thu, 27 Jun 2019 16:25:55 -0500 Subject: [PATCH 53/56] Add changelog entry for syslog tag change --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index be0b74a16..447fa1700 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,6 +68,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - MRF: Support for filtering out likely spam messages by rejecting posts from new users that contain links. - Configuration: `ignore_hosts` option - Configuration: `ignore_tld` option +- Configuration: default syslog tag "Pleroma" is now lowercased to "pleroma" ### Changed - **Breaking:** bind to 127.0.0.1 instead of 0.0.0.0 by default From eeb419e3a0e8ad97b0061f5da9938bbf4f52c5c9 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 28 Jun 2019 09:41:34 +0300 Subject: [PATCH 54/56] Add a note about the develop branch --- docs/installation/migrating_from_source_otp_en.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/installation/migrating_from_source_otp_en.md b/docs/installation/migrating_from_source_otp_en.md index 4d6f20ee0..0b41d0c0e 100644 --- a/docs/installation/migrating_from_source_otp_en.md +++ b/docs/installation/migrating_from_source_otp_en.md @@ -1,6 +1,8 @@ # Switching a from-source install to OTP releases ## What are OTP releases? OTP releases are as close as you can get to binary releases with Erlang/Elixir. The release is self-contained, and provides everything needed to boot it, it is easily administered via the provided shell script to open up a remote console, start/stop/restart the release, start in the background, send remote commands, and more. +### Can I still run the develop branch if I decide to use them? +Yes, we produce builds for every commit in `develop`. However `develop` is considered unstable, please don't use it in production because of faster access to new features, unless you need them as an app developer. ## Why would one want to switch? Benefits of OTP releases over from-source installs include: * **Less space used.** OTP releases come without source code, build tools, have docs and debug symbols stripped from the compiled bytecode and do not cointain tests, docs, revision history. @@ -94,6 +96,7 @@ rm -r ~pleroma/* export FLAVOUR="arm64-musl" # Clone the release build into a temporary directory and unpack it +# Replace `master` with `develop` if you want to run the develop branch su pleroma -s $SHELL -lc " curl 'https://git.pleroma.social/api/v4/projects/2/jobs/artifacts/master/download?job=$FLAVOUR' -o /tmp/pleroma.zip unzip /tmp/pleroma.zip -d /tmp/ From efad26bbb9b134a684a6a0c21efa693f57824044 Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 28 Jun 2019 14:29:26 +0200 Subject: [PATCH 55/56] Update frontend. --- priv/static/index.html | 2 +- .../static/js/app.670c36c0acc42fadb4fe.js | Bin 0 -> 856921 bytes .../static/js/app.670c36c0acc42fadb4fe.js.map | Bin 0 -> 1429874 bytes .../static/js/app.83ab168f1882edc9bb37.js | Bin 855238 -> 0 bytes .../static/js/app.83ab168f1882edc9bb37.js.map | Bin 1425055 -> 0 bytes ...js => vendors~app.4b7be53256fba5c365c9.js} | Bin 430332 -> 430333 bytes .../vendors~app.4b7be53256fba5c365c9.js.map | Bin 0 -> 1994198 bytes .../vendors~app.ec33d2f791fb3c02da1d.js.map | Bin 1994202 -> 0 bytes priv/static/sw-pleroma.js | Bin 31068 -> 31068 bytes 9 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 priv/static/static/js/app.670c36c0acc42fadb4fe.js create mode 100644 priv/static/static/js/app.670c36c0acc42fadb4fe.js.map delete mode 100644 priv/static/static/js/app.83ab168f1882edc9bb37.js delete mode 100644 priv/static/static/js/app.83ab168f1882edc9bb37.js.map rename priv/static/static/js/{vendors~app.ec33d2f791fb3c02da1d.js => vendors~app.4b7be53256fba5c365c9.js} (85%) create mode 100644 priv/static/static/js/vendors~app.4b7be53256fba5c365c9.js.map delete mode 100644 priv/static/static/js/vendors~app.ec33d2f791fb3c02da1d.js.map diff --git a/priv/static/index.html b/priv/static/index.html index e57aec0f7..e58c4380b 100644 --- a/priv/static/index.html +++ b/priv/static/index.html @@ -1 +1 @@ -Pleroma
\ No newline at end of file +Pleroma
\ No newline at end of file diff --git a/priv/static/static/js/app.670c36c0acc42fadb4fe.js b/priv/static/static/js/app.670c36c0acc42fadb4fe.js new file mode 100644 index 0000000000000000000000000000000000000000..bd00063b8da350f042a3ca212fb55c9a4b5af4a9 GIT binary patch literal 856921 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

    625As^gh5%tk)*$D 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