Compare commits

..
5 Commits
Author SHA1 Message Date
raucao 2093f67a64 Merge pull request 'Allow remote access to dev services' (#253) from dev/remote_access into chore/docker-compose-setup
CI / Test (pull_request) Successful in 45s
Reviewed-on: #253
2026-10-06 17:37:49 +00:00
raucao 695977172f Fix Liquor Cabinet performance in dev
CI / Test (pull_request) Failing after 46s
Can't handle enough requests without ThreadPool, so once you hit the
limit, requests take 5s+ (having to wait for the keepalive timeout)
2026-10-06 19:36:26 +02:00
raucao bc37df52a0 Allow remote access to dev services
CI / Test (pull_request) Successful in 46s
Release Drafter / Update release notes draft (pull_request) Successful in 19s
2026-10-06 19:34:24 +02:00
raucao 6279699c11 Switch dev object storage from MinIO to Garage
CI / Test (pull_request) Successful in 43s
MinIO no longer publishes prebuilt community images (quay.io returns
401, Docker Hub 404), so the dev setup cannot pull the image.

Use a single-node Garage instance instead, which auto-creates the
remotestorage bucket and a dev-key1 access key on first start, and
point liquor-cabinet at it.
2026-10-06 13:52:38 +00:00
raucao 0d9c580a0a Automate first-run LDAP and database setup
The documented flow started web (with Solid Queue in Puma) before the
databases existed, and required manually creating the 389ds back-end
and seeding the LDAP directory and databases. Automate it:

- add an ldap-init one-shot service that creates the 389ds back-end if
  it does not exist
- add a web entrypoint that seeds LDAP and the databases on first start,
  and runs db:prepare on later boots
- update README and AGENTS accordingly, including the reset steps
2026-10-06 13:52:38 +00:00
9 changed files with 160 additions and 47 deletions

No files matched your search

+7 -4
View File
@@ -7,13 +7,16 @@ ejabberd, Discourse, Mastodon, remoteStorage, Nostr, LNDHub, and BTCPay.
## Development environment
Development runs in Docker Compose — run all commands against the `web` container.
Start services: `docker compose up` (web, ldap, redis, minio, liquor-cabinet, strfry).
Start services: `docker compose up` (web, ldap, redis, garage, liquor-cabinet, strfry).
The `web` service runs `bin/dev` (foreman: Puma + Tailwind CSS watcher) and embeds
Solid Queue workers (`SOLID_QUEUE_IN_PUMA=true`).
First-time LDAP setup (after creating the 389ds backend once):
`docker compose exec ldap dsconf localhost backend create --suffix="dc=kosmos,dc=org" --be_name="dev"`
then `docker compose run web bin/rails ldap:setup`.
First-time LDAP and database setup is automated: the `ldap-init` service
creates the 389ds back-end, then the `web` entrypoint seeds LDAP and the
databases on first start and runs `db:prepare` on every boot. Manual
equivalents: `docker compose exec ldap dsconf localhost backend create
--suffix="dc=kosmos,dc=org" --be-name="dev"` and `docker compose run --rm web
bin/rails ldap:setup`.
## Common commands (prefix with `docker compose exec web`)
+44 -24
View File
@@ -14,13 +14,14 @@ so:
1. Make sure [Docker Compose is installed][1] and Docker is running (included in
Docker Desktop)
3. Run `docker compose up --build` and wait until all services have started
2. Run `docker compose up --build` and wait until all services have started
(389ds might take an extra minute to be ready). This will take a while when
running for the first time, so you might want to do something else in the
meantime.
4. `docker-compose exec ldap dsconf localhost backend create --suffix="dc=kosmos,dc=org" --be-name="dev"`
5. `docker compose run web rails ldap:setup`
6. `docker compose run web rails db:setup`
On the first start, the `ldap-init` service creates the 389ds back-end, and the
`web` container then seeds the LDAP directory and the databases automatically.
On every start, `web` also applies any pending database migrations.
After these steps, you should have a working Rails app with a handful of test
users running on [http://localhost:3000](http://localhost:3000).
@@ -71,15 +72,12 @@ containers you want to run to the `up` command, like so:
#### LDAP server
After creating the Docker container for the first time (or after deleting it),
you need to run the following command once, in order to create the dirsrv
back-end:
On first start, the `ldap-init` service creates the dirsrv back-end
automatically, and the `web` container then seeds it with development entries.
To do either step manually (for example, after changing the setup), run:
docker-compose exec ldap dsconf localhost backend create --suffix="dc=kosmos,dc=org" --be-name="dev"
Now you can seed the back-end with data using this Rails task:
bundle exec rails ldap:setup
docker compose exec ldap dsconf localhost backend create --suffix="dc=kosmos,dc=org" --be-name="dev"
docker compose run --rm web bin/rails ldap:setup
The setup task will first delete any existing entries in the directory tree
("dc=kosmos,dc=org"), and then create our development entries.
@@ -88,20 +86,42 @@ Note that all 389ds data is stored in the `389ds-data` volume. So if you want
to start over with a fresh installation, delete both that volume as well as the
container.
#### Minio / remoteStorage
To reset the development environment completely, remove all volumes plus the
generated database files and the first-run marker, then start over:
If you want to run remoteStorage accounts locally, you will have to create the
respective bucket first. With the `minio` container running (run by default
when using Docker Compose), follow these steps:
docker compose down -v
rm -f db/*.sqlite3 tmp/.setup-complete
docker compose up --build
* `docker compose up web redis minio liquor-cabinet`
* Head to http://localhost:9001 and log in with user `minioadmin`, password
`minioadmin`
* Create a new bucket called `remotestorage` (or whatever you
change the `S3_BUCKET` config to)
* Create a new key with ID "dev-key" and secret "123456789" (or whatever you
change `S3_ACCESS_KEY` and `S3_SECRET_KEY` to). Leave the policy field empty,
as it will automatically allow access to the bucket you created.
#### Garage / remoteStorage
remoteStorage accounts use the `garage` S3-compatible object store. On first
start, Garage automatically configures a single-node cluster and creates the
`remotestorage` bucket together with a `dev-key1` access key (secret
`1234567890123456`), so no manual setup is required.
If you want to run remoteStorage accounts locally, the `garage` container is
started by default when using Docker Compose. To run just the remoteStorage
stack:
* `docker compose up web redis garage liquor-cabinet`
The S3 API is available at http://localhost:3900 (region `garage`). If you want
to start over with a fresh storage, delete the `garage-data` volume as well as
the container.
#### Accessing remoteStorage from another machine
remoteStorage clients force HTTPS for any host except `localhost`, and browsers
block plain-HTTP requests to a LAN IP as mixed content. To connect to the dev
remoteStorage from a browser on another machine (including production apps such
as Inspektor), forward the ports over SSH and connect as `localhost`:
ssh -N -L 3000:localhost:3000 -L 4567:localhost:4567 <user>@<dev-host>
Then use `<user>@localhost:3000` as the remoteStorage address in the client.
WeFinger discovery and storage requests are served through the forwarded ports,
so no TLS setup is needed.
### Adding npm modules to use with Stimulus controllers
@@ -22,9 +22,12 @@ class Services::RsAuthsController < Services::BaseController
end
def launch_app
user_address = Rails.env.development? ?
"#{current_user.cn}@localhost:3000" :
current_user.address
user_address =
if Rails.env.development?
"#{current_user.cn}@#{request.host_with_port}"
else
current_user.address
end
launch_url = "#{@auth.launch_url}#remotestorage=#{user_address}"
+16 -2
View File
@@ -88,8 +88,14 @@ class WebfingerController < WellKnownController
end
def remotestorage_link
auth_url = new_rs_oauth_url(@username, host: Setting.rs_accounts_domain)
storage_url = "#{Setting.rs_storage_url}/#{@username}"
auth_url =
if Rails.env.development?
new_rs_oauth_url(@username)
else
new_rs_oauth_url(@username, host: Setting.rs_accounts_domain)
end
storage_url = "#{remotestorage_storage_base_url}/#{@username}"
{
rel: "http://tools.ietf.org/id/draft-dejong-remotestorage",
@@ -103,4 +109,12 @@ class WebfingerController < WellKnownController
}
}
end
def remotestorage_storage_base_url
return Setting.rs_storage_url unless Rails.env.development?
uri = URI.parse(Setting.rs_storage_url)
uri.host = request.host
uri.to_s
end
end
+40 -14
View File
@@ -12,6 +12,20 @@ services:
DS_DM_PASSWORD: passthebutter
SUFFIX_NAME: "dc=kosmos,dc=org"
ldap-init:
image: 4teamwork/389ds:latest
networks:
- internal_network
volumes:
- ./docker/ldap-init.sh:/ldap-init.sh:ro
environment:
LDAP_ADMIN_PASSWORD: passthebutter
LDAP_SUFFIX: "dc=kosmos,dc=org"
depends_on:
ldap:
condition: service_healthy
command: ["/bin/sh", "/ldap-init.sh"]
redis:
restart: always
image: redis:7-alpine
@@ -26,7 +40,7 @@ services:
web:
build: .
tty: true
command: bash -c "rm -f /akkounts/tmp/pids/server.pid; bin/dev"
command: ["bash", "docker/web-entrypoint.sh"]
volumes:
- .:/akkounts
- /akkounts/node_modules
@@ -57,20 +71,28 @@ services:
NOSTR_PRIVATE_KEY: 7c3ef7e448505f0615137af38569d01807d3b05b5005d5ecf8aaafcd40323cea
NOSTR_RELAY_URL: ws://strfry:7777
depends_on:
- ldap
- redis
ldap:
condition: service_started
ldap-init:
condition: service_completed_successfully
redis:
condition: service_started
minio:
image: quay.io/minio/minio:latest
command: "server /data --console-address ':9001'"
garage:
image: dxflrs/garage:v2.4.1
command: ["/garage", "server", "--single-node", "--default-bucket"]
networks:
- external_network
- internal_network
ports:
- "9000:9000"
- "9001:9001"
- "3900:3900"
volumes:
- minio-data:/data
- ./docker/garage/garage.toml:/etc/garage.toml:ro
- garage-data:/var/lib/garage
environment:
GARAGE_DEFAULT_ACCESS_KEY: dev-key1
GARAGE_DEFAULT_SECRET_KEY: "1234567890123456"
GARAGE_DEFAULT_BUCKET: remotestorage
liquor-cabinet:
image: gitea.kosmos.org/5apps/liquor-cabinet:2.0.0-rc.1
@@ -79,17 +101,21 @@ services:
- internal_network
ports:
- "4567:4567"
volumes:
- ./docker/liquor-cabinet/rainbows.conf.rb:/etc/liquor-cabinet/rainbows.conf.rb:ro
command: ["bundle", "exec", "rainbows", "-c", "/etc/liquor-cabinet/rainbows.conf.rb", "--listen", "0.0.0.0:4567"]
environment:
RACK_ENV: staging
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_DB: 1
S3_ENDPOINT: http://minio:9000
S3_ACCESS_KEY: dev-key
S3_SECRET_KEY: 123456789
S3_ENDPOINT: http://garage:3900
S3_REGION: garage
S3_ACCESS_KEY: dev-key1
S3_SECRET_KEY: "1234567890123456"
S3_BUCKET: remotestorage
depends_on:
- minio
- garage
- redis
strfry:
@@ -127,7 +153,7 @@ networks:
volumes:
389ds-data:
driver: local
minio-data:
garage-data:
driver: local
redis-data:
driver: local
+14
View File
@@ -0,0 +1,14 @@
metadata_dir = "/var/lib/garage/meta"
data_dir = "/var/lib/garage/data"
db_engine = "sqlite"
replication_factor = 1
rpc_bind_addr = "[::]:3901"
rpc_public_addr = "127.0.0.1:3901"
rpc_secret = "1799bccfd7411eddcf9ebd316bc1f5287ad12a68094e1c6ac6abde7e6feae1ec"
[s3_api]
s3_region = "garage"
api_bind_addr = "[::]:3900"
root_domain = ".s3.garage.localhost"
+14
View File
@@ -0,0 +1,14 @@
#!/bin/sh
set -e
SUFFIX="${LDAP_SUFFIX:-dc=kosmos,dc=org}"
URI="ldap://ldap:3389"
if dsconf -D "cn=Directory Manager" -w "$LDAP_ADMIN_PASSWORD" "$URI" \
backend suffix list --suffix 2>/dev/null | grep -Fqx "$SUFFIX"; then
echo "LDAP backend for $SUFFIX already exists, skipping."
else
echo "Creating LDAP backend for $SUFFIX..."
dsconf -D "cn=Directory Manager" -w "$LDAP_ADMIN_PASSWORD" "$URI" \
backend create --suffix "$SUFFIX" --be-name dev
fi
+5
View File
@@ -0,0 +1,5 @@
Rainbows! do
use :ThreadPool
worker_connections 16
client_max_body_size 100 * 1024 * 1024
end
+14
View File
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -e
if [ ! -f tmp/.setup-complete ]; then
echo "First start: setting up LDAP entries and databases..."
bin/rails ldap:setup
bin/rails db:setup
touch tmp/.setup-complete
else
bin/rails db:prepare
fi
rm -f tmp/pids/server.pid
exec bin/dev