Skip to main content

[July 2026] Comparing Generative AI Models (Claude, GPT, Gemini, Grok, DeepSeek, Kimi, GLM, Mistral)

OpenRouter lets you switch between all sorts of AIs, from closed models like Claude, GPT, and Gemini to open-weight models coming out of China. Even so, it's easy to get stuck on "which one should I actually pick?", so this time I did a rough comparison of the price and performance of the major models.

What do "open" and "closed" even mean here

  • Closed: Models like Claude, GPT, Gemini, and Grok, where the internals (weights) aren't published. You can only use them through the company's servers.
  • Open-weight: Models like DeepSeek, Kimi, GLM, and Mistral, where the internals are published, so anyone can run them on their own PC or cloud.

Pricing by weight class

Let's start with pricing for the heaviest class.

Pro class pricing comparison

As you can see, Claude Fable 5 is overwhelmingly expensive (output $50/1M tokens), while DeepSeek V4 Pro's output is just $0.87. Even though both are labeled "Pro," the price gap is more than 50x. It's immediately obvious that the open camp (green labels) is cheaper across the board.

Let's also look at the mid and light classes.

Mid class pricing comparison Nano class pricing comparison

Down at the light class, GPT-5 nano comes in at $0.40 for output — practically "unlimited use" territory. For simple classification tasks or draft generation, this class is often more than enough.

Looking at cost-performance

Just looking at price, you might assume "the cheap models must be weaker too" — but that's not really the case. Ignoring weight classes for a moment, here's a single chart combining 20 models that have both pricing and Intelligence Index scores available. I tried to include as many models as possible, open and closed alike, across GPT, Gemini, Qwen, Llama, Gemma, Mistral, and more.

Cost vs. performance scatter plot (all models)

The vertical axis is the "Intelligence Index," an overall capability score (more on this later). The dotted "cost-performance frontier" line is formed by seven models spanning the Nano, Mid, and Pro classes: Gemma 3 27B → DeepSeek V4 Flash → DeepSeek V4 Pro → Kimi K2.6 → Gemini 3.1 Pro → Claude Opus 4.8 → Claude Fable 5. DeepSeek V4 Pro, at just $0.87 for output, comes close to matching Gemini 3.1 Pro's ($12.00) score, putting it a clear step ahead as the effective starting point for cost-efficiency. Meanwhile, models sitting inside the frontier — Qwen3.7 Max, MiniMax M3, GLM 5.2, Claude Sonnet 5, Gemini 3 Flash, Grok 4.20, Claude Haiku 4.5, Gemini 3.1 Flash-Lite, Qwen3-Coder, Mistral Large 3, Llama 4 Maverick, and Llama 4 Scout — all underperform relative to other models in their price range.

If cost-efficiency is your priority, it's worth starting from the cheapest end of the frontier.

So which model is actually the smartest

Let's also look at the rankings for overall capability and coding ability.

Overall benchmark: Artificial Analysis Intelligence Index Coding capability: SWE-bench Verified

The first chart, "overall capability," is the score from a third-party benchmark organization called the Artificial Analysis Intelligence Index. The second, "coding ability," is the score on SWE-bench Verified, a test that measures how many real-world software bug-fix tasks a model can solve. Both are figures measured and published by independent external evaluation sites, not self-reported by the model vendors.

On overall capability, Claude Fable 5 takes the top spot, about 5 points ahead of GPT-5.5, with Claude Opus 4.8, GPT-5.5, and Gemini 3.1 Pro close behind. On coding specifically, Claude Fable 5 pulls clearly ahead with a 95% score. Interestingly, right below it, the open-weight DeepSeek V4 Pro holds its own against the closed-model pack.

Bonus: how big are open models "under the hood"

Since open-weight models publish their internals, you can also see their parameter count (the model's size). In the bar charts, the dark green portion is the "activated parameters" actually used during inference, while the light green is the rest of the experts that sit unused at any given moment under the MoE (Mixture of Experts) architecture.

Parameter counts of open-weight models

DeepSeek V4 Pro is the largest at 1.6 trillion total parameters, but only 49 billion of those are actually used at inference time (thanks to the MoE mechanism). Being huge while still running light is the whole point. Notably, Gemma 3 27B is the only model in the chart with a fully dark-green bar, because it's not MoE — it's a "dense" architecture that uses all its parameters every time. For dense models, total parameters equal active parameters, so keep in mind that size comparisons against MoE models carry a slightly different meaning.

Conclusion: which one should you pick

  • Just want the smartest option available → Claude Fable 5 or Claude Opus 4.8 (brace for the price)
  • Cost-efficiency focused, but still want good coding → DeepSeek V4 Pro (dirt cheap yet quite capable)
  • A well-balanced everyday model → Claude Sonnet 5 or Gemini 3 Flash
  • Want to process huge volumes as cheaply as possible → GPT-5 nano or DeepSeek V4 Flash

Both pricing and rankings move fast in this world, so before you actually use any of these, don't forget to check the latest info at openrouter.ai/models.

Sources for the scores

The benchmark scores used in this post come from the following sources. Both are figures measured and published by third-party evaluation sites independent of the model vendors.

Note that the SWE-bench Verified scores for Kimi K2.6 / Qwen3.7 Max vary somewhat across sources, so they're treated here as reference values only.

Using GLM-5.2 / GLM-4.7-Flash Models with Claude Code

The Claude Code CLI (claude) isn't limited to Anthropic's own models. By using the Anthropic Messages API-compatible endpoint (the "Anthropic Skin") provided by OpenRouter, you can run any model as the backend. This time I tried a setup that assigns z-ai/glm-5.2 as the main conversation model and z-ai/glm-4.7-flash for lightweight background tasks such as title generation, and I'm summarizing how to do it here.

Reference: https://openrouter.ai/docs/cookbook/coding-agents/claude-code-integration

Prerequisites

  • $env:OPENROUTER_API_KEY must already be set to your OpenRouter API key.
  • Even if you're logged into Claude Code with a claude.ai account, authentication via environment variables takes priority when present. In that case a warning ⚠ claude.ai connectors are disabled ... appears, but it doesn't affect operation.

Required Environment Variables

VariableValueNotes
ANTHROPIC_BASE_URLhttps://openrouter.ai/apiOpenRouter's Anthropic-compatible endpoint
ANTHROPIC_AUTH_TOKENYour OpenRouter API keySent as Authorization: Bearer
ANTHROPIC_API_KEY"" (explicitly empty string)If unset or non-empty, authentication methods conflict and cause an error
ANTHROPIC_MODELz-ai/glm-5.2The main conversation model. Specify the OpenRouter model ID as-is
ANTHROPIC_SMALL_FAST_MODELz-ai/glm-4.7-flashSub-model for lightweight background tasks such as title generation

Distinguishing Main and Sub Models

ANTHROPIC_MODEL only controls the main conversation model. The lightweight, fast sub-model that Claude Code uses internally for things like title generation and auto-mode detection is specified via ANTHROPIC_SMALL_FAST_MODEL. Setting this variable alone reliably switches the model used for lightweight tasks.

Setup Methods

Configure the following in the repository's .claude/settings.local.json.

{
"env": {
"ANTHROPIC_BASE_URL": "https://openrouter.ai/api",
"ANTHROPIC_API_KEY": "",
"ANTHROPIC_MODEL": "z-ai/glm-5.2",
"ANTHROPIC_SMALL_FAST_MODEL": "z-ai/glm-4.7-flash"
}
}

Don't write ANTHROPIC_AUTH_TOKEN (a secret) into the file — supply it from the shell side via OPENROUTER_API_KEY instead. Add the following once to your PowerShell profile ($PROFILE) and it will be set automatically every time you open a shell afterward.

$env:ANTHROPIC_AUTH_TOKEN = $env:OPENROUTER_API_KEY

For bash/zsh, add this to ~/.bashrc or ~/.zshrc:

export ANTHROPIC_AUTH_TOKEN="$OPENROUTER_API_KEY"

With this in place, running claude -p "..." inside this directory automatically loads the settings from .claude/settings.local.json, and both the main and sub models are used via OpenRouter. Running Claude Code in other projects is unaffected.

Method B: Switch temporarily for a specific command only

If you don't want to modify your shell profile, specify the environment variables inline when running the command.

PowerShell:

$env:ANTHROPIC_BASE_URL = "https://openrouter.ai/api"
$env:ANTHROPIC_AUTH_TOKEN = $env:OPENROUTER_API_KEY
$env:ANTHROPIC_API_KEY = ""
$env:ANTHROPIC_MODEL = "z-ai/glm-5.2"
$env:ANTHROPIC_SMALL_FAST_MODEL = "z-ai/glm-4.7-flash"
claude -p "1+1は?"

bash:

ANTHROPIC_BASE_URL="https://openrouter.ai/api" \
ANTHROPIC_AUTH_TOKEN="$OPENROUTER_API_KEY" \
ANTHROPIC_API_KEY="" \
ANTHROPIC_MODEL="z-ai/glm-5.2" \
ANTHROPIC_SMALL_FAST_MODEL="z-ai/glm-4.7-flash" \
claude -p "1+1は?"

Persisting the above variables as Windows user environment variables makes OpenRouter/GLM the default in every terminal and project. However, this also affects operations in other projects where you intend to use regular Claude (Anthropic), so Method A/B is recommended unless you actually want to change the global default unintentionally.

Verification

I confirmed with the following command that z-ai/glm-5.2 is recorded in the response and in the billing log (modelUsage).

claude -p "Reply with exactly: OK-GLM-TEST" --output-format json
{
"result": "OK-GLM-TEST",
"modelUsage": {
"z-ai/glm-5.2": { "inputTokens": 3272, "outputTokens": 8, "costUSD": 0.028336 }
}
}

Also, running a slightly longer prompt with --debug all confirmed that dispatching to both the main model and the sub model actually occurs.

[API:timing] dispatching to firstParty model=z-ai/glm-4.7-flash
[API:timing] dispatching to firstParty model=z-ai/glm-5.2

For a single prompt, the lightweight task correctly goes to z-ai/glm-4.7-flash and the main response correctly goes to z-ai/glm-5.2 — the models are being used properly.

Known Caveat: Request Proliferation in Interactive Sessions

In an interactive claude session (whether opened from VS Code or launched directly in a TTY), even light input resulted in 13 API calls being recorded within the same minute in OpenRouter's Activity log. Of those, 12 were small calls to the sub model (GLM 4.7 Flash), and only the last one was the main response from the main model (GLM 5.2). Total cost stayed around $0.0094.

On the other hand, I confirmed that a single run via claude -p (non-interactive, print mode) barely causes this proliferation. If you want to keep costs down, using -p is safer. If you regularly use interactive sessions, it's a good idea to set ANTHROPIC_SMALL_FAST_MODEL to route requests to a cheap model while monitoring usage on OpenRouter's Activity dashboard.

Troubleshooting

  • The warning ⚠ claude.ai connectors are disabled because ANTHROPIC_API_KEY or another auth source is set... can be ignored (it only disables claude.ai's connector feature; the API calls themselves still succeed).
  • Leaving ANTHROPIC_API_KEY unset instead of an empty string can make the authentication method ambiguous and cause an error. Always explicitly set it to "".
  • To switch to a different model, just change ANTHROPIC_MODEL to the model ID on OpenRouter (e.g. anthropic/claude-opus-4-8, openai/gpt-5, etc.).
  • Tool search optimization (ENABLE_TOOL_SEARCH) is disabled by default on non-Anthropic hosts. Add ENABLE_TOOL_SEARCH=true if you need it.

I Built “llmglot” an LLM API Translation Proxy That Connects Claude Code, Codex, and Gemini

In AI development, people are increasingly struggling more with API specification differences than with the models themselves.

Claude Code uses the Anthropic Messages API. OpenAI-based tools use the Chat Completions API or the Responses API. Gemini has its own proprietary API, and local LLM environments such as Ollama and LM Studio provide OpenAI-compatible APIs.

Even when the model you want exists, you may not be able to connect to it because the API specifications differ. You need to rewrite SDKs, implement translation layers, and separate configurations for each environment.

llmglot is the tool that solves these problems.

GitHub: https://github.com/Himeyama/llmglot

What is llmglot?

llmglot is a proxy server that converts multiple LLM APIs back and forth.

It accepts Anthropic Messages API, OpenAI Responses API, OpenAI Chat Completions API, Gemini API, and more, then appropriately converts and forwards them to the upstream API.

In other words, even if the API specification required by the client does not match the API specification of the model you actually want to use, you can still use it.

Supported Scope

On the client side, it supports:

  • Claude Code
  • Anthropic SDK
  • OpenAI SDK
  • Responses API clients
  • Gemini SDK

On the upstream side, it can connect to:

  • Ollama
  • LM Studio
  • OpenAI
  • Gemini
  • OpenRouter
  • Azure OpenAI
  • vLLM

For example, it enables connections such as:

  • Claude Code → Ollama
  • OpenAI SDK → Gemini
  • Responses API → Chat Completions API

Connecting Claude Code to a Local LLM

One use case for llmglot is connecting Claude Code to a local LLM.

For example, if you are using Ollama, start it with:

CHAT_BASE_URL=http://localhost:11434/v1 llmglot

Then simply change Claude Code’s connection target to llmglot, and you can use a local LLM from Claude Code.

Being able to try a code agent without using an expensive API is extremely appealing.

(Note: Ollama actually supports the Messages API, so a proxy is not really necessary.)

Supports the Responses API Too

Recently, more and more tools have been using the Responses API.

llmglot implements the /v1/responses endpoint and supports not only HTTP but also WebSocket.

That makes it easy to connect with Responses API-based clients such as the Codex CLI.

Useful Logging Features

llmglot includes a log display feature.

The information you can check includes:

  • Model name
  • Provider
  • Input token count
  • Output token count
  • Cache usage
  • Estimated cost
  • Generation speed

In environments where multiple LLMs are used, the benefit of centrally managing usage information is significant.

Differences from LiteLLM

At this point, the question is: how is this different from LiteLLM?

Both are software that sits between LLMs, but the direction they aim for is very different.

LiteLLM’s Approach

LiteLLM unifies many LLM providers into OpenAI format.

In other words:

App

LiteLLM

Each LLM provider

You could say it is a mechanism for application developers to use a unified API.

llmglot’s Approach

llmglot, on the other hand, is structured like this:

Claude Code
Codex CLI
Gemini SDK

llmglot

Each LLM provider

Its goal is to translate the client-side API specification.

Comparing with Claude Code

Claude Code uses the Anthropic Messages API.

LiteLLM is basically centered on OpenAI-compatible APIs, so connecting Claude Code directly is difficult.

llmglot, on the other hand, accepts the Anthropic Messages API directly.

That means the following configuration is possible:

Claude Code

llmglot

Ollama

This is a very major feature of llmglot.

Which Should You Choose?

LiteLLM is a good fit for:

  • People developing AI applications
  • People who want to use the OpenAI SDK as a unified interface
  • People who want load balancing or fallback

llmglot is a good fit for:

  • People who want to run Claude Code with a different model
  • People who want to use local LLMs from existing clients
  • People who want to convert the Responses API to another API
  • People who do not want to rewrite SDKs

Conclusion

In the LLM world, API differences are becoming a bigger problem than the models themselves.

You want to use Claude Code, but with Ollama. You want to use the OpenAI SDK, but with Gemini. Demands like these will likely continue to grow.

llmglot sits in the middle and absorbs the differences in API specifications.

  • Claude Code → Ollama
  • OpenAI SDK → Gemini
  • Responses API → Chat Completions API
  • Gemini API → OpenAI-compatible API

If LiteLLM is a “unified API for developers,” llmglot could be described as a “client-compatible proxy.”

What is Coreutils for Windows

In June 2026, Microsoft officially released Coreutils for Windows.

winget install Microsoft.Coreutils

The Microsoft.Coreutils package installed with this command is an official Microsoft project that enables UNIX-style commands commonly used on Linux and macOS—such as ls, cp, rm, and cat—to run natively on Windows.

This article summarizes the project overview, supported commands, limitations, and differences from WSL and PowerShell.

Overview

Microsoft.Coreutils is a set of command-line tools for Windows maintained by Microsoft.

Internally, it is built on:

  • uutils/coreutils
  • findutils
  • grep

and implemented in Rust.

Microsoft describes the project’s goal as:

reducing friction for developers who move between Linux, macOS, WSL, containers, and Windows

Installation

It can be installed easily from WinGet.

winget install Microsoft.Coreutils

WinGet is the package manager built into Windows, and it can automatically download and install the specified package.

After installation, it can be used as ordinary commands.

ls
cat file.txt
grep keyword log.txt
cp source.txt backup.txt

Main Available Commands

Representative commands are as follows.

CategoryExample Commands
File listingls
File copycp
File movemv
File deletionrm
Display contentscat
Working directorypwd
Create directorymkdir
Sleepsleep
Pipe processingtee
Searchgrep, find

If you are a Linux user, you can use familiar commands as they are.

PowerShell Collision Issues

This is the biggest point of caution!

PowerShell already has aliases and built-in commands with the same names.

Examples:

CommandIssue
lsConflicts with a PowerShell alias
cpConflicts with Copy-Item
catConflicts with Get-Content
rmConflicts with Remove-Item
pwdConflicts with Get-Location

Therefore, even if you run:

ls

it does not necessarily invoke the Coreutils version.

Microsoft recommends using PowerShell 7.4 or later.

Windows-Specific Limitations

Although it aims for Linux compatibility, there are limitations due to Windows internals.

1. No POSIX Signals

Linux’s mechanisms for:

kill
SIGTERM
SIGKILL

do not exist on Windows.

Therefore,

kill
timeout

are not provided at this time.

2. No /dev/null

Linux:

grep error log.txt > /dev/null

Windows:

grep error log.txt > NUL

will be used instead.

3. Differences Between ACL and POSIX Permissions

Windows uses ACL-based permission management.

Therefore, commands such as:

chmod
chown
chgrp

are not provided.


Reading is possible, but creating new ones requires:

  • Developer Mode
  • Administrator privileges

Main Commands Not Provided

Microsoft intentionally excludes some commands.

Those that conflict with Windows

  • dir
  • more
  • paste
  • whoami
  • expand

Those with strong POSIX dependencies

  • chmod
  • chown
  • chgrp
  • chroot
  • nohup
  • stty
  • tty
  • who

Not yet implemented at this time

  • kill
  • timeout
  • dd

Differences from WSL

A common comparison is with WSL (Windows Subsystem for Linux).

ItemMicrosoft.CoreutilsWSL
Installation costVery lowRequires setting up a Linux environment
Startup speedNativeHas a virtualized layer
Linux compatibilityPartialVery high
Bash environmentNoneAvailable
apt usageNot possiblePossible
Shell script compatibilityLimitedHigh

WSL is “Linux itself,” whereas Coreutils is “a toolset for using Linux-style commands on Windows.”

Recommendation for Makefile

Background and Problem Awareness

In daily work, when automating data transformation with Python scripts, you often run into the following issues:

  • Only part of the source data has been updated, but you end up rerunning everything and wasting time.
  • It is unclear which steps depend on which files, making execution order and missed steps hard to manage.
  • It is difficult to tell which outputs will be affected when a script changes.

A Makefile is a tool that natively provides "dependencies" and "incremental rebuilds" (rerunning only the changed parts), and can solve these issues with just a small amount of notation.

Basics of Make

  • Target: the artifact to be generated (e.g. output/report.csv)
  • Dependencies: the files required for generation (e.g. data/clean/*.csv and scripts)
  • Recipe: the command used to generate it (e.g. python scripts/aggregate.py ...)

Make runs the recipe only when the dependencies are newer than the target. This automatically reruns only the necessary parts when source data or Python scripts are updated.

Minimal Makefile Example

The following is an example of incrementally processing raw data, cleaning it, and generating an aggregate report.

# Makefile
SHELL := bash
.SHELLFLAGS := -eu -o pipefail -c
.DELETE_ON_ERROR:
.ONESHELL:
.DEFAULT_GOAL := all

RAW_DIR := data/raw
CLEAN_DIR := data/clean
OUT_DIR := output

RAW := $(wildcard $(RAW_DIR)/*.csv)
CLEAN := $(patsubst $(RAW_DIR)/%.csv,$(CLEAN_DIR)/%.csv,$(RAW))
REPORT := $(OUT_DIR)/report.csv

# Directories are order-only dependencies (they are created if missing, but not used for rebuild checks)
$(CLEAN_DIR) $(OUT_DIR):
mkdir -p $@

# The aggregate report depends on the cleaned CSVs and the aggregation script
$(REPORT): $(CLEAN) scripts/aggregate.py | $(OUT_DIR)
python scripts/aggregate.py -i $(CLEAN_DIR) -o $@

# Generate the corresponding clean CSV from each raw CSV
$(CLEAN_DIR)/%.csv: $(RAW_DIR)/%.csv scripts/clean.py | $(CLEAN_DIR)
python scripts/clean.py -i $< -o $@

.PHONY: all clean status

all: $(REPORT)

clean:
rm -rf $(CLEAN_DIR) $(OUT_DIR)

# Helper to check what will be rebuilt
status:
@echo "RAW : $(RAW)"
@echo "CLEAN : $(CLEAN)"
@echo "REPORT: $(REPORT)"
@echo
@echo "Dry-run (what would run):"
@$(MAKE) -n all

With this structure, the following becomes possible:

  • When data/raw/foo.csv is updated, only the corresponding data/clean/foo.csv is regenerated.
  • When scripts/clean.py is updated, only the cleaning steps that are needed are rerun.
  • When scripts/aggregate.py is updated, only the aggregate report is rerun.

How It Works

# First run (generate everything)
make -j

# Part of the raw data is updated (only that file's cleaning and the report are rerun)
touch data/raw/a.csv
make -j

# The cleaning script is updated (all cleaning steps and the report are rerun)
touch scripts/clean.py
make -j

# The aggregation script is updated (only the report is rerun)
make

To check in advance what will run, make -n is useful.

Guidelines for Designing Script Dependencies

  • For each rule, it is important to explicitly list the Python script it directly invokes as a dependency.
  • If you split code across multiple modules, include in the dependencies the modules imported by the target rule so that changes propagate correctly. A simple approach is to collect all Python files in the relevant directory into a variable and add them to the dependencies.

Example (simple approach):

PY_SRCS := $(wildcard scripts/**/*.py) $(wildcard scripts/*.py)

$(CLEAN_DIR)/%.csv: $(RAW_DIR)/%.csv $(PY_SRCS) | $(CLEAN_DIR)
python scripts/clean.py -i $< -o $@

Parallel Execution and Speedup

  • make -j can parallelize independent file transformations. The more data points you have, the more effective this becomes.
  • The more finely you split intermediate outputs, the more effective incremental builds become, avoiding full recomputation.
  • If I/O is the bottleneck, combine this with compressed formats, file partitioning, or a local SSD.

Practical Tips for Production Use

  • Treat directory creation as an order-only dependency (| dir) to avoid unnecessary rebuilds.
  • Enable .DELETE_ON_ERROR so incomplete outputs are not left behind on failure.
  • Standardize the common entry point with .DEFAULT_GOAL := all so that make works out of the box.
  • For debugging, use make -n (show without running), make --trace (show why something runs), and make -d (verbose logs).
  • Use .PHONY: clean for cleanup, and be careful to delete only generated artifacts.

Virtual Environments and Dependencies (Optional)

Python execution environments can also be managed with Make.

VENV := .venv
PY := $(VENV)/bin/python

$(VENV)/bin/python: requirements.txt
python3 -m venv $(VENV)
$(VENV)/bin/pip install -r requirements.txt
touch $@

# Use $(PY) in subsequent recipes
$(CLEAN_DIR)/%.csv: $(RAW_DIR)/%.csv scripts/clean.py | $(CLEAN_DIR) $(VENV)/bin/python
$(PY) scripts/clean.py -i $< -o $@

$(REPORT): $(CLEAN) scripts/aggregate.py | $(OUT_DIR) $(VENV)/bin/python
$(PY) scripts/aggregate.py -i $(CLEAN_DIR) -o $@

If requirements.txt is updated, only the necessary portion will be set up again.

Summary

  • A Makefile is a tool that automates "explicit dependencies" and "incremental rebuilds," greatly improving the reliability and development speed of data transformation pipelines.
  • By correctly linking source data, scripts, and generated outputs, and by splitting processing into smaller steps, only the affected scope of updates is quickly recomputed.
  • With minimal notation, you get reproducibility, parallelization, and observability, making everyday automation work much more comfortable.

Assigned a Custom Domain to a Subpath on Sakura Server with Cloudflare Workers

Background

Sakura’s rental server "Lite Plan" offers an incredibly low price of 121 yen per month for a 36-month lump sum payment (165 yen per month for a 12-month lump sum). It's sufficient for hosting static files and CGI purposes, making it easy to use as personal storage.

However, the assigned domain will be a subdomain of username.sakura.ne.jp, so some ingenuity is required if you want to associate your custom domain with a specific path.

What I Want to Achieve

When accessing https://app.example.com, the content from https://sakurauser.sakura.ne.jp/app/ should be displayed without changing the URL.

Why Simple DNS Settings Won't Work

DNS CNAME records can only specify hostnames, and URLs that include paths like /app/ cannot be specified.

While it can be achieved using a redirect (301), the URL in the browser's address bar would change to sakurauser.sakura.ne.jp/flower/.

Using transparent proxy with Cloudflare Workers allows the URL to remain as app.example.com.

Prerequisites

  • You must be registered with a custom domain on Cloudflare (e.g., example.com)
  • A free plan on Cloudflare is acceptable (up to 100,000 requests per day for free)

Steps

1. Create a Worker

  1. Cloudflare Dashboard → Workers & PagesCreate
  2. Select Start with Hello World!
  3. Enter the Worker name (e.g., storage-proxy)
  4. Click Deploy

2. Edit the Code

After deploying, click Edit code and replace all with the following code.

export default {
async fetch(request) {
const url = new URL(request.url);
const target = new URL("https://sakurauser.sakura.ne.jp");
target.pathname = "/app" + url.pathname;
target.search = url.search;

const newRequest = new Request(target.toString(), {
method: request.method,
headers: request.headers,
body: request.body,
});

const response = await fetch(newRequest);

const newHeaders = new Headers(response.headers);
newHeaders.delete("content-security-policy");
newHeaders.delete("x-frame-options");

return new Response(response.body, {
status: response.status,
headers: newHeaders,
});
}
};

Summary

  • Sakura's rental server Lite Plan is 121 yen per month and can sufficiently serve as a storage for static files.
  • However, assigning a custom domain to a subpath is not possible with standard DNS settings.
  • By using Cloudflare Workers as a transparent proxy, you can deliver content without changing the URL.
  • The Workers' code is only a few dozen lines, and it operates within the limits of the Cloudflare free plan.

Why "Multiples of 8" Are the Standard for Spacing in CSS

In modern UI design, the rule of setting "spacing in multiples of 8" is commonly used. This is not just a convention, but an empirical rule supported by the mathematical consistency of screen density, typography, and scale.

Addressing Various Screen Densities

Modern displays have pixel ratios such as 1x, 1.5x, 2x, 3x, and 4x.

Value1x1.5x2x3x4x
8 px812162432
5 px57.5 ⚠️101520

Since 8 is divisible into integers for many scales, it minimizes blurring caused by subpixel rendering. Using values like 5 px can generate fractions like 7.5 px in a 1.5x environment, leading to inaccurate rendering.

Compatibility with Typography

The default font size in browsers is 16 px (= 8 × 2). Line height is typically 1.5 times that, which equals 24 px (= 8 × 3).

By setting spacing in multiples of 8, the rhythm of the text can visually align more easily. The height of headings and body text matches the spacing grid, creating a well-organized vertical rhythm.

Ease of Creating Design Tokens

--space-1: 8px;
--space-2: 16px;
--space-3: 24px;
--space-4: 32px;

The scale is simple, making it easy for designers and engineers to utilize as a common language. Material Design and Tailwind CSS also adopt this philosophy.

When a designer specifies "space-3," the engineer can confidently apply 24px. A consistent naming convention reduces the communication cost during code reviews.

The Option of a 4 px Base

For UIs that require finer adjustments, a 4 px base (4, 8, 12, 16...) is also common. Tailwind CSS adopts a default 4 px base (p-1 = 4px).

The 4 px base is a subset of the 8 px base, so both can coexist without contradiction. It is effective to use 4 px units for small spacings within components, while using 8 px units for larger spacings between sections.

Conclusion

The reasons for using multiples of 8 as the standard for spacing can be summarized in three points:

  1. Addressing Screen Density: It divides into integers across many pixel ratios, preventing subpixel blurriness.
  2. Consistency with Typography: Aligns with the default font size (16 px) and line height (24 px), creating a vertical rhythm.
  3. Consistency in Scale: A simple token system serves as a common language for designers and engineers.

New Feature: Mount S3 Buckets to EC2 Using Amazon S3 Files

Amazon S3 Files is a service that allows you to directly mount S3 buckets as an NFS file system on compute resources such as EC2. Data remains stored in S3 while enabling typical file operations (ls, cp, cat, etc.) for reading and writing.

What is S3 Files?

S3 Files is a shared file system built on Amazon EFS, providing file system access to data stored in S3 buckets.

Key features include:

ItemDescription
ProtocolNFS 4.1 / 4.2
Supported ComputeEC2, Lambda, ECS, EKS
Concurrent ConnectionsUp to 25,000 compute resources
Read ThroughputUp to TB/second
IOPSOver 10 million / bucket
EncryptionTLS (in transit) + AWS KMS (at rest)
File System FeaturesPOSIX permissions, file locking, read-after-write consistency

How It Works

S3 Files automatically loads accessed data to high-performance storage and provides it with low latency.

  • Small Files (default less than 128 KB): Read directly from high-performance storage
  • Large Files (1 MB and above): Stream directly from S3
  • Writing: Write to high-performance storage and automatically sync to S3

Data on high-performance storage is automatically deleted after a certain period of inactivity (default 30 days, configurable from 1 to 365 days).

Prerequisites

  • AWS Account
  • EC2 Instance (Linux)
  • S3 Bucket (in the same region as EC2)
  • Two IAM Roles
    • For creating the file system: Permissions to read/write to the S3 bucket
    • For the EC2 instance: Attach the AmazonS3FilesClientFullAccess managed policy
  • Security Group: Allow communication on NFS port 2049

Creating IAM Roles

Two IAM roles are required for S3 Files.

1. Role for Creating File Systems

Automatically created when using the management console, so this step is not necessary

This is the role that allows S3 Files to access the bucket.

# Create role
aws iam create-role \
--role-name S3Files-FileSystem-Role \
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "Service": "s3files.amazonaws.com" },
"Action": "sts:AssumeRole"
}
]
}'

# Attach S3 Files client policy
aws iam attach-role-policy \
--role-name S3Files-FileSystem-Role \
--policy-arn arn:aws:iam::aws:policy/AmazonS3FilesClientFullAccess

Specify this role with --role-arn when creating the file system.

2. Role for EC2 Instance

Failure to attach the IAM role will result in mount failure

Create the following role in CloudShell.

# Create role
aws iam create-role \
--role-name EC2-S3Files-Role \
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "Service": "ec2.amazonaws.com" },
"Action": "sts:AssumeRole"
}
]
}'

# Attach S3 Files client policy
aws iam attach-role-policy \
--role-name EC2-S3Files-Role \
--policy-arn arn:aws:iam::aws:policy/AmazonS3FilesClientFullAccess

# Create and attach instance profile
aws iam create-instance-profile \
--instance-profile-name EC2-S3Files-Profile

aws iam add-role-to-instance-profile \
--instance-profile-name EC2-S3Files-Profile \
--role-name EC2-S3Files-Role

Attach this role to the instance.

Setup Steps

1. Prepare the S3 Bucket

Create a general-purpose bucket in the S3 console. You can also use an existing bucket.

However, versioning must be enabled for the bucket.

2. Create the File System

If Creating from the Console

alt text

  1. Select the bucket in the S3 console
  2. Click on the "File Systems" tab → then click "Create File System"

Creating from the console automatically creates mount targets and access points in all AZs.

alt text

  1. Specify the prefix and VPC, and click "Create File System."

Record the output file system ID (e.g., fs-0123456789abcdef0).

3. Mount on the Instance

In the terminal, execute the following:

# Create mount point
sudo mkdir /mnt/s3files

# Mount
sudo mount -t s3files fs-0123456789abcdef0:/ /mnt/s3files
note

If the mount fails, execute the following command and retry.

sudo dnf install -y amazon-efs-utils # Amazon Linux, RHEL
# sudo apt install -y amazon-efs-utils (Ubuntu, Debian)
note

If there is connectivity issue when executing the dnf command, set up an S3 endpoint (gateway) and assign it to the same AZ as the instance.

Ensure that the route table for the S3 endpoint matches the subnet where the instance is located.

To verify the mount:

df -h /mnt/s3files

You should see output similar to the following:

Filesystem Size Used Avail Use% Mounted on
<s3files-dns> 8.0E 129M 8.0E 1% /mnt/s3files

4. Perform Functionality Checks

cd /mnt/s3files

# Create a file
sudo sh -c 'echo "Hello, s3 Files!" > test.txt'

# Read the file
cat test.txt

# Create a directory
sudo mkdir test-directory

ls -la

# Copy the file
sudo cp test.txt test-directory/

cd test-directory/

# Check the file list
ls -la

The file you wrote will sync to the S3 bucket in about one minute. You can verify that the object has been created in the S3 console.

aws s3 ls s3://<bucket-name>/

Setting Up Auto-Mount

To maintain the mount after a reboot, add the following line to /etc/fstab.

# Add to /etc/fstab
fs-0123456789abcdef0:/ /mnt/s3files s3files _netdev,nofail 0 0

_netdev is an option that ensures the mount occurs after the network connection is established and is required. Adding nofail prevents the instance from becoming unbootable in the event of mount failure.

Pricing

The pricing for S3 Files is composed of the following components:

  • High-Performance Storage Usage: The storage fees for data on the file system
  • File System Access Fees: Read and write operations to high-performance storage
  • S3 Request Fees: Only the S3 GET charges apply when reading files over 1 MB directly from S3

It operates on a usage-based pricing model with no provisioning required, and according to AWS, it can achieve cost savings of up to 90% compared to traditional data copying between S3 and file systems.

Summary

  • S3 Files allows you to mount S3 buckets as an NFS file system on EC2
  • Data remains stored in S3 while enabling typical file operations like ls, cat, and cp
  • Low latency is achieved through caching on high-performance storage, and data that goes unused is automatically evicted
  • Configuring auto-mount using /etc/fstab ensures persistence after a reboot

References