PHP library to create a server or a client for the gemini protocol
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Richard Dern dfa39cc2e6 Initial commit 2 months ago
bin Initial commit 2 months ago
examples Initial commit 2 months ago
src Initial commit 2 months ago
tests Initial commit 2 months ago
.gitignore Initial commit 2 months ago
.php_cs Initial commit 2 months ago
LICENSE Initial commit 2 months ago Initial commit 2 months ago
composer.json Initial commit 2 months ago
composer.lock Initial commit 2 months ago


php-gemini is a library implementing the Project Gemini protocol, as both client and server-side.


composer require richarddern/php-gemini

Common features

  • Supports TLS from both client and server-side, thanks to react/socket
  • A script is included to generate your own self-signed certificate in case you don't or can't use an official one
  • URIs are parsed, validated, and resolved, so you can use relative URIs as well, thanks to league/uri
  • Extensive logging, thanks to monolog
  • Filesystem abstraction provided by league/flysystem allowing you to serve files from various locations



To query a remote server, you first need to instanciate the Client class:

use RichardDern\Gemini\Client;

// This will connect to a server running on the same computer
$client = new Client();

// This will connect to a remote server on default port
//$client = new Client('');

// And this will connect to a server using a custom port
//$client = new Client('', 1966);

// You can define the server and remote port after instanciating the class,
// or whenever you want before your query:

You are ready to query the server:

// You can define the base URI that will be used to resolve subsequent
// relative queries

// This will then resolve to 
// gemini://

// Or, you can request an absolute URI directly:

The result will be a RichardDern\Gemini\Response object which exposes the following properties:

  • $status, a two-digits status code ; you can see the full list of status codes in Gemini's specifications, Appendix 1
  • $meta, containing various informations about the response such as MIME type, redirect URL or language, depending on server's response
  • $body, the raw, unformated content of response body


This library also allows you to run a Gemini server with ease.

use RichardDern\Gemini\Server;

// This will create a server on and listening on default port (1965)
$server = new Server();

// You can set the binding address and port when instanciating the class...
//$server = new Server('[::1]', 1966);

// ...or after

You are required to provide the server with the path to a certificate file prior to actually start the server.


You can use the provided bin/generate-self-signed-certificate.php file.

php ./bin/generate-self-signed-certificate.php > localhost.pem

This implementation support basic directory indexing, but you need to enable it manually.


This implementation allows you to serve files from various file systems, including the local file system as well as a FTP server, or even in-memory file system. Please look at the league/flysystem documentation to find out which adapters you can use.

Unless specified otherwise, the server will use the LocalFilesystemAdapter, and will look for files in a www folder located where you launched the server from.

However, you can use a different adapter if you want:

// Serving files on Gemini from a FTP site
$adapter = new League\Flysystem\Ftp\FtpAdapter(
    // Connection options
        'host' => 'hostname', // required
        'root' => '/root/path/', // required
        'username' => 'username', // required
        'password' => 'password', // required
        'port' => 21


You can then start your server:


You will need to use a process manager to ensure your server is kept running. You could use systemd or supervisor to do this. The documentation will soon be updated with some examples.


Both client and server use the same methods to configure logging. You should set up logging to fit your needs right after you instanciated the client or the server.

$client = new Client();

// You can define the log level

// Here, we will define a simple StreamHandler, but we will choose where to log
$handler = new StreamHandler('/var/log/gemini.log', Logger::INFO);

// The channel will help you find your way into the logs


Richard Dern -




  • Ergol - Can use one cert per vhost, supports HTTP delivery with CSS