{"id":44576058,"url":"https://github.com/asreview/asreview-server-stack","last_synced_at":"2026-02-14T05:10:19.228Z","repository":{"id":215777917,"uuid":"738109505","full_name":"asreview/asreview-server-stack","owner":"asreview","description":"Docker compose for setting up ASReview server with authentication","archived":false,"fork":false,"pushed_at":"2025-06-01T10:27:50.000Z","size":46,"stargazers_count":8,"open_issues_count":1,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-09-09T11:36:01.123Z","etag":null,"topics":["artificial-intelligence","asreview","docker","docker-compose","llm","natural-language-processing","systematic-reviews","utrecht-university"],"latest_commit_sha":null,"homepage":"https://asreview.ai","language":"Dockerfile","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/asreview.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"custom":["https://asreview.nl/donate"]}},"created_at":"2024-01-02T12:52:33.000Z","updated_at":"2025-09-03T13:35:56.000Z","dependencies_parsed_at":"2024-01-06T14:24:32.017Z","dependency_job_id":"e70443dd-0103-451e-bc2c-65a0433f1fe4","html_url":"https://github.com/asreview/asreview-server-stack","commit_stats":null,"previous_names":["asreview/asreview-server-stack"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/asreview/asreview-server-stack","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asreview%2Fasreview-server-stack","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asreview%2Fasreview-server-stack/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asreview%2Fasreview-server-stack/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asreview%2Fasreview-server-stack/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/asreview","download_url":"https://codeload.github.com/asreview/asreview-server-stack/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asreview%2Fasreview-server-stack/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29437371,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-14T03:34:37.767Z","status":"ssl_error","status_checked_at":"2026-02-14T03:34:09.092Z","response_time":53,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["artificial-intelligence","asreview","docker","docker-compose","llm","natural-language-processing","systematic-reviews","utrecht-university"],"created_at":"2026-02-14T05:10:18.594Z","updated_at":"2026-02-14T05:10:19.221Z","avatar_url":"https://github.com/asreview.png","language":"Dockerfile","funding_links":["https://asreview.nl/donate"],"categories":[],"sub_categories":[],"readme":"# Deploy ASReview LAB Server with authentication (Docker Compose)\n\n\u003e ⚠️ Deploying Docker containers in a public environment requires careful\n  consideration of security implications. Exposing services without proper\n  safeguards can lead to potential security vulnerabilities, unauthorized\n  access, and data breaches.\n\nThis repository, ASReview Server Stack, contains a recipe for building an\nauthenticated version of the ASReview LAB application in Docker containers in\nDocker Compose. It allows multiple users to access the application and create\nprivate projects. Users need to sign up (with various authentication methods)\nand sign in to access the app.\n\n\u003e ℹ️ Looking for a standalone Dockerfile with ASReview LAB, simulate, insights or\n  datatools? (Prefect for local use or small applications) See\n  https://asreview.readthedocs.io/en/stable/installation.html#install-with-docker\n  or https://github.com/asreview/asreview/pkgs/container/asreview.\n\n## Installation\n\nInstall Docker and Docker Compose to deploy the server stack.\n\n## Deploy to production\n\nTo run the ASReview LAB application as a shared service, a more complicated\ncontainer setup is adviced. A common, robust setup for a Flask application like\nASReview LAB is to use [Gunicorn](https://gunicorn.org/) as a WSGI server and\nuse [NGINX](https://www.nginx.com/) as a reverse proxy. See the Flask\ndocumentation on [Deploying to\nProduction](https://flask.palletsprojects.com/en/3.0.x/deploying/) for more\ninformation.\n\nASReview Server Stack consists of 3 containers: a database (PostgreSQL), an\nASReview, and a NGINX container. [Docker\nCompose](https://docs.docker.com/compose/) is used to run and serve this\nmulti-container application. In this folder, you find the following files of\ninterest:\n\n- `.env` - An environment variable file for all relevant (secret) parameters\n  (ports, frontend-domain, database, and Gunicorn related parameters)\n- `asreview.conf` - a NGINX configuration file\n- `docker-compose.yml` - the Docker Compose file that will create the Docker\n  containers\n- `asreview_config.toml` - the ASReview LAB config file with, for example,\n  authentication options and email server configuration.\n\n### Running the containers\n\nMake a clone or copy of the ASReview Server Stack folder. From the **root**\nfolder of the app execute the `docker compose` command to start your docker\ncontainers in attached mode:\n\n```\n$ docker compose up\n```\n\n### Email server\n\nFor account verification, but also for the forgot-password feature, an email\nserver is required. However, maintaining an email server can be demanding. This can be avoided by using a third-party service like\n[SendGrid](https://sendgrid.com/). Email server\nsettings can be set in the `asreview_config.toml` file.\n\n#### SendGrid\n\nIn this recipe, we use the SMTP Relay Service from\n[SendGrid](https://sendgrid.com/): every email sent by the ASReview application\nwill be relayed by this service. Sendgrid is free if you don't expect the\napplication to send more than 100 emails per day. Receiving reply emails from\nend-users is not possible if you use the Relay service.\n\nCreate an account at Sendgrid. Sign in and click on \"Email API\" in the menu and\nsubsequently click on the \"Integration Guide\" link. Then, choose \"SMTP Relay\",\ncreate an API key and copy the resulting settings (Server, Ports, Username and\nPassword) in your `asreview_config.toml` file. It's important to continue checking\nthe \"I've updated my settings\" checkbox when it's visible **and** click on the\n\"Next: verify Integration\" button before you run the Docker containers.\n\nIt is important to verify the reply address of any email the application\nwill send. While being logged in on the SendGrid website, click on \"Settings\" in\nthe menu, then on \"Sender Authentication\" and follow instructions.\n\nPlease note that sending emails via SendGrid with SSL requires port 465 to be\nopen for outbound connections on your server. Ensure that your firewall is configured\nappropriately.\n\n### Parameters in the .env file\n\nThe `.env` file contains parameters to deploy all containers. All variables that\nend with the `_PORT` suffix refer to the containers' external\nnetwork ports. The prefix of these variables explains for which container they\nare used. Note that the external port of the frontend container, the container\nthat will be directly used by the end-user, is 8080 and not 80. Change this to\n80 if you don't want to use port numbers in the URL of the ASReview LAB\napplication.\n\nThe value of the `WORKERS` parameter determines how many instances of the\nASReview app Gunicorn will start.\n\nVariables prefixed with `POSTGRES` are intended for use with the PostgreSQL\ndatabase. The `_USER` and `_PASSWORD` variables represent the database user and\npassword, respectively. The `_DB` variable specifies the database name.\n\n\u003e ⚠️ Please be aware to change the password in the `.env` file. If deploying\n  Docker containers in a public environment, it is advisable to modify the\n  database user to something less predictable and strengthen the password for\n  enhanced security.\n\n## Deploying to cloud provider\n\n### Digital Ocean\n\nThe following section describes how to deploy the authenticated application with\nemail verification on [Digital Ocean](https://www.digitalocean.com/). The\ndeployment is done on a bare Droplet running Ubuntu 22.04 with 1 CPU, 2 GB of\nmemory and a 50 GB SSD disk. Root access is assumed.\n\nFirst consideration is a (sub)domain name. If you have one, make sure the domain\nname points to the IP address of the Droplet. In this description, the IP\naddress is used to reach the application through a browser.\n\nEmail verification (also handy for forgotten passwords) is used. For that, a\nSendGrid password is required that comes from the [SendGrid setup](#sendgrid).\n\nSsh into your Droplet, update the list of packages and install the software for\nDocker:\n\n```\n$ sudo apt-get update\n$ for pkg in docker.io docker-doc docker-compose docker-compose-v2 \\\n    podman-docker containerd runc; do sudo apt-get remove $pkg; done\n$ sudo apt-get install ca-certificates curl gnupg\n$ sudo install -m 0755 -d /etc/apt/keyrings\n$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg\n$ sudo chmod a+r /etc/apt/keyrings/docker.gpg\n$ echo \\\n  \"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \\\n  $(. /etc/os-release \u0026\u0026 echo \"$VERSION_CODENAME\") stable\" | \\\n  sudo tee /etc/apt/sources.list.d/docker.list \u003e /dev/null\n$ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin\n```\n\nEnter 'Y' if prompted. If you get questions about restarting services just\nselect OK. Verify if all is up and running by creating a test container:\n\n```\n$ sudo docker run hello-world\n```\n\nIf all is well a message 'Hello from Docker' should appear with other\ninformation. Verify if Docker Compose is installed:\n\n```\n$ docker compose version\n```\n\nIf this fails, install Docker Compose with:\n\n```\n$ sudo apt-get install docker-compose-plugin\n```\n\nNext up are ports. It's best practice to enable the firewall and open the ports\nwe need. In this manual the frontend will run on port 8080 (deliberately\ndeviating from the usual port 80), and the backend runs on 8081.\n\n```\n$ sudo ufw default allow outgoing\n$ sudo ufw default deny incoming\n$ sudo ufw allow ssh\n$ sudo ufw allow 8080\n$ sudo ufw allow 8081\n$ sudo ufw enable\n```\n\nClone the ASReview Server Stack extension in the `asreview` folder:\n\n```\n$ git clone https://github.com/asreview/asreview-server-stack.git\n```\n\nNext up is configuring the `.env` file in server stack folder. Substitute\n`localhost` for the Droplet's IP address and enter the reserved external port\nnumbers:\n\n```\nFRONTEND_DOMAIN=http://\u003cIP address of Droplet\u003e\n\nFRONTEND_EXTERNAL_PORT=8080\nBACKEND_EXTERNAL_PORT=8081\n\nPOSTGRES_PASSWORD=\"\u003cPostgres Password\u003e\"\nPOSTGRES_USER=\"postgres\"\nPOSTGRES_DB=\"asreview_db\"\n```\n\nWith that out of the way, the containers can be build. Assuming the `asreview`\nroot folder is the working directory, enter the following command:\n\n```\n$ docker compose up\n```\n\nThis probably takes a couple of minutes. Wait until all containers are accounted\nfor (spinning up the backend container takes a bit longer than the other\ncontainers). Try to access the application by browsing to the IP address. Note\nthat the instance runs on http, **not** https. If all is well, stop the\ncontainers and spin them up again in detached mode:\n\n```\ndocker compose up -d\n```\n\n### Trouble Shooting\n\nIf the containers are built and running, but the application is unresponsive,\nconsider the following guidelines:\n\nIf there is no response whatsoever (no white page with spinner) check the url\nand the protocol that are used in the browser. Does it use http instead of\nhttps, and is the correct port being used (`http://\u003cIP-address\u003e:8080`)? If\nthat's the case, verify if the designated ports are really open on the Droplet.\n\nIn the `asreview_config.toml` the `SESSION_COOKIE_SAMESITE` parameter is set to the recommended\n\"Lax\" value. In this Docker setup, it is assumed that both the backend and\nfrontend can be accessed using the same domain name or IP address. When this is\nnot the case, don't forget to set the value of `SESSION_COOKIE_SAMESITE` to the\nstring \"None\". Although this is an unusual setup it may help if you only deploy\nthe backend and database containers and have a different frontend running on\nanother server.\n\nFinally, this setup does not support encryption. Its purpose is to deploy the\napplication as easy and quickly as possible. Dealing with certificates will make\nthings more complex (see following section). Since the unencrypted HTTP protocol is used, in\n`asreview_config.toml` the `SESSION_COOKIE_SECURE` and `REMEMBER_COOKIE_SECURE`\nparameters are set to `false`. If the setup is tweaked to work with\ncertificates, it is obviously best practice to set the values to `true`.\n\n## Upgrading security: migrate to HTTPS\n\nThis section assumes that all the steps outlined in the preceding sections have been completed.\n\nThe following extra steps are required to run the ASReview application with HTTPS:\n* Open up port 443 of the server.\n* A domain name and certificates for this domain name.\n* Change the Docker configuration.\n\n### Ports\n\nIn the sections above port 8080 was used for demonstrational purposes. For a secured application it's easier to stick with the default web ports 80 and 443. Make sure these ports are open. Additionally, ensure that the port to which the backend listens is also open. By default, in the `.env` file, that is port 8081.\n\nOn Ubuntu this can be accomplished withe the following commands:\n```\n$ sudo ufw allow 80\n$ sudo ufw allow 443\n$ sudo ufw allow 8081\n```\n\n### Domain name and certificates\n\nThe insecure version of the ASReview web application functions without a domain name; an IP address suffices. However, for a secure version, having a domain name is highly advisable. Ensure that there is an A record in the DNS linking the domain name to the server's IP address.\n\nA detailed explanation of domain certificates and how to obtain them falls beyond the document's focus. Usually an IT-department provides them. An alternative method would be to create self-signed certificates which is briefly explained below.\n\nOn the server, install [Certbot](https://certbot.eff.org/). The installation details differ per operating system, but the Certbot website allows customers to specify their system to help with the installation procedure. Once installed, shutdown any webserver that is running on the server and issue the following command:\n```\n$ sudo certbot certonly --standalone\n```\nProvide a necessary email address, agree with the terms of service and enter the domain name when prompted. After completion, the Certbot application produces 2 important files: `fullchain.pem` and `privkey.pem`. On a Linux server these files can typically be found under `/etc/letsencrypt/live/\u003cDOMAIN_NAME\u003e/`. Copy both files into the `asreview-server-stack` folder.\n\n### Update Docker configuration\n\nNumerous minor adjustments need to be made in almost every file within the asreview-server-stack directory. In alphabetical order:\n\n#### 1. .env\nMake sure the DOMAIN parameter points to a domain name and uses the 'https' protocol, and the FRONTEND_EXTERNAL_PORT is set to 80.\n```\nDOMAIN=https://\u003cDOMAIN NAME\u003e\nFRONTEND_EXTERNAL_PORT=80\n```\n\n#### 2. asreview_config.toml\nSet the following parameters to `true`:\n```\nSESSION_COOKIE_SECURE = true\nREMEMBER_COOKIE_SECURE = true\n```\n\n#### 3. asreview.conf\nSubstitute the original contents with:\n```\nevents {\n  worker_connections        1024;\n}\n\nhttp {\n\n  proxy_cache_path          /var/cache/nginx/asreview keys_zone=asreview:20m max_size=500m;\n\n  upstream asreview_container {\n    server                  asreview:5006;\n  }\n\n  server {\n    listen                  [::]:80;\n    listen                  80;\n    return                  301 https://$http_host$request_uri;\n  }\n\n  server {\n    listen                  [::]:443 ssl;\n    listen                  443 ssl;\n    http2                   on;\n\n    ssl_certificate         /etc/pemfiles/fullchain.pem;\n    ssl_certificate_key     /etc/pemfiles/privkey.pem;\n\n    gzip                    on;\n    gzip_http_version       1.0;\n    gzip_comp_level         2;\n    gzip_proxied            any;\n    gzip_types              application/javascript; # our css file is small and cached by browser\n\n    proxy_set_header        Host $http_host;\n    proxy_set_header        X-Real-IP $remote_addr;\n    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;\n    proxy_cache_key         $scheme://$host$uri$is_args$query_string;\n    \n    location / {\n      proxy_pass            https://asreview_container;\n    }\n\n    location = /favicon.ico {\n      proxy_pass            https://asreview_container;\n      proxy_cache           asreview;\n      proxy_cache_valid     200 100d;\n      proxy_ignore_headers  Cache-Control;\n\n      add_header            X-Proxy-Cache $upstream_cache_status;\n    }\n\n    location ^~ /static {\n      proxy_pass            https://asreview_container;\n      proxy_cache           asreview;\n      proxy_cache_valid     200 100d;\n      proxy_ignore_headers  Cache-Control;\n\n      add_header            X-Proxy-Cache $upstream_cache_status;\n    }\n  }\n}\n\n```\n\n#### 4. docker-compose.yml\nThe certificates must be made accessible in the server and asreview container, ports need to be adjusted and Gunicorn has to be started with the certificate files.\n\nIn the `asreview` container add the certificate files under `volume`:\n```\n    volumes:\n      - project-folder:/app/project_folder\n      - ./asreview_config.toml:/app/asreview_config.toml\n      - ./fullchain.pem:/app/fullchain.pem\n      - ./privkey.pem:/app/privkey.pem\n```\nAnd change the value of the `command` key into:\n```\n    command: \u003e\n      bash -c \"asreview auth-tool create-db\n      \u0026\u0026 gunicorn --certfile /app/fullchain.pem --keyfile /app/privkey.pem -w ${WORKERS}\n      -b \\\"0.0.0.0:5006\\\" \\\"asreview.webapp.app:create_app()\\\"\" # THIS\n```\n\nIn the `server` container explicitly set the `ports` to:\n```\n    ports:\n      - 80:80\n      - 443:443\n```\nNote that unsecured data traffic to port 80 will be redirected to the secured application.\n\nMake the certificates available for `asreview.conf` by adding them under the `volume` key:\n```\n    volumes:\n      - ./asreview.conf:/etc/nginx/nginx.conf\n      - ./fullchain.pem:/etc/pemfiles/fullchain.pem\n      - ./privkey.pem:/etc/pemfiles/privkey.pem\n``` \n\n(Re)Build and restart the containers. The application now utilizes HTTPS.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fasreview%2Fasreview-server-stack","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fasreview%2Fasreview-server-stack","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fasreview%2Fasreview-server-stack/lists"}