Root cause per QA on palette-dev (merge d402113): splitLines() joined
.codeline spans with '\n'; under white-space:pre-wrap each newline text
node between display:block spans rendered as its own extra visual row,
while renumber() counted gutter rows only from span heights — numbers
drifted up one row per wrapped line. Join with '' (spans are blocks).
Also: in the <=640px media query, .gutter { font-size: 15px } overrode
the paste-view gutter size while .code switched to 13px, so gutline rows
were ~36.7px vs 22.1px code rows at narrow widths — every number below
line 1 drifted. Scope the paste-view gutter to the code font size.
Verified with headless Chromium DOM geometry (desktop 1400x900 and
mobile 375x812): gutter number tops equal their .codeline tops for
lines wrapping to 2-3 rows, wrap OFF numbering unchanged
('1\n2\n3\n4\n5'), no horizontal scroll.
Palette
Palette is a fast, self-hosted pastebin. One Go binary, a SQLite database, and a web UI for sharing text and small files
Note
✨ This project was built by AI — GLM 5.3 Flash on the Hermes Agent harness, with a human in the loop.
Features
- Multiple files in one paste
- Password protected pastes
- Expir after a specified time
- Burn after a number of views
- Custom URLs
- Syntax highlighting with language auto-detection (go-enry)
- Local cookie based submission history
- Cookie based settings
- Themes!
Screenshots
![]() |
![]() |
![]() |
![]() |
Get Started
Docker
docker run -p 8080:8080 -v palette-data:/data git.archfox.org/poslop/palette
The SQLite database lives in the /data volume inside the container.
Docker Compose
See docker-compose.yml for a ready-to-use example with every environment variable documented, including which are required (only the /data volume) and which are optional.
Build from source
Requires Go 1.27+.
go build -o palette ./cmd/palette
./palette
# open http://localhost:8080
Configuration
| Setting | Default | Description |
|---|---|---|
PALETTE_ADDR |
:8080 |
Listen address |
PALETTE_DB |
palette.db |
SQLite database path |
PALETTE_MAX_TEXT |
5242880 |
Max paste size in bytes (5 MB) |
PALETTE_MAX_ITEM |
26214400 |
Max can item size in bytes (25 MB) |
PALETTE_ADMIN_KEY |
generated | Admin key; if unset a 32-char hex key is generated and persisted to <db-dir>/admin-key (0600) |
PALETTE_DEFAULT_DARK |
dark on | Default dark mode for new visitors. Set false, 0, or off to default to light mode. Visitors who toggle dark mode keep their choice in their browser. |
An /admin page exists for runtime settings, protected by a key set at
install (PALETTE_ADMIN_KEY env var) and resettable locally — see
API and the design docs in the wiki for details.
API
Full REST API: wiki/API. One example:
curl -X POST http://localhost:8080/api/pastes -d '{"content":"hello"}'
Design docs: wiki/design (e2e encryption, attachments & storage, cookie preferences).
License
Palette is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0-only). See LICENSE.
The software is provided AS IS, without warranty of any kind, express or implied, including merchantability and fitness for a particular purpose. In no event shall the authors be liable for any claim, damages, or other liability, including without limitation any security vulnerabilities, data loss, or legal issues arising from use of the software. You use it at your own risk.
If you run a modified version of Palette as a network service, the AGPL requires you to offer your modified source code to its users.



