feat: devcontainers

This commit is contained in:
Min Idzelis 2025-05-01 04:11:18 +00:00
parent da7a81b752
commit eddf85ee2b
24 changed files with 620 additions and 64 deletions

View File

@ -1,2 +0,0 @@
.env
library

View File

@ -1,16 +0,0 @@
ARG BASEIMAGE=mcr.microsoft.com/devcontainers/typescript-node:22@sha256:a20b8a3538313487ac9266875bbf733e544c1aa2091df2bb99ab592a6d4f7399
FROM ${BASEIMAGE}
# Flutter SDK
# https://flutter.dev/docs/development/tools/sdk/releases?tab=linux
ENV FLUTTER_CHANNEL="stable"
ENV FLUTTER_VERSION="3.29.1"
ENV FLUTTER_HOME=/flutter
ENV PATH=${PATH}:${FLUTTER_HOME}/bin
# Flutter SDK
RUN mkdir -p ${FLUTTER_HOME} \
&& curl -C - --output flutter.tar.xz https://storage.googleapis.com/flutter_infra_release/releases/${FLUTTER_CHANNEL}/linux/flutter_linux_${FLUTTER_VERSION}-${FLUTTER_CHANNEL}.tar.xz \
&& tar -xf flutter.tar.xz --strip-components=1 -C ${FLUTTER_HOME} \
&& rm flutter.tar.xz \
&& chown -R 1000:1000 ${FLUTTER_HOME}

View File

@ -1,26 +1,66 @@
{
"name": "Immich",
"service": "immich-devcontainer",
"dockerComposeFile": [
"docker-compose.yml",
"../docker/docker-compose.dev.yml"
],
"name": "Immich - Backend and Frontend",
"service": "immich-devcontainer-server",
"dockerComposeFile": ["server/docker-compose.yml"],
"customizations": {
"vscode": {
"extensions": [
"Dart-Code.dart-code",
"Dart-Code.flutter",
"dbaeumer.vscode-eslint",
"dcmdev.dcm-vscode-extension",
"esbenp.prettier-vscode",
"svelte.svelte-vscode"
"svelte.svelte-vscode",
"ms-vscode-remote.remote-containers",
"foxundermoon.shell-format",
"timonwong.shellcheck",
"rvest.vs-code-prettier-eslint",
"bluebrown.yamlfmt",
"vkrishna04.cspell-sync",
"vitest.explorer",
"ms-playwright.playwright"
]
}
},
"forwardPorts": [],
"initializeCommand": "bash .devcontainer/scripts/initializeCommand.sh",
"onCreateCommand": "bash .devcontainer/scripts/onCreateCommand.sh",
"forwardPorts": [3000, 9231, 9230, 2283],
"portsAttributes": {
"3000": {
"label": "Immich - Frontend HTTP",
"description": "The frontend of the Immich project",
"onAutoForward": "openBrowserOnce"
},
"2283": {
"label": "Immich - API Server - HTTP",
"description": "The API server of the Immich project"
},
"9231": {
"label": "Immich - API Server - DEBUG",
"description": "The API server of the Immich project"
},
"9230": {
"label": "Immich - Workers - DEBUG",
"description": "The workers of the Immich project"
}
},
"overrideCommand": true,
"workspaceFolder": "/immich",
"remoteUser": "node"
"workspaceFolder": "/workspaces/immich",
"remoteUser": "node",
"postCreateCommand": "/immich-devcontainer/postCreate.sh",
"userEnvProbe": "loginInteractiveShell",
"remoteEnv": {
// The location where your uploaded files are stored
// If this starts with / or ./, it is a bind mount to a path
// on host. Otherwise, it must be the value "vol-upload"
// which is also the default loaded from .env.
"UPLOAD_LOCATION": "${localEnv:UPLOAD_LOCATION}",
// The location where your database files are stored.
// If this starts with / or ./, it is a bind mount to a path
// on host. Otherwise, it must be the value "vol-database"
// which is also the default loaded from .env.
"DB_DATA_LOCATION": "${localEnv:DB_DATA_LOCATION}",
// Connection secret for postgres. You should change it to a random password
// Please use only the characters `A-Za-z0-9`, without special characters or spaces
"DB_PASSWORD": "${localEnv:DB_PASSWORD}",
// The database username
"DB_USERNAME": "${localEnv:DB_USERNAME}",
// The database name
"DB_DATABASE_NAME": "${localEnv:DB_DATABASE_NAME}"
}
}

19
.devcontainer/ml/.env Normal file
View File

@ -0,0 +1,19 @@
# You can find documentation for all the supported env variables at https://immich.app/docs/install/environment-variables
# The location where your uploaded files are stored
UPLOAD_LOCATION=upload-volume
# The location where your database files are stored
DB_DATA_LOCATION=db-volume
# To set a timezone, uncomment the next line and change Etc/UTC to a TZ identifier from this list: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List
# TZ=Etc/UTC
# Connection secret for postgres. You should change it to a random password
# Please use only the characters `A-Za-z0-9`, without special characters or spaces
DB_PASSWORD=postgres
# The values below this line do not need to be changed
###################################################################################
DB_USERNAME=postgres
DB_DATABASE_NAME=immich

View File

@ -0,0 +1,17 @@
{
"name": "Immich - Machine Learning",
"service": "immich-machine-learning",
"dockerComposeFile": ["docker-compose.yml"],
"customizations": {
"vscode": {
"extensions": [
"ms-python.python","ms-python.debugpy","KevinRose.vsc-python-indent"
]
}
},
"forwardPorts": [],
"overrideCommand": true,
"workspaceFolder": "/workspaces/immich",
"remoteUser": "node"
}

View File

@ -0,0 +1,15 @@
services:
immich-machine-learning:
image: immich-machine-learning-dev:latest
build:
context: ../../machine-learning
dockerfile: Dockerfile
target: devcontainer
hostname: immich-machine-learning
volumes:
# bind mount host to /workspaces/immich
- ../..:/workspaces/immich
- model-cache:/cache
volumes:
model-cache:

19
.devcontainer/mobile/.env Normal file
View File

@ -0,0 +1,19 @@
# You can find documentation for all the supported env variables at https://immich.app/docs/install/environment-variables
# The location where your uploaded files are stored
UPLOAD_LOCATION=upload-volume
# The location where your database files are stored
DB_DATA_LOCATION=db-volume
# To set a timezone, uncomment the next line and change Etc/UTC to a TZ identifier from this list: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List
# TZ=Etc/UTC
# Connection secret for postgres. You should change it to a random password
# Please use only the characters `A-Za-z0-9`, without special characters or spaces
DB_PASSWORD=postgres
# The values below this line do not need to be changed
###################################################################################
DB_USERNAME=postgres
DB_DATABASE_NAME=immich

View File

@ -0,0 +1,31 @@
ARG BASEIMAGE=ghcr.io/immich-app/base-server-dev:202503182202@sha256:45ae044b64a7b518f8d94fa4de718090c1c7689d516ac2ac0976a5331eaeb396
FROM ${BASEIMAGE} AS dev
# Flutter SDK
# https://flutter.dev/docs/development/tools/sdk/releases?tab=linux
ENV FLUTTER_CHANNEL="stable"
ENV FLUTTER_VERSION="3.29.2"
ENV FLUTTER_HOME=/flutter
ENV PATH=${PATH}:${FLUTTER_HOME}/bin
RUN apt-get install inetutils-ping sudo
RUN usermod -aG sudo node
RUN echo "node ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
RUN mkdir -p /workspaces/immich
RUN chown node -R /workspaces
# Flutter SDK
RUN mkdir -p ${FLUTTER_HOME} \
&& curl -C - --output flutter.tar.xz https://storage.googleapis.com/flutter_infra_release/releases/${FLUTTER_CHANNEL}/linux/flutter_linux_${FLUTTER_VERSION}-${FLUTTER_CHANNEL}.tar.xz \
&& tar -xf flutter.tar.xz --strip-components=1 -C ${FLUTTER_HOME} \
&& rm flutter.tar.xz \
&& chown -R node ${FLUTTER_HOME}
USER node
RUN sudo apt-get update \
&& wget -qO- https://dcm.dev/pgp-key.public | sudo gpg --dearmor -o /usr/share/keyrings/dcm.gpg \
&& echo 'deb [signed-by=/usr/share/keyrings/dcm.gpg arch=amd64] https://dcm.dev/debian stable main' | sudo tee /etc/apt/sources.list.d/dart_stable.list \
&& sudo apt-get update \
&& sudo apt-get install dcm -y
RUN dart --disable-analytics

View File

@ -0,0 +1,20 @@
{
"name": "Immich - Mobile",
"service": "immich-mobile",
"dockerComposeFile": ["docker-compose.yml"],
"customizations": {
"vscode": {
"extensions": [
"Dart-Code.dart-code",
"Dart-Code.flutter",
"dcmdev.dcm-vscode-extension",
"esbenp.prettier-vscode"
]
}
},
"forwardPorts": [],
"overrideCommand": true,
"workspaceFolder": "/workspaces/immich",
"remoteUser": "node",
"postCreateCommand": "/workspaces/immich/.devcontainer/mobile/postCreate.sh"
}

View File

@ -0,0 +1,27 @@
services:
immich-mobile:
build:
dockerfile: Dockerfile
hostname: immich-devcontainer-mobile
extra_hosts:
- 'host.docker.internal:host-gateway'
volumes:
# by default, bind mount host to /workspaces/immich
- ../..:/workspaces/immich
- ./vscode:/workspaces/immich/.vscode
- cli_node_modules:/workspaces/immich/cli/node_modules
- e2e_node_modules:/workspaces/immich/e2e/node_modules
- open_api_node_modules:/workspaces/immich/open-api/typescript-sdk/node_modules
- server_node_modules:/workspaces/immich/server/node_modules
- web_node_modules:/workspaces/immich/web/node_modules
- ${UPLOAD_LOCATION}:/workspaces/immich/server/upload
volumes:
cli_node_modules:
e2e_node_modules:
open_api_node_modules:
server_node_modules:
web_node_modules:
immich:
upload-volume:
db-volume:

View File

@ -0,0 +1,33 @@
#!/bin/bash
# Enable multiarch for arm64 if necessary
if [ "$(dpkg --print-architecture)" = "arm64" ]; then
sudo dpkg --add-architecture amd64 &&
sudo apt-get update &&
sudo apt-get install -y --no-install-recommends \
qemu-user-static \
libc6:amd64 \
libstdc++6:amd64 \
libgcc1:amd64
fi
dart --disable-analytics
export IMMICH_PORT="${DEV_SERVER_PORT:-2283}"
export DEV_PORT="${DEV_PORT:-3000}"
sudo chown node -R /workspaces/immich/.vscode \
/workspaces/immich/cli/node_modules \
/workspaces/immich/e2e/node_modules \
/workspaces/immich/open-api/typescript-sdk/node_modules \
/workspaces/immich/server/node_modules \
/workspaces/immich/web/node_modules \
/workspaces/immich/server/upload
echo "Installing dependencies (server)"
npm --prefix /workspaces/immich/server install
echo "Installing dependencies (web)"
npm --prefix /workspaces/immich/open-api/typescript-sdk install
npm --prefix /workspaces/immich/open-api/typescript-sdk run build
npm --prefix /workspaces/immich/web install

View File

@ -1,6 +0,0 @@
#!/bin/bash
# If .env file does not exist, create it by copying example.env from the docker folder
if [ ! -f ".devcontainer/.env" ]; then
cp docker/example.env .devcontainer/.env
fi

View File

@ -1,25 +0,0 @@
#!/bin/bash
# Enable multiarch for arm64 if necessary
if [ "$(dpkg --print-architecture)" = "arm64" ]; then
sudo dpkg --add-architecture amd64 && \
sudo apt-get update && \
sudo apt-get install -y --no-install-recommends \
qemu-user-static \
libc6:amd64 \
libstdc++6:amd64 \
libgcc1:amd64
fi
# Install DCM
wget -qO- https://dcm.dev/pgp-key.public | sudo gpg --dearmor -o /usr/share/keyrings/dcm.gpg
sudo echo 'deb [signed-by=/usr/share/keyrings/dcm.gpg arch=amd64] https://dcm.dev/debian stable main' | sudo tee /etc/apt/sources.list.d/dart_stable.list
sudo apt-get update
sudo apt-get install dcm
dart --disable-analytics
# Install immich
cd /immich || exit
make install-all

14
.devcontainer/server/.env Normal file
View File

@ -0,0 +1,14 @@
# You can find documentation for all the supported env variables at https://immich.app/docs/install/environment-variables
# The location where your uploaded files are stored
UPLOAD_LOCATION=vol-upload
# The location where your db files are stored
DB_DATA_LOCATION=vol-database
# Connection secret for postgres. You should change it to a random password
DB_PASSWORD=postgres
# The values below this line do not need to be changed
DB_USERNAME=postgres
DB_DATABASE_NAME=immich

View File

@ -0,0 +1,16 @@
ARG BASEIMAGE=ghcr.io/immich-app/base-server-dev:202503182202@sha256:45ae044b64a7b518f8d94fa4de718090c1c7689d516ac2ac0976a5331eaeb396
FROM ${BASEIMAGE} AS dev
RUN apt-get install inetutils-ping sudo -y
RUN usermod -aG sudo node
RUN echo "node ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
RUN mkdir -p /workspaces/immich
RUN chown node -R /workspaces
RUN mkdir /immich-devcontainer && chown node -R /immich-devcontainer
COPY --chmod=777 ./.devcontainer/server/common.sh /immich-devcontainer/common.sh
COPY --chmod=777 ./.devcontainer/server/postCreate.sh /immich-devcontainer/postCreate.sh
COPY --chmod=777 ./.devcontainer/server/startNestApiServer.sh /immich-devcontainer/startNestApiServer.sh
COPY --chmod=777 ./.devcontainer/server/startViteWebServer.sh /immich-devcontainer/startViteWebServer.sh

23
.devcontainer/server/common.sh Executable file
View File

@ -0,0 +1,23 @@
#!/bin/bash
export IMMICH_PORT="${DEV_SERVER_PORT:-2283}"
export DEV_PORT="${DEV_PORT:-3000}"
# search for immich directory inside workspace.
# /workspaces/immich is the bind mount, but other directories can be mounted if runing
# Devcontainer: Clone [repository|pull request] in container volumne
WORKSPACES_DIR="/workspaces"
IMMICH_DIR="$WORKSPACES_DIR/immich"
# Find directories excluding /workspaces/immich
mapfile -t other_dirs < <(find "$WORKSPACES_DIR" -mindepth 1 -maxdepth 1 -type d ! -path "$IMMICH_DIR" ! -name ".*")
if [ ${#other_dirs[@]} -gt 1 ]; then
echo "Error: More than one directory found in $WORKSPACES_DIR other than $IMMICH_DIR."
exit 1
elif [ ${#other_dirs[@]} -eq 1 ]; then
export IMMICH_WORKSPACE="${other_dirs[0]}"
else
export IMMICH_WORKSPACE="$IMMICH_DIR"
fi
echo "Found immich workspace in $IMMICH_WORKSPACE"

View File

@ -0,0 +1,64 @@
services:
immich-devcontainer-server:
build:
dockerfile: ./.devcontainer/server/Dockerfile
context: ../..
hostname: immich-devcontainer-server
extra_hosts:
- 'host.docker.internal:host-gateway'
environment:
- IMMICH_SERVER_URL=http://127.0.0.1:2283/
- REDIS_PORT=6400
- REDIS_HOSTNAME=immich-devcontainer-redis
- DB_PORT=5500
- DB_HOSTNAME=immich-devcontainer-database
volumes:
# bind mount host to /workspaces/immich
- ../..:/workspaces/immich
- ./vscode:/workspaces/immich/.vscode
- cli_node_modules:/workspaces/immich/cli/node_modules
- e2e_node_modules:/workspaces/immich/e2e/node_modules
- open_api_node_modules:/workspaces/immich/open-api/typescript-sdk/node_modules
- server_node_modules:/workspaces/immich/server/node_modules
- web_node_modules:/workspaces/immich/web/node_modules
- ${UPLOAD_LOCATION}:/workspaces/immich/server/upload
immich-devcontainer-redis:
image: redis:6.2-alpine@sha256:148bb5411c184abd288d9aaed139c98123eeb8824c5d3fce03cf721db58066d8
command: redis-server --port 6400
healthcheck:
test: redis-cli ping || exit 1
immich-devcontainer-database:
image: tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:739cdd626151ff1f796dc95a6591b55a714f341c737e27f045019ceabf8e8c52
env_file:
- .env
environment:
PGPORT: 5500
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_DB: ${DB_DATABASE_NAME}
POSTGRES_INITDB_ARGS: '--data-checksums'
volumes:
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
ports:
- 5432:5432
healthcheck:
test: >-
pg_isready --dbname="$${POSTGRES_DB}" --username="$${POSTGRES_USER}" || exit 1; Chksum="$$(psql --dbname="$${POSTGRES_DB}" --username="$${POSTGRES_USER}" --tuples-only --no-align --command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
interval: 5m
start_period: 5m
command: >-
postgres -c shared_preload_libraries=vectors.so -c 'search_path="$$user", public, vectors' -c logging_collector=on -c max_wal_size=2GB -c shared_buffers=512MB -c wal_compression=on
volumes:
cli_node_modules:
e2e_node_modules:
open_api_node_modules:
server_node_modules:
web_node_modules:
immich:
# UPLOAD_LOCATION must be set to a absolute path or vol-upload
vol-upload:
# DB_DATA_LOCATION must be set to a absolute path or vol-database
vol-database:

View File

@ -0,0 +1,26 @@
#!/bin/bash
# shellcheck source=common.sh
source /immich-devcontainer/common.sh
sudo find "${IMMICH_WORKSPACE}/server/upload" -not -path "${IMMICH_WORKSPACE}/server/upload/postgres/*" -not -path "${IMMICH_WORKSPACE}/server/upload/postgres" -exec chown node {} +
sudo chown node -R "${IMMICH_WORKSPACE}/.vscode" \
"${IMMICH_WORKSPACE}/cli/node_modules" \
"${IMMICH_WORKSPACE}/e2e/node_modules" \
"${IMMICH_WORKSPACE}/open-api/typescript-sdk/node_modules" \
"${IMMICH_WORKSPACE}/server/node_modules" \
"${IMMICH_WORKSPACE}/server/dist" \
"${IMMICH_WORKSPACE}/web/node_modules" \
"${IMMICH_WORKSPACE}/web/dist"
echo "Installing dependencies (server)"
echo npm --prefix "${IMMICH_WORKSPACE}/server" install
npm --prefix "${IMMICH_WORKSPACE}/server" install
echo "Installing dependencies (web)"
echo npm --prefix "${IMMICH_WORKSPACE}/open-api/typescript-sdk" install
npm --prefix "${IMMICH_WORKSPACE}/open-api/typescript-sdk" install
echo npm --prefix "${IMMICH_WORKSPACE}/open-api/typescript-sdk" run build
npm --prefix "${IMMICH_WORKSPACE}/open-api/typescript-sdk" run build
echo npm --prefix "${IMMICH_WORKSPACE}/web" install
npm --prefix "${IMMICH_WORKSPACE}/web" install

View File

@ -0,0 +1,16 @@
#!/bin/bash
# shellcheck source=common.sh
source /immich-devcontainer/common.sh
echo "Starting Nest API Server"
cd "${IMMICH_WORKSPACE}/server" || (
echo workspace not found
exit 1
)
while true; do
node ./node_modules/.bin/nest start --debug "0.0.0.0:9230" --watch
echo " Nest API Server crashed with exit code $?. Respawning in 3s ..."
sleep 3
done

View File

@ -0,0 +1,20 @@
#!/bin/bash
# shellcheck source=common.sh
source /immich-devcontainer/common.sh
until curl --output /dev/null --silent --head --fail "http://127.0.0.1:${IMMICH_PORT}/api/server/config"; do
echo 'waiting for api server...'
sleep 1
done
echo "Starting web"
cd "${IMMICH_WORKSPACE}/web" || (
echo workspace not found
exit 1
)
while true; do
node ./node_modules/.bin/vite dev --host 0.0.0.0 --port "${DEV_PORT}"
echo "Web crashed with exit code $?. Respawning in 3s ..."
sleep 3
done

View File

@ -0,0 +1,24 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "attach",
"restart": true,
"port": 9231,
"name": "Immich API Server",
"remoteRoot": "/usr/src/app",
"localRoot": "${workspaceFolder}/server"
},
{
"type": "node",
"request": "attach",
"restart": true,
"port": 9230,
"name": "Immich Workers",
"remoteRoot": "/usr/src/app",
"localRoot": "${workspaceFolder}/server"
}
]
}

View File

@ -0,0 +1,63 @@
{
"[css]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.tabSize": 2
},
"[dart]": {
"editor.defaultFormatter": "Dart-Code.dart-code",
"editor.formatOnSave": true,
"editor.selectionHighlight": false,
"editor.suggest.snippetsPreventQuickSuggestions": false,
"editor.suggestSelection": "first",
"editor.tabCompletion": "onlySnippets",
"editor.wordBasedSuggestions": "off"
},
"[javascript]": {
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit",
"source.removeUnusedImports": "explicit"
},
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.tabSize": 2
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.tabSize": 2
},
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.tabSize": 2
},
"[svelte]": {
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit",
"source.removeUnusedImports": "explicit"
},
"editor.defaultFormatter": "svelte.svelte-vscode",
"editor.formatOnSave": true,
"editor.tabSize": 2
},
"[typescript]": {
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit",
"source.removeUnusedImports": "explicit"
},
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.tabSize": 2
},
"cSpell.words": ["immich"],
"editor.formatOnSave": true,
"eslint.validate": ["javascript", "svelte"],
"explorer.fileNesting.enabled": true,
"explorer.fileNesting.patterns": {
"*.dart": "${capture}.g.dart,${capture}.gr.dart,${capture}.drift.dart",
"*.ts": "${capture}.spec.ts,${capture}.mock.ts"
},
"svelte.enable-ts-plugin": true,
"typescript.preferences.importModuleSpecifier": "non-relative"
}

View File

@ -0,0 +1,47 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Immich API Server (Nest)",
"type": "shell",
"command": "/immich-devcontainer/startNestApiServer.sh",
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "dedicated",
"showReuseMessage": true,
"clear": true
},
"runOptions": {
"runOn": "default"
},
"problemMatcher": []
},
{
"label": "Immich Web Server (Vite)",
"type": "shell",
"command": "/immich-devcontainer/startViteWebServer.sh",
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "dedicated",
"showReuseMessage": true,
"clear": true
},
"runOptions": {
"runOn": "default"
},
"problemMatcher": []
},
{
"label": "Immich Server and Web",
"dependsOn": ["Immich Web Server (Vite)", "Immich API Server (Nest)"],
"runOptions": {
"runOn": "folderOpen"
},
"problemMatcher": []
}
]
}

View File

@ -0,0 +1,71 @@
---
sidebar_position: 3
---
## Dev Containers
### Getting started with Dev Containers
The Dev Container is a fully featured dev environment. It is a portable way, using docker containers, to set up a dev environment. With a single click, you can get started with a Immich environment, on Mac, Linux or Windows or the cloud, like GitHub codespaces.
[![Open in VSCode Containers](https://img.shields.io/static/v1?label=VSCode%20DevContainer&message=Immich&color=blue)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/immich-app/immich/)
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/immich-app/immich/)
[More info on dev containers here](https://docs.github.com/en/codespaces/setting-up-your-project-for-codespaces/adding-a-dev-container-configuration/introduction-to-dev-containers)
### Details
The Immich dev container runs the web and server in one container, and redis and ML each in their own container.
By default, if you don't customize any ENV VARs, when you start the Immich dev container, it will be configured to use volumes for the upload and database locations on disk. These volumes are persistent, and they last between container rebuilds and restarts.
In non-cloud environments, you can optionally use host filesystem paths instead of volumes - this will allow you to store the upload directory and database directory on the host filesystem, rather than a volume.
### Launching Dev Container from a cloned repo
1. Clone the project repo.
2. Open VS Code
3. Press ctrl/command-p type ">Dev Containers: Rebuild and Reopen in Container"
4. Select "Immich - Backend and Frontend"
5. Wait a while - after the builds are done, the server and web processes will be started as tasks, and the browser will be opened (once) to the front page.
## Configuring Database and Upload paths to the host
ENV VARs can use to control the location of the upload and the database paths.
### UPLOAD_LOCATION
The default for `UPLOAD_LOCATION` is `vol-upload` which is a volume mount.
The only supported value when using volumes is `vol-upload`. This is because it is hard-coded as a named volume in the `.devcontainer/server/docker-compose.yaml` file.
To use a bind mount instead, simply set `UPLOAD_LOCATION` to an **absolute** path on the host file system instead. This must be added to the `.bash_profile` if your using bash, or equivalent for other shells.
```bash
export UPLOAD_LOCATION=/data/my/upload/path
```
### DB_DATA_LOCATION
The default for `DB_DATA_LOCATION` is `vol-database` which is a volume mount.
The only supported value when using volumes is `vol-database` since it hard-coded as a named volume in the `.devcontainer/server/docker-compose.yaml` file.
To use a bind mount instead, simply set `DB_DATA_LOCATION` to an **absolute** path on the host file system instead. This must be added to the `.bash_profile` if your using bash, or equivalent for other shells.
```bash
export DB_DATA_LOCATION=/data/my/upload/path
```
### Other Variables
Its unlikely, but in case you modified the username/password of the database, you can control these values using the following ENV VARs:
```bash
export DB_PASSWORD=postgres
export DB_USERNAME=postgres
export DB_DATABASE_NAME=immich
```
This must be added to the `.bash_profile` if your using bash, or equivalent for other shells.