Self-Hosting Specify 7

:book: This guide describes how to self-host an environment of Specify 7.

:gear: This guide is intended for technical or IT users only.

[!info]
:thought_balloon: Before you begin, consider that the Specify Collections Consortium (SCC) offers the Specify Cloud hosting service to members of the consortium.

By choosing SCC’s Specify Cloud hosting, you get a fully managed Specify 7 environment with automatic updates, priority support, and low-latency servers in cloud regions around the world. Daily backups of your database and attachments ensure your data is always protected, and optional add-ons—like scalable digital asset storage, direct SQL access, and remote Specify 6 connectivity—give your IT team the flexibility they need without the extra maintenance overhead.

If you’d like pricing details or to discuss an evaluation period, please see our services prices or get in touch at membership@specifysoftware.org. We’d love to help you turn over the sysadmin headaches and focus on what you do best—advancing collection‐based research.

Introduction

This approach means that your IT support will need to be responsible for managing the server hosting Specify and the associated assets, updates, and day-to-day accesss troubleshooting. We ask that all SCC members use our Dockerized compositions of Specify 7.

:incoming_envelope: Click here to request access, including your GitHub username, member institution, collection, and any additional questions or notes you have for us.

There already exists similar documentation regarding self hosting Specify 7. If desired, see the Installation Instructions on the Specify 7 GitHub, Specify 7 Installation Instructions, Install Specify 7 With Docker (from Matthew Cruz of the University of Michigan), the Developer Wiki for general information regarding the architecture of Specify 7, Docker Workflow for Development on the Developer Wiki regarding setting up an environment specifically for development.

Getting Started

We recommend using Docker to host Specify 7 (as well as hosting the Report Runner and Web Asset Server services). Docker allows each service to be “containerized” or in other words, generally isolated from the host computer. This means each container is in charge of its dependencies and only Docker is required to be installed for each containerized service.

For the Specify database, it must be updated to or created with Specify 6.8.03 (latest release). Databases created or used with previous versions of Specify 6 are incompatible with Specify 7.

Service and Architecture Overview

Because Specify 7 is a webservice, there are a number of separate services or components which act and communicate together to provide the entire Specify suite of functionality.

You can learn more about the software architecture in the following topic:

Recommended Server Specifications

Specify 7 Components

Specify 7

Code Source: https://github.com/specify/specify7
Container Images: https://hub.docker.com/r/specifyconsortium/specify7-service/tags

The primary frontend and backend of the Specify 7 application. Specifically, it contains a Django web framework for processing web requests. Once the initial server-provided web-page is loaded, rendering is handled client-side via React and React Router.
Traditionally, the Web Server Gateway Interface (WSGI) Gunicorn is used to forward web-server requests to Django.

At runtime, Django configuration settings for the Specify installation are read from the specifyweb/settings/__init__.py file. This file generally expects the user-configured settings to be present within a local_specify_settings.py file in the same directory. Possible user-configurable variables can be found within the specify_settings.py file.
For local non-containerized installations, this file is copied and renamed to local_specify_settings.py (see Adjusting Settings Files).

[!tip]
If you are looking for how to install Specify 7 via Docker, skip ahead to Specify 7 Example Docker Compose Configurations.

When building Specify 7 using the provided Dockerfile or when using any of the built images hosted on Docker Hub (https://hub.docker.com/r/specifyconsortium/specify7-service/tags), these user-configurable variables are read from the container environment variables and copied into local_specify_settings.py.

Example commands to start the Specify 7 Service:

# Apply the initial Specify migration if not already applied
ve/bin/python manage.py base_specify_migration
# Apply any normal migrations
ve/bin/python manage.py migrate
# Start the WSGI Server + Django
ve/bin/gunicorn -w 3 -b 0.0.0.0:8000 -t 300 specifyweb_wsgi

See Dockerfile#L225, docker-entrypoint.sh, and specifyweb.wsgi.

When using a built image from the Specify 7 Image repository, these commands are executed automatically on container startup.

Specify 7 Worker

Potentially computationally expensive, asynchronous, or otherwise slow operations in the main Specify application are commonly passed to a separate task queue (traditionally Celery), through a message broker (commonly Redis).

Redis Container Images: https://hub.docker.com/_/redis

Architecturally, the Specify 7 Worker is usually identical to the primary Specify 7 service.

The Celery worker can be started from the Specify 7 Worker instance via the following command (which is commonly included within a compose file for the Specify 7 Worker service) :

command: bash -c "ve/bin/celery -A specifyweb worker -l INFO --concurrency=1"

For more information regarding using Celery from the command line, view the Celery documentation at https://docs.celeryq.dev/en/latest/userguide/workers.html.

Additional information regarding Celery and Django (including the CELERY_BROKER_URL and CELERY_RESULT_BACKEND variables) can be found at: celery/docs/django/first-steps-with-django.rst at main

Specify 7 and Worker Configuration

Supported Customization / Environment Variables

Variable Name Description Default / Example Value
DATABASE_HOST Hostname or IP of the server hosting the database localhost
DATABASE_PORT The port number of the database application 3306
DATABASE_NAME The name of the database to connect to within the database application SpecifyDB
MASTER_NAME The username of the database user which the Specify application will act as MasterUser
MASTER_PASSWORD The password of the database user which the Specify application will act as MasterPassword
SECRET_KEY An unpredictable, unique key that Django uses for cryptographic signing. See Django’s SECRET_KEY
ASSET_SERVER_URL The complete url to the web_asset_store.xml of the Attachment Server service http://host.docker.internal/web_asset_store.xml
ASSET_SERVER_KEY The configured ATTACHMENT_KEY of the Attachment Server service
REPORT_RUNNER_HOST The hostname or IP of the Report Runner service report-runner
REPORT_RUNNER_PORT The port number of the report runner application 8080
CELERY_BROKER_URL The URL of the message broker celery will use to send and receive messages. See Celery’s broker_url redis://localhost/0
CELERY_RESULT_BACKEND The backend used to store task results. See Celery’s result_backend redis://localhost/1
LOG_LEVEL The logging level mask for the Specify 7 backend. All logging statements for levels below WARNING (possible values: DEBUG, INFO, WARNING, ERROR, CRITICAL)
SP7_DEBUG Whether Django is run in DEBUG mode. See Django’s DEBUG true (or false)
SPECIFY_CONFIG_DIR A file path to a Specify 6 config directory containing Specify-specific configuration files. See https://github.com/specify/specify6/tree/master/config
ALLOWED_HOSTS A comma-separated list of hosts and/or domains that Specify can serve to. * denotes all hosts, and a period can be used as a wildcard to match against subdomains. See Django’s ALLOWED_HOSTS *,localhost,.specifycloud.org
CSRF_TRUSTED_ORIGINS A comma-separated list of trusted origins for unsafe requests that can create, modify, or delete data (POST, PUT, DELETE, etc.). * can be used a wildcard to match against subdomains. The scheme (http://, https://) MUST be included in each origin. See Django’s CSRF_TRUSTED_ORIGINS http://*,https://*,https://*.specifycloud.org
ANONYMOUS_USER You can provide the name of a specify user for anonymous access to the instance. This user will have all of the permissions given to that user, so make sure to configure this carefully. Documentation. GuestUser
TIME_ZONE The time zone for the Specify instance used on the backend can be any from the list of TZ identifiers. This is used for fetching notifications, timestamps, and more. America/Chicago

Security

[!warning]
The provided Specify 7 defaults should not be considered secure. The section below outlines some security-related variables and their use within the application. Before setting up a production-ready environment, review each variable and modify it if needed

SECRET_KEY

Source: Django | Settings | SECRET_KEY

The SECRET_KEY is used internally by Django and Specify to verify and manage Sessions, manage and store OAuthLogin (SSO) information within the session, and for Cryptographic Signing of data.

The value of the SECRET_KEY should be changed from the default and kept secret. As stated by Django in the SECRET_KEY documentation:

[!caution] Keep this value secret

Running Django with a known SECRET_KEY defeats many of Django’s security protections, and can lead to privilege escalation and remote code execution vulnerabilities.

ALLOWED_HOSTS

Source: Django | Settings | ALLOWED_HOSTS
Default: *

As an environment variable, Specify expects ALLOWED_HOSTS to be a comma-separated list of host and/or domain names.

The list of host and/or domain names are the servers that Specify (through Django) is able to serve. Any host which is not present in this list which attempts to utilize Specify will receive a 400 Bad Request and not be able to access the requested resource.

Configuring this setting to a limited number of hosts you know will access Specify will achieve Host header validation, and aim to prevent Host header attacks.

Values in the list can be fully qualified domain names (like www.example.com) or a portion of a domain name beginning with a period (like .example.com).
Values beginning with a period are treated as subdomain wildcards.
So .example.com would match any subdomain of example.com: www.example.com, test.example.com, etc.).
The special value * can be provided to allow all hosts.

:warning: The default ALLOWED_HOSTS - * - is insecure and allows all hosts to connect with the Specify instance.
Before deploying Specify in a production environment, modify this setting to the host or list of hosts that are expected to utilize the Specify instance.

CSRF_TRUSTED_ORIGINS

Source: Django | Settings | CSRF_TRUSTED_ORIGINS
Default: http://*, https://*

As an environment variable, Specify expects CSRF_TRUSTED_ORIGINS to be a comma-separated list of domain names (which must include the scheme of either http or https).

Values in the list represent trusted domains from which unsafe requests can originate. An unsafe request is one that create, modify, or delete data (POST, PUT, and DELETE requests). Similarly to ALLOWED_HOSTS, if an unsafe request originates from a domain that is not present in the CSRF_TRUSTED_ORIGINS, then it will be rejected with a CSRF Verification failed response.

:warning: The default CSRF_TRUSTED_ORIGINS - http://*, https://* - is insecure and trusts all hosts for sending unsafe requests.
Before deploying Specify in a production environment, modify this setting to the domain or list of domains that are expected to send unsafe requests.

MariaDB (Database)

The MariaDB service provides the database for Specify 7. By default, MariaDB listens on port 3306. At this time, there are no other supported database management systems available for Specify 7. This can both be managed in a Docker container and managed externally.

Supported Customization / Environment Variables

Variable Name Description Default Value
MYSQL_ROOT_PASSWORD Password for the MariaDB root superuser. root
MYSQL_DATABASE Name of the default database to create on startup. specify
MYSQL_USER Name of a non-root user to create and grant privileges on the default database. master
MYSQL_PASSWORD Password for the non-root user specified by MYSQL_USER. master

Additionally, command line options for starting the database application are commonly included within compose files:

command: --max_allowed_packet=1073741824

Attachment Server

Source Code: https://github.com/specify/web-asset-server
Docker Hub (Includes available Images): https://hub.docker.com/r/specifyconsortium/specify-asset-service
Documentation: https://discourse.specifysoftware.org/t/web-asset-server-attachment-server/657

This is our official attachment server implementation for Specify. This implementation is targeted at Ubuntu flavors, but will work with minor modifications on other Linux systems.

Supported Customization / Environment Variables

Variable Name Description Default Value
SERVER_NAME The hostname or IP (and optional path) at which the asset server is publicly accessible.
SERVER_PORT The TCP port on which the server listens for incoming HTTP requests. 80
ATTACHMENT_KEY A shared secret key used to authenticate requests between the Specify 7 service and the asset server service.
DEBUG_MODE Enable verbose logging and error output. Set to true for development, false for production. false

Report Runner

Source Code: https://github.com/specify/report-runner-service
Docker Hub (Includes available Images): https://hub.docker.com/r/specifyconsortium/report-runner

The Specify Report Runner is a simple web service wrapper around the Jasper Reports libraries for report and label generation in Specify 7. It generates reports for Specify 7 via a REST endpoint.

Supported Customization / Environment Variables

Variable Name Description Default Value
REPORT_RUNNER_HOST Hostname or IP address (container name or network alias) where the report-runner service is reachable. report-runner
REPORT_RUNNER_PORT TCP port on which the report-runner service listens. 8080
LOG_LEVEL Minimum log level for the report-runner process (DEBUG, INFO, WARNING, ERROR, or CRITICAL). INFO
SP7_DEBUG Enable debug mode in integrated components (affects verbose output). false

Web Server / Reverse Proxy

Docker Hub (Includes available Images): https://hub.docker.com/_/nginx

We recommend and commonly utilize NGINX as a webserver and reverse proxy.
As a reverse proxy, it’s important to forward requests meant for the asset server (see the routes in web-asset-server/server.py#L212-361) to the correct hostname and port, as well as serving static files directly to the requesting client. All other requests can be forwarded to the main Specify 7 service.

Simple example NGINX configuration for Specify 7:
See docker-compositions/all-in-one/nginx/specify.conf or specify7/nginx.conf

Example Docker Compose Configurations

Below are three example compositions for self-hosting Specify 7. Each scenario is available in our member-exclusive GitHub repository.

:incoming_envelope: Click here to request access, including your GitHub username, member institution, collection, and any additional questions or notes you have for us.

Clone the repo, pick the directory matching your needs, adjust environment variables, then start the containers.


1. All-in-One

Use case: Single-host evaluation or small deployments where you want every service bundled: database, Specify 7, asset server, report runner, and web server.

Key steps:

  1. Seed database:
    • Place your Specify 6 SQL dump (no CREATE DATABASE/USE statements) into seed-database/.
    • Ensure the dump originates from a preconfigured Specify 6 instance (with at least one collection, discipline, division, and institution).

  2. Configure .env or docker-compose.yml:
    SEED_DB_FILE – filename in seed-database/
    MYSQL_ROOT_PASSWORD – MariaDB root password
    MYSQL_USER / MYSQL_PASSWORD – non-root Specify 7 user credentials
    SPECIFY_ASSET_DIR – in-container mount point for attachments volume
    REPORT_RUNNER_ENABLEDtrue or false

  3. Launch:

docker-compose up -d

Reference: all-in-one/docker-compose.yml


2. Just Specify 7

Use case: You already have a production Specify 6 (MySQL/MariaDB + asset server). You only want the new Specify 7 front-end and its web server.

Services included:

  1. specify7-service (Specify 7 application)
  2. nginx (proxy + static file server)
  3. report-runner (optional; for labels & reports)

Configuration steps:

  1. In docker-compose.yml, set:
    DATABASE_HOST, DATABASE_NAME, MASTER_NAME, MASTER_PASSWORD – point to your existing MariaDB
    ASSET_SERVER_URL / ASSET_SERVER_KEY – match your asset server
    REPORT_RUNNER_HOST / REPORT_RUNNER_PORT (if enabled)
  2. Comment out the report-runner service if you don’t need reporting.
  3. Start services:
docker-compose up -d

Reference: just-specify/docker-compose.yml


3. Multiple Databases

Use case: Host multiple, distinct Specify 7 databases on one host via name-based virtual hosting.

How it works:

  • Define one Specify 7 service per database in docker-compose.yml.
  • Allocate a dedicated Docker volume (for static files) to each instance.
  • In Nginx’s specify.conf, create multiple server blocks—each with its own server_name and upstream to the matching Specify 7 container.

Setup steps:

  1. Duplicate the Specify 7 service block (-db1, -db2, …) and assign unique environment variables and volumes.
  2. Update nginx/specify.conf:
server {
  listen 80;
  server_name specify-db1.example.com;
  location / {
    proxy_pass http://specify7-db1:8000;
  }
  …
}
server {
  listen 80;
  server_name specify-db2.example.com;
  location / {
    proxy_pass http://specify7-db2:8000;
  }
  …
}
  1. Launch all services:
docker-compose up -d

Reference:


Updating Specify 7

1 Like