Captain
Captain is an experimental no-installation blog engine written by AI agents.
Features
- No-installation required, single binary distribution
- SQLite database for simple deployment
- Markdown and HTML content support
- Customizable themes
- S3-compatible storage support
Trivia
Captain is an experimental blog engine entirely mostly written by AI models. This project explores the possibilities and limitations of AI-generated software by creating a fully functional blogging platform.
Project Structure
Captain is written in Go and uses:
Quick Start
Docker
- Pull the Docker image:
docker pull ghcr.io/captain-corp/captain:latest
- Run the Docker container with default settings:
docker run --name captain -p 8080:8080 ghcr.io/captain-corp/captain:latest
- Access the admin interface at http://localhost:8080/setup
Docker Compose
- Create a
docker-compose.yml
file with the following content:
version: '3.8'
services:
captain:
image: ghcr.io/captain-corp/captain:latest
ports:
- "8080:8080"
volumes:
- ./data:/data
- Run the Docker Compose setup:
docker-compose up -d
- Access the admin interface at http://localhost:8080/setup
For more details, refer to the Docker documentation.
Installation
From Binary Releases
- Download the latest release for your platform from the releases page
- Extract the archive:
unzip captain-<platform>.zip
- Move the binary to a location in your PATH:
sudo mv captain /usr/local/bin/
- Verify the installation:
captain
From Source
- Ensure you have Go 1.21 or later installed
- Clone the repository:
git clone https://github.com/captain-corp/captain.git
cd captain
- Build and install:
make build
sudo mv dist/captain /usr/local/bin/
Getting Started
When you first run Captain, if no user exists, you'll be guided through a setup wizard to create your first admin user. This ensures you can immediately access the admin interface to start writing.
-
Run Captain:
captain run
Available flags:
-b, --bind
: Address to bind to (overrides config)
-p, --port
: Server port (overrides config)
-i, --init-dev-db
: Initialize development database with test data
-c, --config
: Config file path
Examples:
# Run with default settings
captain run
# Bind to all interfaces on port 3000
captain run -b 0.0.0.0 -p 3000
# Use custom config and initialize test data
captain run -c /path/to/config.yaml -i
-
Follow the setup wizard prompts to create your admin account
-
Access the admin interface at http://localhost:8080/admin
-
Start writing!
Available Make Commands
Build & Run
make build
- Builds the binary in dist/captain
make run
- Builds and runs the server
make dev
- Runs the server in development mode with live reload
make clean
- Removes build artifacts
Docker
make docker-build
- Builds Docker image tagged as captain:latest
make docker-run
- Runs the container and exposes port 8080
To use Docker:
Then open http://localhost:8080 in your browser
Testing & Quality
make test
- Runs all unit tests
make test-coverage
- Generates test coverage report in coverage.html
make lint
- Runs golangci-lint checks
make fmt
- Formats Go code
User Management
make create-user
- Creates a new user interactively
make update-password
- Updates user password
Storage Configuration
Captain supports both local filesystem and S3-compatible storage for media files. You can configure the storage provider in your config.yaml
file.
Local Storage (Default)
Local storage is the default option. Files are stored in the local filesystem.
storage:
provider: "local"
local_path: "./uploads" # Path where files will be stored
S3 Storage
To use S3 or an S3-compatible storage service (like MinIO, DigitalOcean Spaces, etc.):
- Configure your S3 credentials in
config.yaml
:
storage:
provider: "s3"
s3:
bucket: "your-bucket-name"
region: "your-region" # e.g., us-east-1
endpoint: "" # Optional: Custom endpoint for S3-compatible services
access_key: "your-key" # AWS access key
secret_key: "your-secret" # AWS secret key
-
Make sure your S3 bucket has the appropriate permissions:
- The provided AWS credentials should have permissions for:
s3:PutObject
- For uploading files
s3:GetObject
- For retrieving files
s3:DeleteObject
- For deleting files
- If using public access, configure the bucket policy to allow public read access
-
For S3-compatible services:
- Set the
endpoint
field to your service's endpoint URL
- Make sure the
region
matches your service's configuration
Development
Running in Development Mode
For development, you can use the run_dev
command which enables debug mode:
make run_dev
This will:
- Enable Gin's debug mode with detailed request logging
- Set GORM's log level to info for detailed SQL logging
- Display more detailed error messages
You can also:
- Initialize the database with test data using
-i
- Change the bind address with
-b
- Change the port with
-p
Examples:
# Run in dev mode with test data
make run_dev
./dist/bin/captain-darwin-amd64 run -i
# Run on a different port
./dist/bin/captain-darwin-amd64 run -p 3000
# Bind to all interfaces
./dist/bin/captain-darwin-amd64 run -b 0.0.0.0
For production use, use the standard make run
command which disables debug mode.
Configuration
Captain can be configured through environment variables or a YAML configuration file. Environment variables take precedence over the configuration file.
Config File (config.yaml)
The config file can be specified using the -c
flag:
captain run -c /path/to/config.yaml
If the -c
flag is not provided, Captain will look for a config file named config.yaml
in the current directory or in /etc/captain/
.
Here's a complete configuration file with all available options:
# Server Configuration
server:
host: "localhost" # Listen address
port: 8080 # Listen port
# Database Configuration
db:
path: "blog.db" # SQLite database file path
log_level: "warn" # Database log level (silent, error, warn, info)
# Site Configuration
site:
theme: "default-light" # Theme name
secure_cookie: false # Use secure cookies (set to true when serving over HTTPS)
domain: "" # Cookie domain (e.g., "example.com") or empty for current domain
# Storage Configuration
storage:
provider: "local" # Storage provider: "local" or "s3"
local_path: "./media" # Path for local file storage (only for local provider)
# S3 Configuration (only required when provider is "s3")
s3:
bucket: "" # S3 bucket name
region: "" # AWS region (e.g., "us-east-1")
endpoint: "" # Optional: Custom endpoint for S3-compatible services
access_key: "" # S3 access key
secret_key: "" # S3 secret key
# Debug mode
debug: false
Configuration Key |
Description |
Default Value |
Valid Values |
server.host |
Server listen address |
localhost |
Any valid IP or hostname |
server.port |
Server listen port |
8080 |
1-65535 |
db.path |
SQLite database file path |
blog.db |
Any valid file path |
db.log_level |
Database logging verbosity |
warn |
silent , error , warn , info |
site.theme |
Website theme |
"" |
Any installed theme name |
site.secure_cookie |
Use secure cookies |
false |
true , false (set to true when serving over HTTPS) |
site.domain |
Cookie domain |
"" |
Domain name (e.g., "example.com") or empty for current domain |
storage.provider |
Storage provider type |
local |
local , s3 |
storage.local_path |
Local storage path |
./media |
Any valid directory path |
storage.s3.bucket |
S3 bucket name |
"" |
Valid S3 bucket name |
storage.s3.region |
S3 region |
"" |
Valid AWS region (e.g., us-east-1) |
storage.s3.endpoint |
S3 endpoint URL |
"" |
Valid URL for S3-compatible services |
storage.s3.access_key |
S3 access key |
"" |
Valid AWS access key |
storage.s3.secret_key |
S3 secret key |
"" |
Valid AWS secret key |
debug |
Enable debug mode |
false |
true , false |
Note: Site settings such as title, subtitle, timezone, and admin theme can be configured through the admin panel under Settings.
Environment Variables
Variable |
Description |
Default |
Valid Values |
CAPTAIN_DEBUG |
Enable debug mode |
false |
true , false |
CAPTAIN_SERVER_HOST |
Host address to bind to |
localhost |
Any valid IP or hostname |
CAPTAIN_SERVER_PORT |
Port number for the server |
8080 |
1-65535 |
CAPTAIN_DB_PATH |
SQLite database file location |
blog.db |
Any valid file path |
CAPTAIN_DB_LOG_LEVEL |
Database logging verbosity |
warn |
silent , error , warn , info |
CAPTAIN_STORAGE_PROVIDER |
Storage provider type |
local |
local , s3 |
CAPTAIN_STORAGE_PATH |
Local storage path |
./uploads |
Any valid directory path |
CAPTAIN_SITE_SECURE_COOKIE |
Use secure cookies |
false |
true , false (set to true when serving over HTTPS) |
CAPTAIN_SITE_DOMAIN |
Cookie domain |
"" |
Domain name (e.g., "example.com") or empty for current domain |
CAPTAIN_S3_BUCKET |
S3 bucket name |
"" |
Valid S3 bucket name |
CAPTAIN_S3_REGION |
S3 region |
"" |
Valid AWS region (e.g., us-east-1) |
CAPTAIN_S3_ENDPOINT |
S3 endpoint URL |
"" |
Valid URL for S3-compatible services |
CAPTAIN_S3_ACCESS_KEY |
S3 access key |
"" |
Valid AWS access key |
CAPTAIN_S3_SECRET_KEY |
S3 secret key |
"" |
Valid AWS secret key |
CAPTAIN_SITE_THEME |
Website theme name |
"" |
Any installed theme name |
Debug Mode
When CAPTAIN_DEBUG
is set to true
:
- Gin framework runs in debug mode with detailed logging
- GORM database logging is set to info level
- More detailed error messages are displayed
For production use, keep debug mode disabled.
Themes
Captain supports customizable themes for the public site. The admin interface maintains a consistent look regardless of the website theme selected.
Default Theme
When site.theme
is empty (""
), Captain uses its embedded default theme.
Custom Themes
To use a custom theme:
- Create a directory in
themes/
with your theme name (e.g., themes/mytheme/
)
- Add the required theme files:
themes/mytheme/
├── templates/
│ ├── header.tmpl
│ ├── footer.tmpl
│ ├── login.tmpl
│ ├── page.tmpl
│ ├── post.tmpl
│ ├── posts.tmpl
│ └── tag_posts.tmpl
│
└── static/
├── css/
│ └── main.css
└── js/
└── main.js
- Set
site.theme: "mytheme"
in your config.yaml or CAPTAIN_SITE_THEME=mytheme
Custom themes can override any of the default templates and provide their own static assets.
Version Management
Captain uses semantic versioning. You can check the current version by running:
captain version
To bump the version, use one of the following make commands:
make bump-major
- Bump major version (x.0.0)
make bump-minor
- Bump minor version (0.x.0)
make bump-patch
- Bump patch version (0.0.x)
Each version bump will:
- Update the version in version.go
- Create a git commit with the version change
- Create a git tag for the new version
Contributing
This project is an AI-first experiment. While all contributions are welcome, we encourage:
- Using AI assistants (like GitHub Copilot) for code generation
- Documenting AI-human collaboration in pull requests
- Sharing insights about AI-assisted development
For detailed contribution guidelines, including our branch naming convention and pull request process, please see our CONTRIBUTING.md file.