# picosh/pico: SSH Publishing and Self-Hosting

> picosh/pico provides managed static hosting, tunnels, pipes, blog publishing, feed notifications, and snippet sharing through SSH file-transfer tools. Its Go codebase also contains a self-hosting stack built from service-specific containers, PostgreSQL, Valkey, and Caddy configuration.

**picosh/pico** — The ultimate ssh powered services for developers

- Repository: https://github.com/picosh/pico
- Website: https://pico.sh
- Stars: 1,348 · Forks: 47
- Language: Go
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/picosh-pico

## Why picosh/pico Uses SSH as Its Publishing Interface

picosh/pico addresses a narrow but common developer problem: publishing small pieces of content without installing a separate command-line client or building a conventional web application deployment pipeline. Its managed services accept content through tools already present on many systems, including rsync, scp, sftp, and ssh itself. The intended users are developers who are comfortable moving files over SSH and want static sites, development tunnels, short-lived messages, blog posts, RSS email reports, or shared patches without a larger management interface.

The same repository contains implementation code for the hosted platform and components used to operate it. The module is named `github.com/picosh/pico`, is written in Go, and declares Go 1.27 in `go.mod`. The services are divided into pairs named through commands such as `cmd/${APP}/web` and `cmd/${APP}/ssh`. That separation reflects the product design: one binary presents the web-facing application, while another handles the SSH protocol and command interaction.

## The File-to-Service Data Flow Behind Pico's Managed Tools

Pico maps standard SSH and file-transfer operations onto different managed products. Static sites use rsync to copy a local `public` directory into a remote path under `pgs.sh`. Blogs and feed definitions use scp, while snippets can be piped directly into an SSH command. The remote service interprets the destination or command parameters, stores the uploaded content, and serves it through the corresponding Pico endpoint.

This approach keeps the client side small, but it does not make Pico a generic SSH file server. The accepted paths and subcommands are service-specific. `pgs.sh:/mysite/` means static site deployment, `prose.sh:/` means a blog article upload, and `pastes.sh changes.patch` stores standard output as a named paste. The tunnel service is different again because it initiates a reverse SSH connection rather than accepting a file.

The repository layout also indicates a separated web and SSH architecture. The Dockerfile builds a `${APP}-web` binary and a `${APP}-ssh` binary from separate command directories, then places each in its own scratch-based release image. The Compose file defines matching `*-web` and `*-ssh` containers for pastes, pipe, prose, and pgs. This allows protocol handling and HTTP presentation to scale or fail as separate processes, although it also means self-hosters must operate more than a single binary.

## Publishing a First Pico Static Site with rsync

The README does not provide a local installation procedure for the managed client because the managed service is reached with existing SSH tools. It directs new users to the getting-started documentation at `https://pico.sh/getting-started`. Assuming that setup has established the required account and SSH access, a first static deployment can copy the contents of a local `public` directory to the assigned remote site path.

The documented command is:

```bash
rsync -rv ./public/ pgs.sh:/mysite/
```

The trailing slash on `./public/` means the command transfers the directory contents rather than creating an additional nested `public` directory. Pico assigns the uploaded site a URL in the form shown by the README: `https://{user}-mysite.pgs.sh`. It also states that TLS is handled for generated addresses and custom domains. The README does not document custom-domain DNS records, rollback behavior, build commands, or what happens when a deployment removes or replaces files, so those points require confirmation in the external documentation before production adoption.

## Tunnels, Pipes, Posts, Pastes, and Feeds Share SSH

A localhost web server can be exposed through the documented reverse tunnel command:

```bash
ssh -R dev:80:localhost:8000 tuns.sh
```

Here, the remote port `80` is associated with `localhost:8000`, and the README says the local server becomes available at `https://dev.tuns.sh`. This is useful for temporary development access, but the README does not define authentication details, idle expiry, concurrency limits, connection recovery, or protection against an unintended public endpoint.

The pipe service follows a publisher and subscriber model. One terminal subscribes to a topic:

```bash
ssh pipe.pico.sh sub mytopic
```

Another publishes a line through standard input:

```bash
echo "Hello world!" | ssh pipe.pico.sh pub mytopic
```

The README states that the subscriber receives `Hello world!`. Blogs use file upload. After creating `hello-world.md`, the documented upload is:

```bash
scp hello-world.md prose.sh:/
```

The resulting article path is shown as `https://{user}.prose.sh/hello-world`. Snippets take the shortest client path:

```bash
git diff | ssh pastes.sh changes.patch
```

The feed service accepts a cron schedule and RSS URLs in a file uploaded with scp to `feeds.pico.sh:/`. Its README example runs at 13:00 daily and reports matches by email. These examples show that Pico favors common Unix workflows over a dedicated publishing API, although each product retains its own naming, destination, and output rules.

## Self-Deploying pico Requires an Operational Service Graph

The repository includes `SELFHOST.md`, multiple Dockerfiles, a `docker-compose.yml`, a production Compose file, Caddy configuration, and SQL files. However, the README does not document the self-hosting commands or required deployment settings, so no installation command can be reproduced safely from it.

The Compose file shows that self-hosting is broader than launching one Pico process. Optional profiles select `postgres`, `valkey`, image processing, logging, and individual services. PostgreSQL 14 and Valkey 9.0 Alpine are defined under database profiles. Service containers use published images such as `ghcr.io/picosh/pico/pastes-web:latest` and `ghcr.io/picosh/pico/pastes-ssh:latest`. The repeated `latest` tags mean an operator cannot infer a fixed deployed version from the Compose file alone.

Configuration introduces another layer. `.env.example` includes `DATABASE_URL`, `POSTGRES_PASSWORD`, `CF_API_TOKEN`, `PICO_SECRET`, image proxy settings, service-specific Caddy file paths, IP addresses, SSH and web ports, domains, and debug flags. Several example values are placeholders. It also declares `PICO_SECRET` twice, which makes the file an illustrative template rather than a turnkey production configuration. The presence of these files supports self-hosting, but it does not establish that a new operator can complete setup from the README alone.

## Limits of SSH-Native Publishing and Conventional Hosting

Pico's SSH-native design removes the need for Pico-specific upload software, but it depends on remote SSH endpoints, remote path conventions, DNS-backed URLs, and TLS behavior. A local firewall, an SSH client without the required transfer command, or an organization that blocks direct SSH access can prevent the documented workflow even though rsync or scp is generally available.

The static hosting example also does not document build hooks. Pico accepts files from `public`, so a user whose site needs compilation must perform that step before rsync. The repository layout suggests a larger application platform for self-hosters, but that does not make it equivalent to a full deployment framework. The README does not establish rollback, release selection, database migration procedures, backup policy, or secret rotation guidance.

The clearest alternative is a conventional web host configured for SFTP or rsync. That approach still uses SSH file transfer, but it gives the operator control over the web server, filesystem, domain configuration, retention, and build pipeline. Pico instead centralizes those hosted-service details behind service-specific Pico hosts. Self-hosted Pico is the more relevant comparison for infrastructure teams: it offers a Go implementation and Compose-oriented service graph, while a single conventional server or platform exposes less service orchestration but generally presents a smaller operational surface.

## License, Releases, and Upgrade Work for pico Operators

The repository declares the MIT license. That permits use, modification, distribution, and sublicensing subject to the license text, but this review does not interpret how a particular deployment must comply with third-party component licenses. The Go dependency list and container images introduce separate dependency and image licensing questions that should be checked independently.

The last push was on 2026-10-14, and releases `v4.1.0`, `v4.1.1`, and `v4.1.2` were published on 2026-10-11 and 2026-10-12. This is a recent release sequence, but the documentation does not provide upgrade notes, schema migration commands, compatibility guarantees, or a documented rollback path. The self-hosting Compose file also uses `latest` images rather than pinning the shown releases to a version tag.

For managed users, server upgrades occur outside the local repository. For self-hosters, upgrade work includes reviewing release changes, replacing container images, preserving environment secrets, applying any database or storage changes, and validating Caddy routing. None of those procedures can be claimed without additional release or `SELFHOST.md` documentation.

## Conclusion

picosh/pico fits developers who already prefer SSH, rsync, scp, and sftp for publishing. It is a poor fit for users who need documented one-command self-hosting or who cannot depend on SSH endpoints and DNS-backed Pico services. Before adoption, verify the current getting-started requirements at https://pico.sh/getting-started, then confirm the service, domain, and storage assumptions needed for the specific use case.

## FAQ

### How do I publish a static site with picosh/pico?

The README shows using rsync to upload the contents of `./public/` to `pgs.sh:/mysite/`. It states that TLS is handled for the generated Pico URL and for custom domains.

### Can picosh/pico expose a localhost development server?

Yes, the documented tunnel command uses `ssh -R dev:80:localhost:8000 tuns.sh`. The README says the service is then available at `https://dev.tuns.sh`.

### What operating system dependencies does picosh/pico require?

The README does not specify a supported operating system matrix. The managed examples use standard tools such as `ssh`, `rsync`, and `scp`, while the self-hosting files use Docker services, but no complete client compatibility table is supplied.

## Sources

- [License: MIT](https://github.com/picosh/pico/blob/main/LICENSE)
- [picosh/pico on GitHub](https://github.com/picosh/pico)
- [Project website](https://pico.sh)
- [README](https://github.com/picosh/pico/blob/main/README.md)
- [Releases](https://github.com/picosh/pico/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/picosh-pico
