Compare commits
1 Commits
fix/docker
...
fix/remove
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fbfdec1bbf |
33
.env.example
33
.env.example
@@ -1,39 +1,28 @@
|
|||||||
# https://github.com/kanbn/kan?tab=readme-ov-file#environment-variables-)
|
POSTGRES_URL=
|
||||||
|
|
||||||
# Required environment variables
|
EMAIL_FROM=
|
||||||
NEXT_PUBLIC_BASE_URL= # e.g. https://kan.bn
|
|
||||||
BETTER_AUTH_SECRET= # Random 32+ char string (can gen with: openssl rand -base64 24 | tr -dc 'a-zA-Z0-9' | head -c 32)
|
|
||||||
POSTGRES_URL= # e.g. postgresql://kan:your_password@your_host:5432/kan
|
|
||||||
|
|
||||||
# Only required if deploying from compose
|
|
||||||
POSTGRES_PASSWORD=
|
|
||||||
|
|
||||||
# SMTP (optional)
|
|
||||||
SMTP_HOST=
|
SMTP_HOST=
|
||||||
SMTP_PORT=465 # Port 587 will not work
|
SMTP_PORT=
|
||||||
SMTP_USER=
|
SMTP_USER=
|
||||||
SMTP_PASSWORD=
|
SMTP_PASSWORD=
|
||||||
EMAIL_FROM= # e.g. "Kan <hello@mail.kan.bn>"
|
|
||||||
|
|
||||||
# S3 storage (optional)
|
NEXT_PUBLIC_BASE_URL=
|
||||||
|
NEXT_PUBLIC_STORAGE_URL=
|
||||||
|
NEXT_PUBLIC_AVATAR_BUCKET_NAME=
|
||||||
|
NEXT_PUBLIC_ALLOW_CREDENTIALS=
|
||||||
|
NEXT_PUBLIC_DISABLE_SIGN_UP=
|
||||||
|
|
||||||
S3_REGION=
|
S3_REGION=
|
||||||
S3_ENDPOINT=
|
S3_ENDPOINT=
|
||||||
S3_ACCESS_KEY_ID=
|
S3_ACCESS_KEY_ID=
|
||||||
S3_SECRET_ACCESS_KEY=
|
S3_SECRET_ACCESS_KEY=
|
||||||
NEXT_PUBLIC_STORAGE_URL=
|
|
||||||
NEXT_PUBLIC_AVATAR_BUCKET_NAME=
|
|
||||||
NEXT_PUBLIC_STORAGE_DOMAIN=
|
|
||||||
|
|
||||||
# Auth config (optional)
|
BETTER_AUTH_SECRET=
|
||||||
NEXT_PUBLIC_ALLOW_CREDENTIALS=
|
BETTER_AUTH_TRUSTED_ORIGINS=
|
||||||
NEXT_PUBLIC_DISABLE_SIGN_UP=
|
|
||||||
|
|
||||||
# Integration providers (optional)
|
|
||||||
TRELLO_APP_API_KEY=
|
TRELLO_APP_API_KEY=
|
||||||
TRELLO_APP_SECRET=
|
TRELLO_APP_SECRET=
|
||||||
|
|
||||||
# OAuth providers (optional)
|
|
||||||
BETTER_AUTH_TRUSTED_ORIGINS=
|
|
||||||
GOOGLE_CLIENT_ID=
|
GOOGLE_CLIENT_ID=
|
||||||
GOOGLE_CLIENT_SECRET=
|
GOOGLE_CLIENT_SECRET=
|
||||||
DISCORD_CLIENT_ID=
|
DISCORD_CLIENT_ID=
|
||||||
|
|||||||
73
README.md
73
README.md
@@ -47,67 +47,34 @@ See our [roadmap](https://kan.bn/kan/roadmap) for upcoming features.
|
|||||||
|
|
||||||
## Self Hosting 🐳
|
## Self Hosting 🐳
|
||||||
|
|
||||||
The easiest way to self-host Kan is with Docker Compose. This will set up everything for you including your postgres database.
|
### PostgreSQL Database Setup
|
||||||
|
|
||||||
1. Create a new file called `docker-compose.yml` and paste the following configuration:
|
Kan requires a PostgreSQL database. You can run one using the official PostgreSQL Docker image:
|
||||||
|
|
||||||
```yaml
|
|
||||||
services:
|
|
||||||
web:
|
|
||||||
image: ghcr.io/kanbn/kan:latest
|
|
||||||
container_name: kan-web
|
|
||||||
ports:
|
|
||||||
- "3000:3000"
|
|
||||||
networks:
|
|
||||||
- kan-network
|
|
||||||
environment:
|
|
||||||
NEXT_PUBLIC_BASE_URL: http://localhost:3000
|
|
||||||
BETTER_AUTH_SECRET: your_auth_secret
|
|
||||||
POSTGRES_URL: postgresql://kan:your_postgres_password@postgres:5432/kan_db
|
|
||||||
NEXT_PUBLIC_ALLOW_CREDENTIALS: true
|
|
||||||
depends_on:
|
|
||||||
- postgres
|
|
||||||
restart: unless-stopped
|
|
||||||
|
|
||||||
postgres:
|
|
||||||
image: postgres:15
|
|
||||||
container_name: kan-db
|
|
||||||
environment:
|
|
||||||
POSTGRES_DB: kan_db
|
|
||||||
POSTGRES_USER: kan
|
|
||||||
POSTGRES_PASSWORD: your_postgres_password
|
|
||||||
ports:
|
|
||||||
- 5432:5432
|
|
||||||
volumes:
|
|
||||||
- kan_postgres_data:/var/lib/postgresql/data
|
|
||||||
restart: unless-stopped
|
|
||||||
networks:
|
|
||||||
- kan-network
|
|
||||||
|
|
||||||
networks:
|
|
||||||
kan-network:
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
postgres_data:
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Start the containers in detached mode:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose up -d
|
# Run PostgreSQL in a container using the official postgres image
|
||||||
|
docker run -d \
|
||||||
|
--name kan-db \
|
||||||
|
-e POSTGRES_DB=kan \
|
||||||
|
-e POSTGRES_USER=kan_user \
|
||||||
|
-e POSTGRES_PASSWORD=your_secure_password \
|
||||||
|
-p 5432:5432 \
|
||||||
|
-v kan_postgres_data:/var/lib/postgresql/data \
|
||||||
|
postgres:15
|
||||||
|
|
||||||
|
# Your POSTGRES_URL should be:
|
||||||
|
# postgres://kan_user:your_secure_password@your_host:5432/kan
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Access Kan at http://localhost:3000
|
### Kan Application Deployment
|
||||||
|
|
||||||
The application will be running in the background. You can manage the containers using these commands:
|
Deploy Kan with Docker using our pre-built image:
|
||||||
|
|
||||||
- To stop the containers: `docker compose down`
|
```bash
|
||||||
- To view logs: `docker compose logs -f`
|
docker pull ghcr.io/kanbn/kan:latest && docker run -it -p 3000:3000 --env-file .env ghcr.io/kanbn/kan:latest
|
||||||
- To restart the containers: `docker compose restart`
|
```
|
||||||
|
|
||||||
For the complete Docker Compose configuration, see [docker-compose.yml](./docker-compose.yml) in the repository.
|
Make sure to create a `.env` file with the required environment variables (see the Environment Variables section below).
|
||||||
|
|
||||||
> **Note**: The Docker Compose configuration shown above is a minimal example. For a complete setup with all features (email, OAuth, file uploads, etc.), you'll need to create a `.env` file with the required environment variables. See the Environment Variables section below for the full list of available options.
|
|
||||||
|
|
||||||
## Local Development 🧑💻
|
## Local Development 🧑💻
|
||||||
|
|
||||||
|
|||||||
@@ -53,14 +53,8 @@ RUN --mount=type=cache,id=pnpm,target=~/.pnpm-store pnpm install --frozen-lockfi
|
|||||||
# Copy source code of isolated subworkspace
|
# Copy source code of isolated subworkspace
|
||||||
COPY --from=pruner /app/out/full/ .
|
COPY --from=pruner /app/out/full/ .
|
||||||
|
|
||||||
|
|
||||||
RUN pnpm build --filter=${PROJECT}
|
RUN pnpm build --filter=${PROJECT}
|
||||||
|
|
||||||
# Copy static files to standalone directory
|
|
||||||
RUN mkdir -p apps/web/.next/standalone/.next && \
|
|
||||||
mv apps/web/public apps/web/.next/standalone/ && \
|
|
||||||
mv apps/web/.next/static apps/web/.next/standalone/.next/
|
|
||||||
|
|
||||||
# 4. Final image - runner stage to run the application
|
# 4. Final image - runner stage to run the application
|
||||||
FROM base AS runner
|
FROM base AS runner
|
||||||
ARG APP_DIRNAME
|
ARG APP_DIRNAME
|
||||||
@@ -81,5 +75,6 @@ ARG PORT=3000
|
|||||||
ENV PORT=${PORT}
|
ENV PORT=${PORT}
|
||||||
EXPOSE ${PORT}
|
EXPOSE ${PORT}
|
||||||
|
|
||||||
CMD ["/bin/sh", "./entrypoint.sh"]
|
# Run migration on start for now (until we have a better way to handle this)
|
||||||
|
CMD ["sh", "-c", "cd /app && pnpm db:migrate && cd /app/apps/web && pnpm start"]
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# Run migrations from the Turborepo root context
|
|
||||||
echo "Running database migrations..."
|
|
||||||
# Navigate to the Turborepo root to run the db:migrate command
|
|
||||||
pnpm --prefix /app db:migrate
|
|
||||||
|
|
||||||
# Check if migration was successful
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo "\nDatabase migration failed! Exiting."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "\nStarting Next.js application..."
|
|
||||||
# Start the Next.js application from the web app's directory
|
|
||||||
exec node .next/standalone/apps/web/server.js
|
|
||||||
@@ -10,7 +10,6 @@ configureRuntimeEnv();
|
|||||||
|
|
||||||
/** @type {import("next").NextConfig} */
|
/** @type {import("next").NextConfig} */
|
||||||
const config = {
|
const config = {
|
||||||
output: "standalone",
|
|
||||||
reactStrictMode: true,
|
reactStrictMode: true,
|
||||||
|
|
||||||
/** Enables hot reloading for local packages without a build step */
|
/** Enables hot reloading for local packages without a build step */
|
||||||
|
|||||||
@@ -17,11 +17,8 @@ export const env = createEnv({
|
|||||||
BETTER_AUTH_SECRET: z.string(),
|
BETTER_AUTH_SECRET: z.string(),
|
||||||
BETTER_AUTH_TRUSTED_ORIGINS: z
|
BETTER_AUTH_TRUSTED_ORIGINS: z
|
||||||
.string()
|
.string()
|
||||||
.transform((s) => (s === "" ? undefined : s))
|
.refine((s) =>
|
||||||
.refine(
|
s.split(",").every((l) => z.string().url().safeParse(l).success),
|
||||||
(s) =>
|
|
||||||
!s ||
|
|
||||||
s.split(",").every((l) => z.string().url().safeParse(l).success),
|
|
||||||
)
|
)
|
||||||
.optional(),
|
.optional(),
|
||||||
POSTGRES_URL: z.string().url(),
|
POSTGRES_URL: z.string().url(),
|
||||||
@@ -85,17 +82,11 @@ export const env = createEnv({
|
|||||||
NEXT_PUBLIC_STORAGE_DOMAIN: z.string().optional(),
|
NEXT_PUBLIC_STORAGE_DOMAIN: z.string().optional(),
|
||||||
NEXT_PUBLIC_ALLOW_CREDENTIALS: z
|
NEXT_PUBLIC_ALLOW_CREDENTIALS: z
|
||||||
.string()
|
.string()
|
||||||
.transform((s) => (s === "" ? undefined : s))
|
.refine((s) => s.toLowerCase() === "true" || s.toLowerCase() === "false")
|
||||||
.refine(
|
|
||||||
(s) => !s || s.toLowerCase() === "true" || s.toLowerCase() === "false",
|
|
||||||
)
|
|
||||||
.optional(),
|
.optional(),
|
||||||
NEXT_PUBLIC_DISABLE_SIGN_UP: z
|
NEXT_PUBLIC_DISABLE_SIGN_UP: z
|
||||||
.string()
|
.string()
|
||||||
.transform((s) => (s === "" ? undefined : s))
|
.refine((s) => s.toLowerCase() === "true" || s.toLowerCase() === "false")
|
||||||
.refine(
|
|
||||||
(s) => !s || s.toLowerCase() === "true" || s.toLowerCase() === "false",
|
|
||||||
)
|
|
||||||
.optional(),
|
.optional(),
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,49 +1,29 @@
|
|||||||
services:
|
services:
|
||||||
web:
|
web:
|
||||||
image: ghcr.io/kanbn/kan:latest
|
image: ghcr.io/kanbn/kan:latest
|
||||||
container_name: kan-web
|
|
||||||
ports:
|
ports:
|
||||||
- "${WEB_PORT:-3000}:3000"
|
- "3001:3000"
|
||||||
networks:
|
networks:
|
||||||
- kan-network
|
|
||||||
- dokploy-network
|
- dokploy-network
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: ./apps/web/Dockerfile
|
dockerfile: ./apps/web/Dockerfile
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
|
command: ["pnpm", "start"]
|
||||||
environment:
|
environment:
|
||||||
# Required environment variables
|
- EMAIL_FROM=${EMAIL_FROM}
|
||||||
- NEXT_PUBLIC_BASE_URL=${NEXT_PUBLIC_BASE_URL}
|
|
||||||
- BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET}
|
|
||||||
- POSTGRES_URL=${POSTGRES_URL}
|
|
||||||
|
|
||||||
# SMTP (optional)
|
|
||||||
- SMTP_HOST=${SMTP_HOST}
|
- SMTP_HOST=${SMTP_HOST}
|
||||||
- SMTP_PORT=${SMTP_PORT}
|
- SMTP_PORT=${SMTP_PORT}
|
||||||
- SMTP_USER=${SMTP_USER}
|
- SMTP_USER=${SMTP_USER}
|
||||||
- SMTP_PASSWORD=${SMTP_PASSWORD}
|
- SMTP_PASSWORD=${SMTP_PASSWORD}
|
||||||
- EMAIL_FROM=${EMAIL_FROM}
|
- BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET}
|
||||||
|
- BETTER_AUTH_TRUSTED_ORIGINS=${BETTER_AUTH_TRUSTED_ORIGINS}
|
||||||
# S3 storage (optional)
|
- STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY}
|
||||||
- S3_ACCESS_KEY_ID=${S3_ACCESS_KEY_ID}
|
- STRIPE_WEBHOOK_SECRET=${STRIPE_WEBHOOK_SECRET}
|
||||||
- S3_SECRET_ACCESS_KEY=${S3_SECRET_ACCESS_KEY}
|
- POSTGRES_URL=${POSTGRES_URL}
|
||||||
- S3_REGION=${S3_REGION}
|
|
||||||
- S3_ENDPOINT=${S3_ENDPOINT}
|
|
||||||
- NEXT_PUBLIC_STORAGE_URL=${NEXT_PUBLIC_STORAGE_URL}
|
|
||||||
- NEXT_PUBLIC_AVATAR_BUCKET_NAME=${NEXT_PUBLIC_AVATAR_BUCKET_NAME}
|
|
||||||
- NEXT_PUBLIC_STORAGE_DOMAIN=${NEXT_PUBLIC_STORAGE_DOMAIN}
|
|
||||||
|
|
||||||
# Auth config (optional)
|
|
||||||
- NEXT_PUBLIC_ALLOW_CREDENTIALS=${NEXT_PUBLIC_ALLOW_CREDENTIALS}
|
|
||||||
- NEXT_PUBLIC_DISABLE_SIGN_UP=${NEXT_PUBLIC_DISABLE_SIGN_UP}
|
|
||||||
|
|
||||||
# Integration providers (optional)
|
|
||||||
- TRELLO_APP_API_KEY=${TRELLO_APP_API_KEY}
|
- TRELLO_APP_API_KEY=${TRELLO_APP_API_KEY}
|
||||||
- TRELLO_APP_SECRET=${TRELLO_APP_SECRET}
|
- TRELLO_APP_SECRET=${TRELLO_APP_SECRET}
|
||||||
|
|
||||||
# OAuth providers (optional)
|
|
||||||
- BETTER_AUTH_TRUSTED_ORIGINS=${BETTER_AUTH_TRUSTED_ORIGINS}
|
|
||||||
- GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID}
|
- GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID}
|
||||||
- GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET}
|
- GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET}
|
||||||
- DISCORD_CLIENT_ID=${DISCORD_CLIENT_ID}
|
- DISCORD_CLIENT_ID=${DISCORD_CLIENT_ID}
|
||||||
@@ -81,35 +61,18 @@ services:
|
|||||||
- APPLE_CLIENT_ID=${APPLE_CLIENT_ID}
|
- APPLE_CLIENT_ID=${APPLE_CLIENT_ID}
|
||||||
- APPLE_CLIENT_SECRET=${APPLE_CLIENT_SECRET}
|
- APPLE_CLIENT_SECRET=${APPLE_CLIENT_SECRET}
|
||||||
- APPLE_APP_BUNDLE_IDENTIFIER=${APPLE_APP_BUNDLE_IDENTIFIER}
|
- APPLE_APP_BUNDLE_IDENTIFIER=${APPLE_APP_BUNDLE_IDENTIFIER}
|
||||||
|
- S3_ACCESS_KEY_ID=${S3_ACCESS_KEY_ID}
|
||||||
# Cloud (not required)
|
- S3_SECRET_ACCESS_KEY=${S3_SECRET_ACCESS_KEY}
|
||||||
|
- S3_REGION=${S3_REGION}
|
||||||
|
- S3_ENDPOINT=${S3_ENDPOINT}
|
||||||
- NEXT_PUBLIC_KAN_ENV=${NEXT_PUBLIC_KAN_ENV}
|
- NEXT_PUBLIC_KAN_ENV=${NEXT_PUBLIC_KAN_ENV}
|
||||||
|
- NEXT_PUBLIC_BASE_URL=${NEXT_PUBLIC_BASE_URL}
|
||||||
|
- NEXT_PUBLIC_STORAGE_URL=${NEXT_PUBLIC_STORAGE_URL}
|
||||||
|
- NEXT_PUBLIC_AVATAR_BUCKET_NAME=${NEXT_PUBLIC_AVATAR_BUCKET_NAME}
|
||||||
|
- NEXT_PUBLIC_STORAGE_DOMAIN=${NEXT_PUBLIC_STORAGE_DOMAIN}
|
||||||
- NEXT_PUBLIC_UMAMI_ID=${NEXT_PUBLIC_UMAMI_ID}
|
- NEXT_PUBLIC_UMAMI_ID=${NEXT_PUBLIC_UMAMI_ID}
|
||||||
- STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY}
|
- NEXT_PUBLIC_ALLOW_CREDENTIALS=${NEXT_PUBLIC_ALLOW_CREDENTIALS}
|
||||||
- STRIPE_WEBHOOK_SECRET=${STRIPE_WEBHOOK_SECRET}
|
- NEXT_PUBLIC_DISABLE_SIGN_UP=${NEXT_PUBLIC_DISABLE_SIGN_UP}
|
||||||
depends_on:
|
|
||||||
- postgres
|
|
||||||
restart: unless-stopped
|
|
||||||
|
|
||||||
postgres:
|
|
||||||
image: postgres:15
|
|
||||||
container_name: kan-db
|
|
||||||
environment:
|
|
||||||
- POSTGRES_DB=kan_db
|
|
||||||
- POSTGRES_USER=kan
|
|
||||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
|
||||||
ports:
|
|
||||||
- 5432:5432
|
|
||||||
volumes:
|
|
||||||
- kan_postgres_data:/var/lib/postgresql/data
|
|
||||||
restart: unless-stopped
|
|
||||||
networks:
|
|
||||||
- kan-network
|
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
kan-network:
|
|
||||||
dokploy-network:
|
dokploy-network:
|
||||||
external: true
|
external: true
|
||||||
|
|
||||||
volumes:
|
|
||||||
kan_postgres_data:
|
|
||||||
|
|||||||
Reference in New Issue
Block a user