Open Source Apps: Krita, Inkscape and Zipline

Published: Jul 17, 2025 by Isaac Johnson

I’ve had a few creative apps on my list to checkout for some time. The first is Krita which has a LinuxServer group container. The other is Inkscape which also can be exposed as a container. I’ll also take a moment and just try the installable fat clients in Windows.

Lastly, akin to Filegator and other file serving apps, we’ll check out Zipline which is a very simple clean open-source file sharing app. I’ll explore deploying in Kubernetes, exposing with a TLS ingress and how to use it.

Let’s start with Krita.

Krita

Marius posted about this free and open-source painting program, Krita.

The Linuxserver docs suggest we can use Docker compose

---
services:
  krita:
    image: lscr.io/linuxserver/krita:latest
    container_name: krita
    security_opt:
      - seccomp:unconfined #optional
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Etc/UTC
    volumes:
      - /path/to/config:/config
    ports:
      - 3000:3000
      - 3001:3001
    restart: unless-stopped

That should convert nicely to a k8s manifest

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: krita-config-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: local-path
  resources:
    requests:
      storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: krita
spec:
  replicas: 1
  selector:
    matchLabels:
      app: krita
  template:
    metadata:
      labels:
        app: krita
    spec:
      containers:
        - name: krita
          image: lscr.io/linuxserver/krita:latest
          ports:
            - containerPort: 3000
            - containerPort: 3001
          env:
            - name: PUID
              value: "1000"
            - name: PGID
              value: "1000"
            - name: TZ
              value: "America/Chicago"
          volumeMounts:
            - name: config
              mountPath: /config
          securityContext:
            seccompProfile:
              type: Unconfined
      volumes:
        - name: config
          persistentVolumeClaim:
            claimName: krita-config-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: krita
spec:
  selector:
    app: krita
  ports:
    - protocol: TCP
      port: 80
      targetPort: 3000

Which should be easy to apply

$ kubectl apply -f ./krita.yaml
persistentvolumeclaim/krita-config-pvc created
deployment.apps/krita created
service/krita created

I can now port-forward to the service

$ kubectl port-forward svc/krita 8888:80
Forwarding from 127.0.0.1:8888 -> 3000
Forwarding from [::1]:8888 -> 3000
Handling connection for 8888
Handling connection for 8888
Handling connection for 8888
Handling connection for 8888
Handling connection for 8888

there is an interesting page on launch

/content/images/2025/07/krita-01.png

but soon we have the main dashboard for the app

/content/images/2025/07/krita-02.png

I noticed the new document dimensions match the browser window we are using

/content/images/2025/07/krita-03.png

I’m remote in low-bandwidth presently so there is a bit of a delay, but man, this is giving me real Photoshop ~v4 vibes

/content/images/2025/07/krita-04.png

Since I really wasn’t digging on the latency, I decided to pivot back to local as this really is best as a local app

I created a docker compose file according to their docs

builder@LuiGi:~/Workspaces/OSLocal/krita$ cat docker-compose.yaml
services:
  krita:
    image: lscr.io/linuxserver/krita:latest
    container_name: krita
    security_opt:
      - seccomp:unconfined #optional
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/Chicago
    volumes:
      - /home/builder/Workspaces/OSLocal/krita/config:/config
    ports:
      - 3000:3000
      - 3001:3001
    restart: unless-stopped

then fired it up

builder@LuiGi:~/Workspaces/OSLocal/krita$ docker compose up
[+] Running 14/14
 ✔ krita Pulled                                                                                                  130.0s
   ✔ a5e3ea2009e2 Pull complete                                                                                    2.9s
   ✔ e1cde46db0e1 Pull complete                                                                                    3.0s
   ✔ 46f2d9bbcff7 Pull complete                                                                                    3.1s
   ✔ f2d94bf0c7ba Pull complete                                                                                    3.2s
   ✔ 0469477658fc Pull complete                                                                                    3.4s
   ✔ 35e63de34f77 Pull complete                                                                                    6.2s
   ✔ 681cde493f59 Pull complete                                                                                    6.4s
   ✔ 63ef96ffaedd Pull complete                                                                                    8.9s
   ✔ 1c6d24f55ad9 Pull complete                                                                                   10.6s
   ✔ 109b5f323c14 Pull complete                                                                                  112.0s
   ✔ fd6c3b0eb1fb Pull complete                                                                                  112.2s
   ✔ 827fa7ea52bc Pull complete                                                                                  126.0s
   ✔ 206f67857dfb Pull complete                                                                                  126.1s
[+] Running 2/2
 ✔ Network krita_default  Created                                                                                  0.2s
 ✔ Container krita        Created                                                                                  0.4s
Attaching to krita
krita  | [migrations] started
krita  | [migrations] no migrations found
krita  | ───────────────────────────────────────
krita  |
krita  |       ██╗     ███████╗██╗ ██████╗
krita  |       ██║     ██╔════╝██║██╔═══██╗
krita  |       ██║     ███████╗██║██║   ██║
krita  |       ██║     ╚════██║██║██║   ██║
krita  |       ███████╗███████║██║╚██████╔╝
krita  |       ╚══════╝╚══════╝╚═╝ ╚═════╝
krita  |
krita  |    Brought to you by linuxserver.io
krita  | ───────────────────────────────────────
krita  |
krita  | To support LSIO projects visit:
krita  | https://www.linuxserver.io/donate/
krita  |
krita  | ───────────────────────────────────────
krita  | GID/UID
krita  | ───────────────────────────────────────
krita  |
krita  | User UID:    1000
krita  | User GID:    1000
krita  | ───────────────────────────────────────
krita  | ........+.+......+..+.+..+...+.........+++++++++++++++++++++++++++++++++++++++*...+............+++++++++++++++++++++++++++++++++++++++*....+.+.........+.........+..+.............+..+....+........+.+.....+....+...+.................+.+......+........+..................+...+..........+.....+.........+.+......++++++
krita  | ......+...+...+++++++++++++++++++++++++++++++++++++++*..+++++++++++++++++++++++++++++++++++++++*....+......+.........+......+..+.............+..+...+...+....+.....+..........+..+.+.....+...+......+...................+......+......+..+...+...........................+.......+...........+....+...+......+..+.......+...+....................+.......+......+..+.........+....+....................+.......+.........+...+..+...............+...+.......+.........+.....+..........+..++++++
krita  | -----
krita  | [custom-init] No custom files found, skipping...
krita  | [ls.io-init] done.
krita  | Openbox-Message: Failed to open the display from the DISPLAY environment variable.
krita  | _XSERVTransmkdir: ERROR: euid != 0,directory /tmp/.X11-unix will not be created.
krita  |
krita  | Xvnc KasmVNC 1.3.3 - built Jun 28 2025 19:01:22
krita  | Copyright (C) 1999-2018 KasmVNC Team and many others (see README.me)
krita  | See http://kasmweb.com for information on KasmVNC.
krita  | Underlying X server release 12101014
krita  |
krita  | [mi] mieq: warning: overriding existing handler 0 with 0x5eced9fe3a90 for event 2
krita  | [mi] mieq: warning: overriding existing handler 0 with 0x5eced9fe3a90 for event 3
krita  | 19
krita  | Obt-Message: Xinerama extension is not present on the server
krita  | QStandardPaths: wrong permissions on runtime directory /config/.XDG, 0755 instead of 0700
krita  | QStandardPaths: wrong permissions on runtime directory /config/.XDG, 0755 instead of 0700
krita  | QStandardPaths: wrong permissions on runtime directory /config/.XDG, 0755 instead of 0700
krita  | QStandardPaths: wrong permissions on runtime directory /config/.XDG, 0755 instead of 0700
krita  | QStandardPaths: wrong permissions on runtime directory /config/.XDG, 0755 instead of 0700
krita  | krita.lib.resources: Created table "version_information"
krita  | krita.lib.resources: Created table "storage_types"
krita  | krita.lib.resources: Created table "resource_types"
krita  | krita.lib.resources: Created table "storages"
krita  | krita.lib.resources: Created table "tags"
krita  | krita.lib.resources: Created table "resources"
krita  | krita.lib.resources: Created table "versioned_resources"
krita  | krita.lib.resources: Created table "resource_tags"
krita  | krita.lib.resources: Created table "metadata"
krita  | krita.lib.resources: Created table "tags_storages"
krita  | krita.lib.resources: Created table "tag_translations"

It’s not perfect, but more functional than the k8s hosted instance

/content/images/2025/07/krita-06.png

If I want to save that output to use in something else, i can just save to the config directory

/content/images/2025/07/krita-07.png

and pull it through the native file system mount to WSL

/content/images/2025/07/krita-08.png

and when I’m done for now, I can use ctrl-c in the shell to stop the docker compose service

/content/images/2025/07/krita-09.png

and if i want it removed alltogether I can use docker compose down

builder@LuiGi:~/Workspaces/OSLocal/krita$ docker compose down
[+] Running 2/2
 ✔ Container krita        Removed                                                                                  0.1s
 ✔ Network krita_default  Removed                                                                                  0.3s
builder@LuiGi:~/Workspaces/OSLocal/krita$

Inkscape

This made me realize I could do the same setup for Linuxserver’s Inkscape

Just create the compose file

builder@LuiGi:~/Workspaces/OSLocal/inkscape$ mkdir config
builder@LuiGi:~/Workspaces/OSLocal/inkscape$ cat docker-compose.yaml
services:
  inkscape:
    image: lscr.io/linuxserver/inkscape:latest
    container_name: inkscape
    security_opt:
      - seccomp:unconfined #optional
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/Chicago
    volumes:
      - /home/builder/Workspaces/OSLocal/inkscape/config:/config
    ports:
      - 3000:3000
      - 3001:3001
    restart: unless-stopped

Then fire it up

builder@LuiGi:~/Workspaces/OSLocal/inkscape$ docker compose up
[+] Running 14/14
 ✔ inkscape Pulled                                                                                                17.7s
   ✔ a5e3ea2009e2 Already exists                                                                                   0.0s
   ✔ e1cde46db0e1 Already exists                                                                                   0.0s
   ✔ 46f2d9bbcff7 Already exists                                                                                   0.0s
   ✔ f2d94bf0c7ba Already exists                                                                                   0.0s
   ✔ 0469477658fc Already exists                                                                                   0.0s
   ✔ 35e63de34f77 Already exists                                                                                   0.0s
   ✔ 681cde493f59 Already exists                                                                                   0.0s
   ✔ 63ef96ffaedd Already exists                                                                                   0.0s
   ✔ 1c6d24f55ad9 Already exists                                                                                   0.0s
   ✔ 109b5f323c14 Already exists                                                                                   0.0s
   ✔ fd6c3b0eb1fb Already exists                                                                                   0.0s
   ✔ ff8a5133572d Pull complete                                                                                   11.4s
   ✔ 31ede1d86330 Pull complete                                                                                   11.4s
[+] Running 2/2
 ✔ Network inkscape_default  Created                                                                               0.1s
 ✔ Container inkscape        Created                                                                               0.3s
Attaching to inkscape
inkscape  | [migrations] started
inkscape  | [migrations] no migrations found
inkscape  | ───────────────────────────────────────
inkscape  |
inkscape  |       ██╗     ███████╗██╗ ██████╗
inkscape  |       ██║     ██╔════╝██║██╔═══██╗
inkscape  |       ██║     ███████╗██║██║   ██║
inkscape  |       ██║     ╚════██║██║██║   ██║
inkscape  |       ███████╗███████║██║╚██████╔╝
inkscape  |       ╚══════╝╚══════╝╚═╝ ╚═════╝
inkscape  |
inkscape  |    Brought to you by linuxserver.io
inkscape  | ───────────────────────────────────────
inkscape  |
inkscape  | To support LSIO projects visit:
inkscape  | https://www.linuxserver.io/donate/
inkscape  |
inkscape  | ───────────────────────────────────────
inkscape  | GID/UID
inkscape  | ───────────────────────────────────────
inkscape  |
inkscape  | User UID:    1000
inkscape  | User GID:    1000
inkscape  | ───────────────────────────────────────
inkscape  | ....+++++++++++++++++++++++++++++++++++++++*..+....+.........+..+......+....+........+...+...+++++++++++++++++++++++++++++++++++++++*...+..+...+....+...+......+............+..+...+....+.........+.....+.+.........+..+...+......+...+......+......+....+..+...............+.............+..+...+....+..+....+.........+...........+.......+............+...+..+.++++++
inkscape  | .........+......+..+...+.......+...+..+....+...+..+......+...+..........+..+....+.....+.+...+...............+......+.....................+........+....+++++++++++++++++++++++++++++++++++++++*..+............+.+..+.......+.....+......+......+......+...+.+...+...........+....+...+............+.....+................+..+...+..........+++++++++++++++++++++++++++++++++++++++*.......+.........+.....+.+..+.+..+....+..................+........+...+......+......+.......+.....+...+....+...+.....+.......+...+...+...+...........+.+...+..+...+......+...+.............+...........................+........+....+..............+......+..................+...+...+....+.....+...+.......+...+...+..+...+................+.....+...+...+...+.........+.+.....+......+.+.........+.....+...+.......+.....+...+...+...+.+..................+.....+.+..............+...+....+......+..+...+............+.......+......+...+.........+..+.........+....+..+....+...........+....+..+.............+..+..........+........+.+...+......+.....+.......+.....+............++++++
inkscape  | -----
inkscape  | [custom-init] No custom files found, skipping...
inkscape  | [ls.io-init] done.
inkscape  | Openbox-Message: Failed to open the display from the DISPLAY environment variable.
inkscape  | _XSERVTransmkdir: ERROR: euid != 0,directory /tmp/.X11-unix will not be created.
inkscape  |
inkscape  | Xvnc KasmVNC 1.3.3 - built Jun 28 2025 19:01:22
inkscape  | Copyright (C) 1999-2018 KasmVNC Team and many others (see README.me)
inkscape  | See http://kasmweb.com for information on KasmVNC.
inkscape  | Underlying X server release 12101014
inkscape  |
inkscape  | [mi] mieq: warning: overriding existing handler 0 with 0x58be34f54a90 for event 2
inkscape  | [mi] mieq: warning: overriding existing handler 0 with 0x58be34f54a90 for event 3
inkscape  | 19
inkscape  | Obt-Message: Xinerama extension is not present on the server
inkscape  |
inkscape  | ** (org.inkscape.Inkscape:299): WARNING **: 07:11:35.657: Can't open file: /config/.config/inkscape/cphistory.xml (doesn't exist)
inkscape  |
inkscape  | (org.inkscape.Inkscape:299): Gtk-CRITICAL **: 07:11:37.390: invalid accelerator string ''
inkscape  |
inkscape  | (org.inkscape.Inkscape:299): Gtk-CRITICAL **: 07:11:37.390: gtk_application_accels_get_actions_for_accel: assertion 'accel_key.key != 0' failed
inkscape  |
inkscape  | (org.inkscape.Inkscape:299): Gtk-WARNING **: 07:11:37.394: Unable to parse accelerator '': ignored request to install 1 accelerators

I’m not that good with Inkscape, but here you can see me whip up a image, save and view it

I’ve had bookmarked this InkScape tutorial I wanted to try and now I can.

This made me wonder if I should just try the windows binary

The Windows app does work, but i also had it crash a couple times on me so I would recommend saving often

/content/images/2025/07/inkscape-02.png

Zipline

I had a note in Vikunja to circle back on Zipline which is an Open-Source containerized file server.

They have a docker compose file:

services:
  postgresql:
    image: postgres:16
    restart: unless-stopped
    env_file:
      - .env
    environment:
      POSTGRES_USER: ${POSTGRESQL_USER:-zipline}
      POSTGRES_PASSWORD: ${POSTGRESQL_PASSWORD:?POSTGRESSQL_PASSWORD is required}
      POSTGRES_DB: ${POSTGRESQL_DB:-zipline}
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ['CMD', 'pg_isready', '-U', 'zipline']
      interval: 10s
      timeout: 5s
      retries: 5

  zipline:
    image: ghcr.io/diced/zipline
    ports:
      - '3000:3000'
    env_file:
      - .env
    environment:
      - DATABASE_URL=postgres://${POSTGRESQL_USER:-zipline}:${POSTGRESQL_PASSWORD}@postgresql:5432/${POSTGRESQL_DB:-zipline}
    depends_on:
      postgresql:
        condition: service_healthy
    volumes:
      - './uploads:/zipline/uploads'
      - './public:/zipline/public'
      - './themes:/zipline/themes'
    healthcheck:
      test: ['CMD', 'wget', '-q', '--spider', 'http://localhost:3000/api/healthcheck']
      interval: 15s
      timeout: 2s
      retries: 2

volumes:
  pgdata:

Let’s start with Docker and move from there.

builder@bosgamerz9:~/zipline$ curl -LO https://zipline.diced.sh/docker-compose.yml
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    15    0    15    0     0     47      0 --:--:-- --:--:-- --:--:--    47
100  1117    0  1117    0     0    452      0 --:--:--  0:00:02 --:--:--   970
builder@bosgamerz9:~/zipline$ cat docker-compose.yml 
services:
  postgresql:
    image: postgres:16
    restart: unless-stopped
    env_file:
      - .env
    environment:
      POSTGRES_USER: ${POSTGRESQL_USER:-zipline}
      POSTGRES_PASSWORD: ${POSTGRESQL_PASSWORD:?POSTGRESSQL_PASSWORD is required}
      POSTGRES_DB: ${POSTGRESQL_DB:-zipline}
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ['CMD', 'pg_isready', '-U', 'zipline']
      interval: 10s
      timeout: 5s
      retries: 5

  zipline:
    image: ghcr.io/diced/zipline:latest
    restart: unless-stopped
    ports:
      - '3000:3000'
    env_file:
      - .env
    environment:
      - DATABASE_URL=postgres://${POSTGRESQL_USER:-zipline}:${POSTGRESQL_PASSWORD}@postgresql:5432/${POSTGRESQL_DB:-zipline}
    depends_on:
      postgresql:
        condition: service_healthy
    volumes:
      - './uploads:/zipline/uploads'
      - './public:/zipline/public'
      - './themes:/zipline/themes'
    healthcheck:
      test: ['CMD', 'wget', '-q', '--spider', 'http://0.0.0.0:3000/api/healthcheck']
      interval: 15s
      timeout: 2s
      retries: 2

volumes:
  pgdata:

We can create an .env file with some random secrets

builder@bosgamerz9:~/zipline$ echo "POSTGRESQL_PASSWORD=$(openssl rand -base64 42 | tr -dc A-Za-z0-9 | cut -c -32 | tr -d '\n')" > .env
echo "CORE_SECRET=$(openssl rand -base64 42 | tr -dc A-Za-z0-9 | cut -c -32 | tr -d '\n')" >> .env
builder@bosgamerz9:~/zipline$ cat .env 
POSTGRESQL_PASSWORD=wBxxxxxxxxxxxxxxxxxxxV
CORE_SECRET=Jxxxxxxxxxxxxxxxxxd

I can fire up the containers now

builder@bosgamerz9:~/zipline$ sudo docker compose up -d
[+] Running 34/34
 ✔ zipline Pulled                                                                                                                                 29.9s 
   ✔ f18232174bc9 Already exists                                                                                                                   0.0s 
   ✔ 5056ee185863 Pull complete                                                                                                                    1.9s 
   ✔ 974362762896 Pull complete                                                                                                                    1.9s 
   ✔ 18d8590713a4 Pull complete                                                                                                                    2.0s 
   ✔ 384c3be0b1f5 Pull complete                                                                                                                    2.0s 
   ✔ 0e6f14bf1b1c Pull complete                                                                                                                    2.4s 
   ✔ 44bcba074ba0 Pull complete                                                                                                                    2.4s 
   ✔ e97cf444ba59 Pull complete                                                                                                                    2.4s 
   ✔ fc520afb2f60 Pull complete                                                                                                                    2.4s 
   ✔ ca56b87feb09 Pull complete                                                                                                                    2.5s 
   ✔ 315d2a42fb2c Pull complete                                                                                                                   27.9s 
   ✔ 608a0238234e Pull complete                                                                                                                   28.0s 
   ✔ 36ad4b4ebc78 Pull complete                                                                                                                   28.5s 
   ✔ 8fb31568ddc7 Pull complete                                                                                                                   28.5s 
   ✔ 6da86230782a Pull complete                                                                                                                   28.5s 
   ✔ 6a47961ac2b6 Pull complete                                                                                                                   28.6s 
   ✔ d1298c38b91d Pull complete                                                                                                                   29.0s 
   ✔ 8341e0163493 Pull complete                                                                                                                   29.0s 
 ✔ postgresql Pulled                                                                                                                              10.8s 
   ✔ 3da95a905ed5 Pull complete                                                                                                                    4.8s 
   ✔ 525b0b7a1d26 Pull complete                                                                                                                    4.8s 
   ✔ bfee09e98282 Pull complete                                                                                                                    4.9s 
   ✔ c3f120721a2e Pull complete                                                                                                                    5.2s 
   ✔ 0f750f482557 Pull complete                                                                                                                    5.8s 
   ✔ fc5e0f223019 Pull complete                                                                                                                    6.1s 
   ✔ 94f4e8dd553a Pull complete                                                                                                                    6.3s 
   ✔ b5735d961ce0 Pull complete                                                                                                                    6.6s 
   ✔ ee4088773a9e Pull complete                                                                                                                    9.8s 
   ✔ 3f1ebdb897f5 Pull complete                                                                                                                    9.8s 
   ✔ 10a344c4eea9 Pull complete                                                                                                                    9.8s 
   ✔ 33fda3db53ca Pull complete                                                                                                                    9.8s 
   ✔ 4f5214727328 Pull complete                                                                                                                    9.8s 
   ✔ 73e2aac8af8b Pull complete                                                                                                                    9.8s 
[+] Running 4/4
 ✔ Network zipline_default         Created                                                                                                         0.0s 
 ✔ Volume "zipline_pgdata"         Created                                                                                                         0.0s 
 ✔ Container zipline-postgresql-1  Healthy                                                                                                        11.0s 
 ✔ Container zipline-zipline-1     Started                                                                                                        10.8s

As I’m remote, I’ll want to create a proper HTTPS ingress to reach it

First, I create an A Record

 $  az account set --subscription "Pay-As-You-Go" && az network dns record-set a add-record -g idjdnsrg -z tpk.pw -a 75.73.224.240 -n zipline
{
  "ARecords": [
    {
      "ipv4Address": "75.73.224.240"
    }
  ],
  "TTL": 3600,
  "etag": "9c8ab014-9c0a-4612-9e60-8635514c5733",
  "fqdn": "zipline.tpk.pw.",
  "id": "/subscriptions/d955c0ba-13dc-44cf-a29a-8fed74cbb22d/resourceGroups/idjdnsrg/providers/Microsoft.Network/dnszones/tpk.pw/A/zipline",
  "name": "zipline",
  "provisioningState": "Succeeded",
  "resourceGroup": "idjdnsrg",
  "targetResource": {},
  "trafficManagementProfile": {},
  "type": "Microsoft.Network/dnszones/A"
}

Then a server, endpoint and ingress

$ cat ingress.zipline.yaml

---
apiVersion: v1
kind: Endpoints
metadata:
  name: zipline-external-ip
subsets:
- addresses:
  - ip: 192.168.1.143
  ports:
  - name: zipline
    port: 3000
    protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  name: zipline-external-ip
spec:
  clusterIP: None
  clusterIPs:
  - None
  internalTrafficPolicy: Cluster
  ipFamilies:
  - IPv4
  - IPv6
  ipFamilyPolicy: RequireDualStack
  ports:
  - name: zipline
    port: 80
    protocol: TCP
    targetPort: 3000
  sessionAffinity: None
  type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: azuredns-tpkpw
    ingress.kubernetes.io/ssl-redirect: "true"
    kubernetes.io/ingress.class: nginx
    kubernetes.io/tls-acme: "true"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/proxy-body-size: "0"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
    nginx.org/client-max-body-size: "0"
    nginx.org/proxy-connect-timeout: "3600"
    nginx.org/proxy-read-timeout: "3600"
    nginx.org/websocket-services: zipline-external-ip
  name: zipline-ingress
spec:
  rules:
  - host: zipline.tpk.pw
    http:
      paths:
      - backend:
          service:
            name: zipline-external-ip
            port:
              number: 80
        path: /
        pathType: Prefix
  tls:
  - hosts:
    - zipline.tpk.pw
    secretName: zipline-tls
status:
  loadBalancer: {}

Then apply

$ kubectl apply -f ./ingress.zipline.yaml
endpoints/zipline-external-ip created
service/zipline-external-ip created
Warning: annotation "kubernetes.io/ingress.class" is deprecated, please use 'spec.ingressClassName' instead
ingress.networking.k8s.io/zipline-ingress created

As soon as I saw the cert was valid

$ kubectl get cert zipline-tls
NAME          READY   SECRET        AGE
zipline-tls   True    zipline-tls   87s

I tried the web app

/content/images/2025/07/zipline-02.png

I can now make a super user account

/content/images/2025/07/zipline-03.png

The last step is to click finish

/content/images/2025/07/zipline-04.png

Here I’ll try and upload a Word doc to start

/content/images/2025/07/zipline-05.png

It replies with a link

/content/images/2025/07/zipline-06.png

It did create an anonymous link that worked, albeit renamed the file

/content/images/2025/07/zipline-07.png

Now, I can go to the files and edit the details to set a password

/content/images/2025/07/zipline-08.png

When i try the URL now, it does require a password

/content/images/2025/07/zipline-09.png

If I delete the file, then come back, it shows a 404

/content/images/2025/07/zipline-10.png

In administration, we can make sure our URLs are HTTPS and with the right URL

/content/images/2025/07/zipline-11.png

Now when I upload I see “https” instead of “http”

/content/images/2025/07/zipline-12.png

We can also do things like expiring and number of views

/content/images/2025/07/zipline-13.png

And verified it viewed once then closed. I can say that PDFs show in the browser (but Docx files do download).

Summary

Today we looked at a couple of nice image creation tools, Krita and Inkscape as served up by Linuxserver. While they worked, I did find the latency didn’t make them all that useful. The containerized instances, however, worked nearly as good as the fat clients in windows.

We also looked at Zipline which is a nice small open-source containerized file serving app.

opensource krita inkscape zipline containers docker kubernetes

Have something to add? Feedback? You can use the feedback form

Isaac Johnson

Isaac Johnson

Cloud Solutions Architect

Isaac is a CSA and DevOps engineer who focuses on cloud migrations and devops processes. He also is a dad to three wonderful daughters (hence the references to Princess King sprinkled throughout the blog).

Theme built by C.S. Rhymes