Stop the SQLite volume from hiding new migrations
Uploads on share.kadenpartner.ch failed with 409 on every chunk after the update to 2.1. The example docker-compose.yml mounts the SQLite volume over all of /app/database. Docker fills a volume from the image only when it is created, so the container kept the 2.0 migrations and never saw the 2.1 one. share_files.uploaded_chunks was never created, so the chunk endpoint read null and answered 409. SQLite takes the unknown "completed_at" in whereNull() as a string, so nothing failed earlier. - The image keeps a copy of its migrations in docker/migrations. On startup the entrypoint adds the ones missing from database/migrations before migrating, so installs with the old mount recover by pulling the new image. - docker-compose.example.yml and docker-compose.yml mount sealshare_database at /app/database/sqlite and set DB_DATABASE to the file in it. An existing volume can be moved there without losing data: its database.sqlite lands at exactly that path. - Tested with a locally built image: a volume created by 2.0.1 with the old mount gets the migration once (not again on restart) and keeps its settings; the same volume moved to the new path keeps its data; a fresh volume with the new layout starts healthy. - README and CHANGELOG (Unreleased) describe the new path and how to switch. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
7ffc1c1ead
commit
c1906d2009
@@ -5,6 +5,16 @@ All notable changes to this project are documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Docker installs updated from 2.0 answered every upload with "409 Conflict". The example `docker-compose.yml` mounted the SQLite volume over all of `/app/database`, which hid the image's new migration, so it never ran. The container now adds the migrations the volume is missing before migrating, so existing compose files keep working.
|
||||
|
||||
### Changed
|
||||
|
||||
- `docker-compose.example.yml` mounts `sealshare_database` at `/app/database/sqlite` and sets `DB_DATABASE` to the file in it. To switch an existing install, mount the same volume there and set `DB_DATABASE: /app/database/sqlite/database.sqlite` in both services; the database is kept.
|
||||
|
||||
## [2.1.0] - 2026-09-16
|
||||
|
||||
### Added
|
||||
|
||||
+5
-1
@@ -88,9 +88,13 @@ RUN rm -rf node_modules tests .gitea docker/dev.Dockerfile docker/dev-entrypoint
|
||||
bootstrap/cache/*.php \
|
||||
&& mkdir -p storage/app/shares storage/app/public storage/framework/cache \
|
||||
storage/framework/sessions storage/framework/testing storage/framework/views \
|
||||
storage/logs database \
|
||||
storage/logs database/sqlite \
|
||||
&& chmod -R 777 storage database bootstrap/cache
|
||||
|
||||
# A docker-compose.yml from before 2.1.1 mounts the SQLite volume over all of database/, which hides
|
||||
# the migrations of every later image; the entrypoint adds the ones the volume is missing from here.
|
||||
RUN cp -R database/migrations docker/migrations
|
||||
|
||||
# Create SQLite database file if it doesn't exist
|
||||
RUN touch database/database.sqlite \
|
||||
&& chmod 666 database/database.sqlite
|
||||
|
||||
@@ -99,10 +99,12 @@ Migrations run automatically on startup. Open your configured domain — the Set
|
||||
| Volume | Path | Purpose |
|
||||
|--------|------|---------|
|
||||
| `sealshare_storage` | `/app/storage/app` | Encrypted uploaded files |
|
||||
| `sealshare_database` | `/app/database` | SQLite database |
|
||||
| `sealshare_database` | `/app/database/sqlite` | SQLite database (`DB_DATABASE: /app/database/sqlite/database.sqlite`) |
|
||||
| `caddy_data` | `/data` | TLS certificates |
|
||||
| `caddy_config` | `/config` | Caddy configuration |
|
||||
|
||||
A `docker-compose.yml` from before 2.1.1 mounts `sealshare_database` at `/app/database`, which also hides the image's migrations; the container adds the ones the volume is missing on startup, so it keeps working. To move to the layout above, mount the same volume at `/app/database/sqlite` and set `DB_DATABASE: /app/database/sqlite/database.sqlite` in both services — the existing database is at that path then, and nothing is lost.
|
||||
|
||||
**Large files:**
|
||||
|
||||
Files go up in chunks of `UPLOAD_CHUNK_SIZE_MB`, one request each, so PHP's upload limits and a proxy's request timeout do not limit a file's size. What does:
|
||||
|
||||
@@ -26,13 +26,14 @@ services:
|
||||
- "443:443/udp" # HTTP/3 (QUIC)
|
||||
volumes:
|
||||
- sealshare_storage:/app/storage/app # Uploaded & encrypted files
|
||||
- sealshare_database:/app/database # SQLite database
|
||||
- sealshare_database:/app/database/sqlite # SQLite database
|
||||
- caddy_data:/data # TLS certificates
|
||||
- caddy_config:/config # Caddy configuration
|
||||
environment:
|
||||
# --- REQUIRED ---
|
||||
APP_URL: # Your full URL, e.g. https://share.example.com
|
||||
# APP_KEY: # Auto-generated if not set. Copy from logs to persist across restarts.
|
||||
DB_DATABASE: /app/database/sqlite/database.sqlite # The SQLite file in sealshare_database
|
||||
|
||||
# --- HTTPS ---
|
||||
# Files are encrypted in the uploader's browser, which browsers only allow over HTTPS (or on
|
||||
@@ -51,7 +52,7 @@ services:
|
||||
# DB_CONNECTION: sqlite # Options: sqlite, mysql, pgsql
|
||||
# DB_HOST: # Required for mysql/pgsql
|
||||
# DB_PORT: # Required for mysql/pgsql
|
||||
# DB_DATABASE: # Required for mysql/pgsql
|
||||
# DB_DATABASE: # For mysql/pgsql the database's name, in place of the SQLite file above
|
||||
# DB_USERNAME: # Required for mysql/pgsql
|
||||
# DB_PASSWORD: # Required for mysql/pgsql
|
||||
|
||||
@@ -84,10 +85,11 @@ services:
|
||||
entrypoint: ["php", "artisan", "schedule:work"]
|
||||
volumes:
|
||||
- sealshare_storage:/app/storage/app
|
||||
- sealshare_database:/app/database
|
||||
- sealshare_database:/app/database/sqlite
|
||||
environment:
|
||||
# APP_KEY: # Same key as the app service above (auto-generated if not set)
|
||||
APP_URL: # Same URL as the app service above
|
||||
DB_DATABASE: /app/database/sqlite/database.sqlite # Same as the app service above
|
||||
depends_on:
|
||||
app:
|
||||
condition: service_healthy
|
||||
|
||||
+4
-4
@@ -11,7 +11,7 @@ services:
|
||||
- "443:443/udp"
|
||||
volumes:
|
||||
- sealshare_storage:/app/storage/app
|
||||
- sealshare_database:/app/database
|
||||
- sealshare_database:/app/database/sqlite
|
||||
- caddy_data:/data
|
||||
- caddy_config:/config
|
||||
environment:
|
||||
@@ -24,7 +24,7 @@ services:
|
||||
DB_CONNECTION: ${DB_CONNECTION:-sqlite}
|
||||
DB_HOST: ${DB_HOST:-}
|
||||
DB_PORT: ${DB_PORT:-}
|
||||
DB_DATABASE: ${DB_DATABASE:-/app/database/database.sqlite}
|
||||
DB_DATABASE: ${DB_DATABASE:-/app/database/sqlite/database.sqlite}
|
||||
DB_USERNAME: ${DB_USERNAME:-}
|
||||
DB_PASSWORD: ${DB_PASSWORD:-}
|
||||
LOG_CHANNEL: ${LOG_CHANNEL:-stderr}
|
||||
@@ -56,7 +56,7 @@ services:
|
||||
entrypoint: ["php", "artisan", "schedule:work"]
|
||||
volumes:
|
||||
- sealshare_storage:/app/storage/app
|
||||
- sealshare_database:/app/database
|
||||
- sealshare_database:/app/database/sqlite
|
||||
environment:
|
||||
APP_KEY: ${APP_KEY:?Set APP_KEY in .env or environment}
|
||||
APP_URL: ${APP_URL:-http://localhost}
|
||||
@@ -65,7 +65,7 @@ services:
|
||||
DB_CONNECTION: ${DB_CONNECTION:-sqlite}
|
||||
DB_HOST: ${DB_HOST:-}
|
||||
DB_PORT: ${DB_PORT:-}
|
||||
DB_DATABASE: ${DB_DATABASE:-/app/database/database.sqlite}
|
||||
DB_DATABASE: ${DB_DATABASE:-/app/database/sqlite/database.sqlite}
|
||||
DB_USERNAME: ${DB_USERNAME:-}
|
||||
DB_PASSWORD: ${DB_PASSWORD:-}
|
||||
LOG_CHANNEL: ${LOG_CHANNEL:-stderr}
|
||||
|
||||
@@ -22,6 +22,16 @@ max_input_time = ${PHP_MAX_INPUT_TIME:-300}
|
||||
memory_limit = ${PHP_MEMORY_LIMIT:-512M}
|
||||
EOF
|
||||
|
||||
# A docker-compose.yml from before 2.1.1 mounts the SQLite volume over all of /app/database, so the
|
||||
# migrations folder is the one the volume was created with: add this image's newer migrations to it.
|
||||
for migration in docker/migrations/*.php; do
|
||||
if [ ! -e "database/migrations/${migration##*/}" ]; then
|
||||
echo "[entrypoint] Adding migration ${migration##*/} to the database volume..."
|
||||
mkdir -p database/migrations
|
||||
cp "$migration" database/migrations/
|
||||
fi
|
||||
done
|
||||
|
||||
echo "[entrypoint] Running database migrations..."
|
||||
php artisan migrate --force
|
||||
|
||||
|
||||
Reference in New Issue
Block a user