Category: Linux

Claude on Incus – All the autonomy, securely

Here's claude-on-incus (or coi for short) - a tool for running Claude Code freely in isolated Incus containers.

If it's useful to you, a star helps.

Note: I'm also working on "code-on-incus" - a generalized version for running any AI coding assistant in isolated containers.

Why?

Three reasons: security, a clean host, and full contextual environments.

Security

Claude Code inherits your entire shell environment. Your SSH keys, git credentials, .env files with API tokens - everything. You either click "Allow" hundreds of times per session, or use --dangerously-skip-permissions and hope nothing goes wrong.

With coi, Claude runs in complete isolation. Your host credentials stay on the host. Claude can't leak what Claude can't see.

What remains exposed: The Claude API token must be present inside the container, and your mounted workspace files are accessible. A malicious or compromised model could theoretically exfiltrate these over the network. Network filtering to restrict outbound connections is under development.

Clean host, full capabilities

Claude loves installing things. Different Node versions, Python packages, Docker images, random build tools. On bare metal, this clutters your system with dependencies you may actually not need.

With coi, Claude can install and run whatever the task requires - without any of it touching your host. Need a specific Ruby version for one project? A Rust toolchain for another? Let Claude set it up in the container. Keep it if useful, throw it away if not.

VM-like isolation, Docker-like speed. Containers start in ~2 seconds.

Contextual environments

Each project can have its own persistent container with Claude's installed context and setup. Your web project has Node 20 and React tools. Your data project has Python 3.11 with pandas and jupyter. Your embedded project has cross-compilers and debugging tools.

Claude remembers what it installed and configured - per project, completely isolated from each other.

Why Incus over Docker?

Claude often needs to run Docker itself. Docker-in-Docker is a mess - you either bind-mount the host socket (defeating isolation) or run privileged mode (no security). Incus runs system containers where Docker works natively without hacks.

Incus also handles UID mapping automatically. No more chown after every session.

Quick start

# Install (or build from sources if you prefer)
curl -fsSL https://raw.githubusercontent.com/mensfeld/claude-on-incus/master/install.sh | bash

# Build image (first time only)
coi build

# Start coding
cd your-project
coi shell

Features And Capabilities

  • Multi-slot sessions - Run parallel Claude instances for different tasks. Each slot has its own isolated home directory, so files don't leak between sessions.
coi shell --slot 1  # Frontend work
coi shell --slot 2  # API debugging
  • Session resume - Stop working, come back tomorrow, pick up where you left off with full conversation history. Sessions are workspace-scoped, so you'll never accidentally resume a conversation from a different project:
coi shell --resume
  • Persistent containers - By default, containers are ephemeral but your workspace files always persist. Enable persistence to also keep your installed tools between sessions:
coi shell --persistent
  • Detachable sessions - All sessions run in tmux, allowing you to detach from running work and reattach later without losing progress. Your code analysis or long-running task continues in the background:
# Detach: Press Ctrl+b d
# Reattach to running session
coi attach

The "dangerous" flags are much safer now

Claude Code's --dangerously-skip-permissions flag has that name for good reason when running on bare metal. Inside a coi container, the threat model changes completely:

Risk Bare metal Inside coi
SSH key exposure Yes No - keys not mounted
Git credential theft Yes No - credentials not present
Environment variable leaks Yes No - host env not inherited
Docker socket access Yes No - separate Docker daemon
Host filesystem access Full Only mounted workspace

The "dangerous" flags give Claude full autonomy to work efficiently. The container isolation ensures that autonomy can't be weaponized against you.

Summary

coi gives you secure, isolated Claude Code sessions that don't pollute your host. Install anything, experiment freely, keep what works, discard what doesn't.

The project is MIT licensed on GitHub.

Synology DSM 6.2 Photo Station 6 – Failed to Load Data Fix

I'm a quite happy Synology user. For the past years I've been using it mostly to backup my things, so I didn't pay much of an attention to the fact, that the Photo Station software would get slower and slower up to the point when I would end up with "Failed to load data" message each time I would access it.

Some articles suggested that you have to drop and re-create the media indexing database to fix it. However, this won't help you in the long run. Your Photo Station 6 database will become bloated once again after a while.

The reason, why Photo Station 6 gets slower and slower, is the fact that Synology, for any crazy reason disabled the PostgreSQL AutoVacuum functionality. Vacuuming is suppose to keep your database in a good state

How to fix that once and for all? You need to enable the PostgreSQL AUTOVACUUM and for an immediate effect, you should also run the vacuuming manually.

SSH into your server and then:

sudo su
cd /volume1/@database/pgsql
vim postgresql.conf

Within the postgresql.conf file replace (or add if they don't not exist) following settings:

wal_buffers =128MB
autovacuum = on
checkpoint_segments = 10

save, exit the file and reboot.

If you want to run vacuuming manually, log in into the PostgreSQL console:

psql -U postgres

List available databases:

postgres=# \l
                                       List of databases
    Name     |           Owner            | Encoding  | Collate | Ctype |   Access privileges   
-------------+----------------------------+-----------+---------+-------+-----------------------
 mediaserver | MediaIndex                 | SQL_ASCII | C       | C     | 
 ong         | SynologyApplicationService | SQL_ASCII | C       | C     | 
 photo       | PhotoStation               | SQL_ASCII | C       | C     | 
 postgres    | postgres                   | SQL_ASCII | C       | C     | 
 synosnmp    | postgres                   | SQL_ASCII | C       | C     | 
 template0   | postgres                   | SQL_ASCII | C       | C     | =c/postgres          +
             |                            |           |         |       | postgres=CTc/postgres
 template1   | postgres                   | SQL_ASCII | C       | C     | postgres=CTc/postgres+
             |                            |           |         |       | =c/postgres

Connect to the photo DB:

postgres=# \c photo;
You are now connected to database "photo" as user "postgres".

Check the tables size by running the following query:

SELECT nspname || '.' || relname AS "relation",
    pg_size_pretty(pg_total_relation_size(C.oid)) AS "total_size"
  FROM pg_class C
  LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
  WHERE nspname NOT IN ('pg_catalog', 'information_schema')
    AND C.relkind <> 'i'
    AND nspname !~ '^pg_toast'
  ORDER BY pg_total_relation_size(C.oid) DESC
  LIMIT 5;
       relation       | total_size 
----------------------+------------
 public.photo_image   | 1097 MB
 public.photo_log     | 5912 kB
 public.video_convert | 936 kB
 public.photo_share   | 928 kB
 public.video         | 864 kB
(5 rows)

and the potential vacuuming candidate should be obvious by now:

photo=# vacuum full public.photo_image;
VACUUM

Re-run the size checking query again just to see 93% size reduction of the images table:

       relation       | total_size 
----------------------+------------
 public.photo_image   | 72 MB
 public.photo_log     | 5912 kB
 public.video_convert | 936 kB
 public.photo_share   | 928 kB
 public.video         | 864 kB
(5 rows)

After that, everything will work blazing fast!

Copyright © 2026 Closer to Code

Theme by Anders NorenUp ↑