Installation¶
Make sure you meet the requirements first.
1. Get the code¶
git clone https://github.com/LundDarkLab/adc.git
cd adc
2. Configure¶
Create your .env from the template and fill in your values:
cp .env.example .env
nano .env
The file is fully commented; in short you must set:
- the database credentials (
DB_USER,DB_PASSWORD,DB_NAME,DB_ROOT_PASSWORD) β the MySQL container is initialised with these values on its first start; - the SMTP parameters (
MAIL*) used for registration and password-reset emails.
Values with special characters
Wrap passwords containing !, $, #, & or spaces in single quotes: DB_PASSWORD='my&secret!'.
3. Build and start¶
Two equivalent options:
A β Build from source (default):
docker compose up -d --build
B β Prebuilt image from the GitHub Container Registry, if you don't need to modify the code:
docker compose -f docker-compose.ghcr.yml up -d
This pulls ghcr.io/lunddarklab/adc instead of building locally β faster, and updates are a docker compose -f docker-compose.ghcr.yml pull && docker compose -f docker-compose.ghcr.yml up -d away. Everything else (configuration, database initialisation, storage) is identical.
On the first start the MySQL container imports every .sql / .sql.gz file found in db-init/, in alphabetical order:
| File | Content |
|---|---|
00-schema.sql |
Database schema and views |
01-seed-data.sql |
Base data: controlled vocabularies, time series, licenses |
02-first-admin.sql |
The default administrator account |
This happens only once, while the database volume is empty.
Check that everything is up:
docker compose ps # web "running", db "running (healthy)"
docker compose logs -f db # follow the first import
The application now answers on http://127.0.0.1:8081.
4. Import the geographic dataset (recommended)¶
The find-site forms and the map rely on the administrative boundaries published by GADM (country β province β district β municipality). They are not bundled with the platform β the GADM license allows free academic and non-commercial use but not redistribution β so each installation downloads them directly from the source, only for the countries it actually needs.
With the stack running, import one or more countries by their ISO 3166-1 alpha-3 code:
./scripts/import-gadm.sh SWE # Sweden
./scripts/import-gadm.sh NOR DNK FIN # add more countries at any time
For each country the script downloads the official GeoPackage from gadm.org and loads every administrative level into the gadm0β¦gadm5 tables with ogr2ogr, run from the official GDAL Docker image β no local GDAL installation required. Re-running the script with new codes appends to the existing data.
Note
The first run pulls the GDAL image (~1.5 GB, one-time). The platform works without the geographic dataset, but the find-site selectors and the geographic layers of the map stay empty until you import at least one country.
Manual import (what the script does under the hood)
Each administrative level N is a layer named ADM_ADM_N in the GADM GeoPackage, loaded into the corresponding gadmN table:
bash
curl -fLO https://geodata.ucdavis.edu/gadm/gadm4.1/gpkg/gadm41_SWE.gpkg
ogr2ogr -f MySQL "MYSQL:dbname,host=127.0.0.1,port=3306,user=...,password=..." \
gadm41_SWE.gpkg ADM_ADM_1 \
-nln gadm1 -append -update -relaxedFieldNameMatch
The target tables already exist (created by 00-schema.sql) with SRID 4326 geometry columns, so any import method that respects their structure works.
5. First login¶
Log in with the default administrator account:
- email:
admin@example.com - password:
changeme
Change the password immediately (Settings β Manage your data profile), then update the account's name and email β or create your real administrator account and disable the default one.
Initial configuration¶
Most controlled vocabularies ship pre-filled (materials, conservation states, licenses, user rolesβ¦), but the ones that depend on the scientific scope of your institution ship empty on purpose and must be filled by an administrator before contributors start creating records:
| What | Where to fill it | Needed for |
|---|---|---|
| Category class and Category specification | Vocabularies page | Classifying artefacts |
| At least one timeline, with its macro / generic / specific periods | Timeline page | The chronological definition of artefacts and the timeline browsing |
Optionally, the cultural_generic_period table feeds the chronological-distribution chart; it has no editing interface yet and can be populated directly in the database if you want that chart.
Re-running the initialisation
The db-init/ files are applied only to an empty database volume. If the first import fails midway (or you want to start over), wipe the volume with docker compose down -v β this deletes all data β and run docker compose up -d again.
6. Reverse proxy and HTTPS¶
The web container is bound to the loopback interface on purpose: public traffic should arrive through a reverse proxy on the host, which owns the domain and terminates TLS.
Apache¶
<VirtualHost *:443>
ServerName collections.example.org
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/collections.example.org/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/collections.example.org/privkey.pem
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:8081/
ProxyPassReverse / http://127.0.0.1:8081/
# Uploads of 3D models can be large
LimitRequestBody 0
</VirtualHost>
Required modules: a2enmod proxy proxy_http ssl headers.
nginx¶
server {
listen 443 ssl;
server_name collections.example.org;
ssl_certificate /etc/letsencrypt/live/collections.example.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/collections.example.org/privkey.pem;
client_max_body_size 0; # uploads of 3D models can be large
location / {
proxy_pass http://127.0.0.1:8081;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Obtain the certificates with certbot.
Local test without a proxy
For a quick test you can open http://localhost:8081 directly, or temporarily change the port mapping in docker-compose.yml from 127.0.0.1:8081:80 to 8081:80 to reach the instance from other machines on the network. Do not run a public production instance without TLS.
7. Storage directories¶
Uploaded content is stored outside the container: archive/ (models, images, documents β the repository already contains the required folder skeleton) and img/ (logos and icons), both mounted into the web container. By default they are the folders of the repository itself; to keep the data elsewhere on the server, set ARCHIVE_DIR and IMG_DIR in .env:
ARCHIVE_DIR=/srv/dyncoll/archive
IMG_DIR=/srv/dyncoll/img
The container entrypoint automatically aligns file-ownership UIDs between the host directories and the Apache user.
Development setup¶
For local development, create a docker-compose.override.yml (ignored by git) that mounts the source code into the container, so changes are visible without rebuilding:
services:
web:
volumes:
- .:/var/www/html
- ./archive:/var/www/html/archive
- ./img:/var/www/html/img
Compose picks the override up automatically with docker compose up.
Next: Architecture Β· Maintenance