> ## Documentation Index
> Fetch the complete documentation index at: https://docs.malak.vc/llms.txt
> Use this file to discover all available pages before exploring further.

# Installation

## Services needed

* Redis
* Postgresql
* A resend account or any SMTP provider for emailing
* Maxmind country and city dbs ( they are free to download )

## Backend

Malak's backend runs with very minimal hardware requirements by itself, you really need
as little as 512MB ram amongst others. For production, we strongly recommend Linux
but it should work across Windows and macOS too

<Tip>
  We offer white glove self-hosting services. Shoot us an email at
  [support@ayinke.ventures](mailto:support@ayinke.ventures)
</Tip>

At the very minimum, this needs to be in your `.env` or your `.yml` config file but if using `.env`,
it should look like below:

<Info>You can generate you `aes_gcm` key with `LC_ALL=C tr -dc 'A-Za-z0-9' </dev/urandom | head -c 32; echo`</Info>

<Tip>Download the maxmind country db and city db then use their path</Tip>

<CodeGroup>
  ```txt env theme={null}

  MALAK_AUTH_GOOGLE_CLIENT_ID=
  MALAK_AUTH_GOOGLE_CLIENT_SECRET=
  MALAK_AUTH_GOOGLE_REDIRECT_URI=https://app.malak.vc
  MALAK_AUTH_GOOGLE_IS_ENABLED=true

  MALAK_API_KEY_HASH_SECRET=12347844

  MALAK_AUTH_JWT_KEY=a907e75f8091

  ## new acccounts are assigned this plan
  MALAK_BILLING_DEFAULT_PLAN_REFERENCE=prod_Qm

  MALAK_HTTP_SWAGGER_UI_ENABLED=false
  MALAK_HTTP_PORT=5400

  MALAK_LOGGING_MODE=prod

  MALAK_UPLOADER_S3_ACCESS_KEY=78264ae70f26d7
  MALAK_UPLOADER_S3_ACCESS_SECRET=5bc45d2
  MALAK_UPLOADER_S3_REGION=auto
  MALAK_UPLOADER_S3_ENDPOINT=https://6d3.cloudflarestorage.com
  MALAK_UPLOADER_S3_USE_TLS=true

  MALAK_EMAIL_PROVIDER=resend
  MALAK_EMAIL_RESEND_API_KEY=re_c
  MALAK_EMAIL_RESEND_WEBHOOK_SECRET=re_c
  MALAK_EMAIL_SENDER=oops@domain.com
  MALAK_EMAIL_SENDER_NAME=Your org

  MALAK_SECRETS_PROVIDER=aes_gcm
  MALAK_SECRETS_AES_KEY=V90duVSe

  MALAK_ANALYTICS_MAX_MIND_COUNTRY_DB=
  MALAK_ANALYTICS_MAX_MIND_CITY_DB=

  MALAK_BILLING_DEFAULT_PLAN_REFERENCE
  ```

  ```yml yaml theme={null}
  auth:
    google:
      client_id: "CLIENT_ID"
      client_secret: "CLIENT_SECRET"
      redirect_uri: "http://localhost:3000"
      is_enabled: true

    jwt:
      key: JWT_KEY

  api_key:
    hash_secret: 12345

  billing:
    ## new accounts assigned this plan
    default_plan_reference: prod_Qmjfkf

  http:
    port: 5400 ## defaults to 5300
    swagger:
      port: 9999
      ui_enabled: true

  uploader:
    s3:
      access_key: BhK
      access_secret: dzE
      region: lagos-1
      endpoint: http://localhost:9000
      use_tls: false

  email:
    provider: smtp
    sender: email@updates.domain
    sender_name: Malak
    resend:
      api_key: fjfk
      webhook_secret: fufhifuji

  billing:
    default_plan_reference: "reference from plans table"

  secrets:
    provider: aes_gcm
    aes:
      key: ujffjkfk
  ```
</CodeGroup>

<Tip>
  There are way more options but [you can find other
  options](/backend-configuration){" "}
</Tip>

### Running

Prerequisites:

* [Run cron jobs](/self-hosting/cron)

#### Kubernetes

<CodeGroup>
  ```yml deployment.yml theme={null}
  apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: malak-server
    namespace: experiments
  spec:
    replicas: 2
    selector:
      matchLabels:
        app: malak-server
    template:
      metadata:
        labels:
          app: malak-server
        annotations:
          secrets.infisical.com/auto-reload: "true"
      spec:
        volumes:
          - name: geoip-volume
            emptyDir: {}
        initContainers:
          - name: maxmind-downloader
            image: curlimages/curl:latest
            command:
              - sh
              - -c
              - |
                curl -L -u maxmindAccountID:licenseKey "https://download.maxmind.com/geoip/databases/GeoLite2-City/download?suffix=tar.gz" -o /tmp/city.tar.gz && \
                cd /tmp && \
                tar -xzf city.tar.gz && \
                find . -name "*.mmdb" -type f -exec cp {} /opt/maxmind/city.mmdb \;
            volumeMounts:
              - name: geoip-volume
                mountPath: /opt/maxmind

          - name: country-maxmind-downloader
            image: curlimages/curl:latest
            command:
              - sh
              - -c
              - |
                curl -L -u maxmindAccountID:licenseKey "https://download.maxmind.com/geoip/databases/GeoLite2-Country/download?suffix=tar.gz" -o /tmp/country.tar.gz && \
                cd /tmp && \
                tar -xzf country.tar.gz && \
                find . -name "*.mmdb" -type f -exec cp {} /opt/maxmind/country.mmdb \;
            volumeMounts:
              - name: geoip-volume
                mountPath: /opt/maxmind

        containers:
          - name: server
            resources:
              requests:
                memory: "512Mi"
              limits:
                memory: "1Gi"
            image: ghcr.io/ayinke-llc/malak:0.9.9
            envFrom:
              - secretRef:
                  name: infisicalsecret-malak
            imagePullPolicy: Always
            ports:
              - containerPort: 5400
            volumeMounts:
              - name: geoip-volume
                mountPath: /opt/maxmind
        imagePullSecrets:
          - name: regcred
  ```

  ```yml service theme={null}
  ---
  apiVersion: networking.k8s.io/v1
  kind: Ingress
  metadata:
    name: malak-ingress
    namespace: experiments
    annotations:
      nginx.ingress.kubernetes.io/rewrite-target: /
      cert-manager.io/cluster-issuer: letsencrypt-prod
      kubernetes.io/ingress.class: "nginx"
  spec:
    ingressClassName: nginx
    tls:
      - hosts:
          - api.malak.vc
        secretName: malak-tls
    rules:
      - host: api.malak.vc
        http:
          paths:
            - path: /
              pathType: Prefix
              backend:
                service:
                  name: malak-service
                  port:
                    number: 80
  ---
  apiVersion: v1
  kind: Service
  metadata:
    name: malak-service
    namespace: experiments
  spec:
    ports:
      - port: 80
        targetPort: 5400
    selector:
      app: malak-server
  ```
</CodeGroup>

#### VPS, bare metal

To run the actual server, you need the following command:

<CodeGroup>
  ```sh env config theme={null}
  malak http
  ```

  ```sh yaml config theme={null}
  malak http --config path/to/.yml
  ```
</CodeGroup>

##### Systemd service

You can use this sample Systemd configuration to run the service.

```txt theme={null}
[Unit]
Description=Malak Backend API

[Service]
ExecStart=malak http
User=root
Group=root
UMask=007
EnvironmentFile=/etc/path/.env

[Install]
WantedBy=multi-user.target
```

#### Docker

```sh theme={null}
docker run ghcr.io/ayinke-llc/malak:0.9.7
```

You can view the [latest docker images here](https://github.com/ayinke-llc/malak/pkgs/container/malak/versions)

You can verify with `gh attestation verify oci://ghcr.io/ayinke-llc/malak:{TAG} --owner ayinke-llc --predicate-type https://in-toto.io/attestation/release/v0.1`

#### Plans

You need to have atleast one plan in your `plans` table. There are two ways to do this:

* `malak plans create`
* Import this sample sql into your database. [Github gist](https://gist.github.com/adelowo/f05d6845752e336ceb45b60573da37ed)

After this, make sure to update the billing default reference to this

## Frontend

It is a NextJS app so it can be Installable anywhere such as Vercel and others.
Source is [on Github and installable from there](https://github.com/ayinke-llc/malak/tree/main/web/ui)

### Configuration

```txt theme={null}
NEXT_PUBLIC_GOOGLE_CLIENT_ID=
# NEXT_PUBLIC_MALAK_POSTHOG_KEY=
# NEXT_PUBLIC_MALAK_POSTHOG_HOST=https://us.i.posthog.com
# NEXT_PUBLIC_MALAK_ENABLE_POSTHOG=false
# NEXT_PUBLIC_SENTRY_DSN=https://xxxx.ingest.us.sentry.io/45
NEXT_PUBLIC_DECKS_DOMAIN=https://deck.malak.vc
NEXT_PUBLIC_SUPPORT_EMAIL=support@ayinke.ventures
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_API_URL=http://localhost:5300/v1
```

### Deck viewer

<Link href="/self-hosting/deck">Docs are available here </Link>
