# Standalone module deployments — each module runs as its own container. # # Usage: # docker compose -f docker-compose.yml -f docker-compose.standalone.yml up -d rbooks-standalone # # All services reuse the same rspace-online image (built by the main compose). # They share the rspace-db database and traefik-public network. # To deploy ALL standalone modules at once: # docker compose -f docker-compose.yml -f docker-compose.standalone.yml up -d # # NOTE: Standalone services override the default CMD to run standalone.ts. # The unified rspace-online container still serves all domains by default. # To switch a domain from unified to standalone, remove its Traefik label # from the main compose and bring up its standalone service here. x-standalone-base: &standalone-base image: rspace-online-rspace:latest restart: unless-stopped environment: &base-env NODE_ENV: production PORT: "3000" DATABASE_URL: postgres://rspace:${POSTGRES_PASSWORD:-rspace}@rspace-db:5432/rspace depends_on: rspace-db: condition: service_healthy networks: - traefik-public - rspace-internal x-traefik-labels: &traefik-enabled traefik.enable: "true" services: # ── rBooks ── rbooks-standalone: <<: *standalone-base container_name: rbooks-standalone command: ["bun", "run", "modules/books/standalone.ts"] volumes: - rspace-books:/data/books environment: <<: *base-env BOOKS_DIR: /data/books labels: <<: *traefik-enabled traefik.http.routers.rbooks-sa.rule: Host(`rbooks.online`) traefik.http.routers.rbooks-sa.entrypoints: web traefik.http.services.rbooks-sa.loadbalancer.server.port: "3000" # ── rPubs ── rpubs-standalone: <<: *standalone-base container_name: rpubs-standalone command: ["bun", "run", "modules/pubs/standalone.ts"] labels: <<: *traefik-enabled traefik.http.routers.rpubs-sa.rule: Host(`rpubs.online`) traefik.http.routers.rpubs-sa.entrypoints: web traefik.http.services.rpubs-sa.loadbalancer.server.port: "3000" # ── rCart ── rcart-standalone: <<: *standalone-base container_name: rcart-standalone command: ["bun", "run", "modules/cart/standalone.ts"] environment: <<: *base-env FLOW_SERVICE_URL: http://payment-flow:3010 FLOW_ID: a79144ec-e6a2-4e30-a42a-6d8237a5953d FUNNEL_ID: 0ff6a9ac-1667-4fc7-9a01-b1620810509f X402_PAY_TO: ${X402_PAY_TO:-} X402_NETWORK: ${X402_NETWORK:-eip155:84532} X402_UPLOAD_PRICE: ${X402_UPLOAD_PRICE:-0.01} X402_FACILITATOR_URL: ${X402_FACILITATOR_URL:-https://x402.org/facilitator} networks: - traefik-public - rspace-internal - payment-network labels: <<: *traefik-enabled traefik.http.routers.rcart-sa.rule: Host(`rcart.online`) traefik.http.routers.rcart-sa.entrypoints: web traefik.http.services.rcart-sa.loadbalancer.server.port: "3000" # ── rProviders ── rproviders-standalone: <<: *standalone-base container_name: rproviders-standalone command: ["bun", "run", "modules/providers/standalone.ts"] labels: <<: *traefik-enabled traefik.http.routers.rproviders-sa.rule: Host(`providers.mycofi.earth`) traefik.http.routers.rproviders-sa.entrypoints: web traefik.http.services.rproviders-sa.loadbalancer.server.port: "3000" # ── rSwag ── rswag-standalone: <<: *standalone-base container_name: rswag-standalone command: ["bun", "run", "modules/swag/standalone.ts"] volumes: - rspace-swag:/data/swag-artifacts environment: <<: *base-env SWAG_ARTIFACTS_DIR: /data/swag-artifacts labels: <<: *traefik-enabled traefik.http.routers.rswag-sa.rule: Host(`swag.mycofi.earth`) traefik.http.routers.rswag-sa.entrypoints: web traefik.http.services.rswag-sa.loadbalancer.server.port: "3000" # ── rChoices ── rchoices-standalone: <<: *standalone-base container_name: rchoices-standalone command: ["bun", "run", "modules/choices/standalone.ts"] labels: <<: *traefik-enabled traefik.http.routers.rchoices-sa.rule: Host(`rchoices.online`) traefik.http.routers.rchoices-sa.entrypoints: web traefik.http.services.rchoices-sa.loadbalancer.server.port: "3000" # ── rFunds ── rfunds-standalone: <<: *standalone-base container_name: rfunds-standalone command: ["bun", "run", "modules/funds/standalone.ts"] environment: <<: *base-env FLOW_SERVICE_URL: http://payment-flow:3010 FLOW_ID: a79144ec-e6a2-4e30-a42a-6d8237a5953d FUNNEL_ID: 0ff6a9ac-1667-4fc7-9a01-b1620810509f networks: - traefik-public - rspace-internal - payment-network labels: <<: *traefik-enabled traefik.http.routers.rfunds-sa.rule: Host(`rfunds.online`) traefik.http.routers.rfunds-sa.entrypoints: web traefik.http.services.rfunds-sa.loadbalancer.server.port: "3000" # ── rFiles ── rfiles-standalone: <<: *standalone-base container_name: rfiles-standalone command: ["bun", "run", "modules/files/standalone.ts"] volumes: - rspace-files:/data/files environment: <<: *base-env FILES_DIR: /data/files labels: <<: *traefik-enabled traefik.http.routers.rfiles-sa.rule: Host(`rfiles.online`) traefik.http.routers.rfiles-sa.entrypoints: web traefik.http.services.rfiles-sa.loadbalancer.server.port: "3000" # ── rForum ── rforum-standalone: <<: *standalone-base container_name: rforum-standalone command: ["bun", "run", "modules/forum/standalone.ts"] environment: <<: *base-env HETZNER_API_TOKEN: ${HETZNER_API_TOKEN} CLOUDFLARE_API_TOKEN: ${CLOUDFLARE_API_TOKEN} CLOUDFLARE_ZONE_ID: ${CLOUDFLARE_ZONE_ID} labels: <<: *traefik-enabled traefik.http.routers.rforum-sa.rule: Host(`rforum.online`) traefik.http.routers.rforum-sa.entrypoints: web traefik.http.services.rforum-sa.loadbalancer.server.port: "3000" # ── rVote ── rvote-standalone: <<: *standalone-base container_name: rvote-standalone command: ["bun", "run", "modules/vote/standalone.ts"] labels: <<: *traefik-enabled traefik.http.routers.rvote-sa.rule: Host(`rvote.online`) traefik.http.routers.rvote-sa.entrypoints: web traefik.http.services.rvote-sa.loadbalancer.server.port: "3000" # ── rNotes ── rnotes-standalone: <<: *standalone-base container_name: rnotes-standalone command: ["bun", "run", "modules/notes/standalone.ts"] labels: <<: *traefik-enabled traefik.http.routers.rnotes-sa.rule: Host(`rnotes.online`) traefik.http.routers.rnotes-sa.entrypoints: web traefik.http.services.rnotes-sa.loadbalancer.server.port: "3000" # ── rMaps ── rmaps-standalone: <<: *standalone-base container_name: rmaps-standalone command: ["bun", "run", "modules/maps/standalone.ts"] environment: <<: *base-env MAPS_SYNC_URL: wss://sync.rmaps.online labels: <<: *traefik-enabled traefik.http.routers.rmaps-sa.rule: Host(`rmaps.online`) traefik.http.routers.rmaps-sa.entrypoints: web traefik.http.services.rmaps-sa.loadbalancer.server.port: "3000" # ── rWork ── rwork-standalone: <<: *standalone-base container_name: rwork-standalone command: ["bun", "run", "modules/work/standalone.ts"] labels: <<: *traefik-enabled traefik.http.routers.rwork-sa.rule: Host(`rwork.online`) traefik.http.routers.rwork-sa.entrypoints: web traefik.http.services.rwork-sa.loadbalancer.server.port: "3000" # ── rTrips ── rtrips-standalone: <<: *standalone-base container_name: rtrips-standalone command: ["bun", "run", "modules/trips/standalone.ts"] environment: <<: *base-env OSRM_URL: http://osrm-backend:5000 labels: <<: *traefik-enabled traefik.http.routers.rtrips-sa.rule: Host(`rtrips.online`) traefik.http.routers.rtrips-sa.entrypoints: web traefik.http.services.rtrips-sa.loadbalancer.server.port: "3000" # ── rCal ── rcal-standalone: <<: *standalone-base container_name: rcal-standalone command: ["bun", "run", "modules/cal/standalone.ts"] labels: <<: *traefik-enabled traefik.http.routers.rcal-sa.rule: Host(`rcal.online`) traefik.http.routers.rcal-sa.entrypoints: web traefik.http.services.rcal-sa.loadbalancer.server.port: "3000" # ── rNetwork ── rnetwork-standalone: <<: *standalone-base container_name: rnetwork-standalone command: ["bun", "run", "modules/network/standalone.ts"] environment: <<: *base-env TWENTY_API_URL: https://rnetwork.online TWENTY_API_TOKEN: ${TWENTY_API_TOKEN} labels: <<: *traefik-enabled traefik.http.routers.rnetwork-sa.rule: Host(`rnetwork.online`) traefik.http.routers.rnetwork-sa.entrypoints: web traefik.http.services.rnetwork-sa.loadbalancer.server.port: "3000" # ── rTube ── rtube-standalone: <<: *standalone-base container_name: rtube-standalone command: ["bun", "run", "modules/tube/standalone.ts"] environment: <<: *base-env R2_ENDPOINT: ${R2_ENDPOINT} R2_BUCKET: ${R2_BUCKET:-rtube-videos} R2_ACCESS_KEY_ID: ${R2_ACCESS_KEY_ID} R2_SECRET_ACCESS_KEY: ${R2_SECRET_ACCESS_KEY} R2_PUBLIC_URL: ${R2_PUBLIC_URL} labels: <<: *traefik-enabled traefik.http.routers.rtube-sa.rule: Host(`rtube.online`) traefik.http.routers.rtube-sa.entrypoints: web traefik.http.services.rtube-sa.loadbalancer.server.port: "3000" # ── rInbox ── rinbox-standalone: <<: *standalone-base container_name: rinbox-standalone command: ["bun", "run", "modules/inbox/standalone.ts"] environment: <<: *base-env IMAP_HOST: mail.rmail.online IMAP_PORT: "993" IMAP_TLS_REJECT_UNAUTHORIZED: "false" networks: - traefik-public - rspace-internal - rmail-mailcow labels: <<: *traefik-enabled traefik.http.routers.rinbox-sa.rule: Host(`rinbox.online`) traefik.http.routers.rinbox-sa.entrypoints: web traefik.http.services.rinbox-sa.loadbalancer.server.port: "3000" # ── rData ── rdata-standalone: <<: *standalone-base container_name: rdata-standalone command: ["bun", "run", "modules/data/standalone.ts"] environment: <<: *base-env UMAMI_URL: https://analytics.rspace.online UMAMI_WEBSITE_ID: 292f6ac6-79f8-497b-ba6a-7a51e3b87b9f labels: <<: *traefik-enabled traefik.http.routers.rdata-sa.rule: Host(`rdata.online`) traefik.http.routers.rdata-sa.entrypoints: web traefik.http.services.rdata-sa.loadbalancer.server.port: "3000" # ── rWallet ── rwallet-standalone: <<: *standalone-base container_name: rwallet-standalone command: ["bun", "run", "modules/wallet/standalone.ts"] labels: <<: *traefik-enabled traefik.http.routers.rwallet-sa.rule: Host(`rwallet.online`) traefik.http.routers.rwallet-sa.entrypoints: web traefik.http.services.rwallet-sa.loadbalancer.server.port: "3000" # Volumes and networks inherited from main docker-compose.yml # Use: docker compose -f docker-compose.yml -f docker-compose.standalone.yml up -d