Spyglass requires a MySQL database backend for storing experimental data and analysis results. This guide covers all setup options from quick local development to production deployments.
The easiest way to set up a database is using the installer with Docker Compose:
cd spyglass
python scripts/install.py
# Choose "Docker" option when prompted for database setupThis automatically:
- Pulls the DataJoint MySQL 8.0 Docker image
- Creates and starts a container named
spyglass-db - Waits for MySQL to be ready
- Creates configuration file with credentials
Or use Docker Compose directly:
cd spyglass
docker compose up -dPros:
- One-command setup (~2 minutes)
- Version controlled
- Easy to customize via .env file
- Industry-standard tool
- Persistent data storage
- Health checks built-in
Cons:
- Requires Docker Desktop with Compose plugin
- Uses system resources when running
-
Start Docker Desktop and ensure it's running
-
Verify Compose is available:
docker compose --version # Should show: Docker Compose version ##.##.##
Using installer (recommended):
python scripts/install.py --docker # Will auto-detect and use compose commandUsing Docker Compose directly:
# From spyglass repository root
docker compose up -dThe default configuration uses:
- Port: 3306
- Password: tutorial
- Container name: spyglass-db
- Persistent storage: spyglass-db-data volume
Create a .env file to customize settings:
# Copy and edit example
cp example.env .env
nano .env # or use your favorite editorAvailable options:
# Change port if 3306 is in use
MYSQL_PORT=3307
# Change root password (for production)
MYSQL_ROOT_PASSWORD=your-secure-password
# Use different MySQL version
MYSQL_IMAGE=datajoint/mysql:8.0.18Important: If you change port or password, update your DataJoint config accordingly. You can either edit this file directly, or run the following in your python environment.
dj.config.save_global()Start/stop services:
# Start
docker compose up -d
# Stop (keeps data)
docker compose stop
# Stop and remove containers (keeps data)
docker compose down
# Stop and remove everything including data
docker compose down -v # WARNING: Deletes all data!View logs:
docker compose logs mysql
docker compose logs -f mysql # Follow modeCheck status:
docker compose psAccess MySQL shell:
docker compose exec mysql mysql -uroot -pThis will securely prompt you for a password. For test cases, you can directly
append the password (e.g., -ptutorial).
Restart services:
docker compose restartPros:
- Shared across team members
- Production-ready
- Professional backup/monitoring
- Persistent storage
Cons:
- Requires existing MySQL server
- Network configuration needed
- May need VPN/SSH tunnel
- MySQL 8.0+ server accessible over network
- Database credentials (host, port, user, password)
- Firewall rules allowing connection
Using installer (interactive):
python scripts/install.py --remote
# Enter connection details when promptedUsing installer (non-interactive for automation):
# Using CLI arguments
python scripts/install.py --remote \
--db-host db.mylab.edu \
--db-user myusername \
--db-password mypassword
# Using environment variables (recommended for CI/CD)
export SPYGLASS_DB_PASSWORD=mypassword
python scripts/install.py --remote \
--db-host db.mylab.edu \
--db-user myusernameManual configuration:
Create ~/.datajoint_config.json:
{
"database.host": "db.mylab.edu",
"database.port": 3306,
"database.user": "myusername",
"database.password": "mypassword",
"database.use_tls": true
}Test connection:
import datajoint as dj
dj.conn().ping() # Should succeedIf the database is behind firewall, use SSH tunnel:
# Create tunnel (keep running in terminal)
ssh -L 3306:localhost:3306 user@remote-server
# In separate terminal, configure as localhost
cat > ~/.datajoint_config.json << EOF
{
"database.host": "localhost",
"database.port": 3306,
"database.user": "root",
"database.password": "password",
"database.use_tls": false
}
EOFOr use autossh for persistent tunnel:
autossh -M 0 -L 3306:localhost:3306 user@remote-serverPros:
- No Docker required
- Direct system integration
- Full control over configuration
Cons:
- More complex setup
- Platform-specific installation
- Harder to reset/clean
# Install MySQL
brew install mysql
# Start MySQL service
brew services start mysql
# Secure installation
mysql_secure_installation
# Create user
mysql -uroot -pIn MySQL shell:
CREATE USER 'spyglass'@'localhost' IDENTIFIED BY 'spyglass_password';
GRANT ALL PRIVILEGES ON *.* TO 'spyglass'@'localhost';
FLUSH PRIVILEGES;
EXIT;Configure DataJoint:
{
"database.host": "localhost",
"database.port": 3306,
"database.user": "spyglass",
"database.password": "spyglass_password",
"database.use_tls": false
}# Install MySQL
sudo apt-get update
sudo apt-get install mysql-server
# Start service
sudo systemctl start mysql
sudo systemctl enable mysql
# Secure installation
sudo mysql_secure_installation
# Create user
sudo mysqlIn MySQL shell:
CREATE USER 'spyglass'@'localhost' IDENTIFIED BY 'spyglass_password';
GRANT ALL PRIVILEGES ON *.* TO 'spyglass'@'localhost';
FLUSH PRIVILEGES;
EXIT;- Download MySQL Installer: https://dev.mysql.com/downloads/installer/
- Run installer and select "Developer Default"
- Follow setup wizard
- Create spyglass user with full privileges
Location: ~/.datajoint_config.json
Full configuration example:
{
"database.host": "localhost",
"database.port": 3306,
"database.user": "root",
"database.password": "tutorial",
"database.use_tls": false,
"database.charset": "utf8mb4",
"connection.init_function": null,
"loglevel": "INFO",
"safemode": true,
"fetch_format": "array"
}Key settings:
database.host: MySQL server hostname or IPdatabase.port: MySQL port (default: 3306)database.user: MySQL usernamedatabase.password: MySQL passworddatabase.use_tls: Use TLS/SSL encryption (recommended for remote)
When to use TLS:
- ✅ Remote database connections
- ✅ Production environments
- ✅ When connecting over untrusted networks
- ❌ localhost connections
- ❌ Docker containers on same machine
Enable TLS:
{
"database.use_tls": true
}Custom certificate:
{
"database.use_tls": {
"ssl": {
"ca": "/path/to/ca-cert.pem",
"cert": "/path/to/client-cert.pem",
"key": "/path/to/client-key.pem"
}
}
}For local development, simple credentials are acceptable:
- User:
rootor dedicated user - Password: Simple but unique
- TLS: Disabled for localhost
For shared/production databases:
-
Strong passwords:
# Generate secure password openssl rand -base64 32 -
User permissions: Manage by database prefix
-- Create user with specific database access CREATE USER 'spyglass'@'%' IDENTIFIED BY 'strong_password'; GRANT ALL PRIVILEGES ON someprefix_*.* TO 'spyglass'@'%'; FLUSH PRIVILEGES;
-
Enable TLS:
{ "database.use_tls": true } -
Network security:
- Use firewall rules
- Consider VPN for remote access
- Use SSH tunnels when appropriate
-
Credential management:
- Never commit config files to git
- Use environment variables for CI/CD (e.g., GitHub Actions)
- Consider secrets management tools
Protect configuration file by only allowing read/write access by you:
chmod 600 ~/.datajoint_config.jsonFor lab environments with shared database:
-- Create database prefix for lab
CREATE DATABASE yourlab_common;
-- Create users
CREATE USER 'alice'@'%' IDENTIFIED BY 'alice_password';
CREATE USER 'bob'@'%' IDENTIFIED BY 'bob_password';
-- Grant permissions
GRANT ALL PRIVILEGES ON yourlab_*.* TO 'alice'@'%';
GRANT ALL PRIVILEGES ON yourlab_*.* TO 'bob'@'%';
FLUSH PRIVILEGES;Each user creates their own config:
Alice's config:
{
"database.host": "lab-db.university.edu",
"database.user": "alice",
"database.password": "alice_password",
"database.use_tls": true
}Bob's config:
{
"database.host": "lab-db.university.edu",
"database.user": "bob",
"database.password": "bob_password",
"database.use_tls": true
}Check MySQL is running:
# Docker
docker ps | grep spyglass-db
# System service (Linux)
systemctl status mysql
# Homebrew (macOS)
brew services list | grep mysqlTest connection:
# With mysql client
mysql -h HOST -P PORT -u USER -p
# With Python
python -c "import datajoint as dj; dj.conn().ping()"Grant additional privileges to a given user in mysql:
GRANT ALL PRIVILEGES ON *.* TO 'user'@'host';
FLUSH PRIVILEGES;# Find what's using port 3306
lsof -i :3306
netstat -an | grep 3306
# Use different port
docker run -p 3307:3306 ...
# Update config with port 3307# Disable TLS for localhost
config = {"database.host": "localhost", "database.use_tls": False}For more troubleshooting help, see TROUBLESHOOTING.md.
=== Docer database
```bash
# Backup
docker exec spyglass-db mysqldump -uroot -ptutorial --all-databases > backup.sql
# Restore
docker exec -i spyglass-db mysql -uroot -ptutorial < backup.sql
```
=== System MySQL
```bash
# Backup
mysqldump -u USER -p --all-databases > backup.sql
# Restore
mysql -u USER -p < backup.sql
```
### Performance Tuning
**Increase buffer pool (Docker):**
```bash
docker run -d \
--name spyglass-db \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=tutorial \
datajoint/mysql:8.0 \
--innodb-buffer-pool-size=2G
Optimize tables:
OPTIMIZE TABLE tablename;Moving from Docker to Remote:
- Backup Docker database
- Restore to remote server
- Update config to point to remote
- Test connection
Example:
# Backup from Docker
docker exec spyglass-db mysqldump -uroot -ptutorial --all-databases > backup.sql
# Restore to remote
mysql -h remote-host -u user -p < backup.sql
# Update config
cat > ~/.datajoint_config.json << EOF
{
"database.host": "remote-host",
"database.user": "user",
"database.password": "password",
"database.use_tls": true
}
EOF- Issues: https://github.com/LorenFrankLab/spyglass/issues
- Docs: See main Spyglass documentation
- DataJoint: https://docs.datajoint.org/