Skip to content

Instantly share code, notes, and snippets.

@wraybowling
Last active October 9, 2025 15:41
Show Gist options
  • Select an option

  • Save wraybowling/37eeb2408bc94dccf3eede54518ba5d0 to your computer and use it in GitHub Desktop.

Select an option

Save wraybowling/37eeb2408bc94dccf3eede54518ba5d0 to your computer and use it in GitHub Desktop.
Raspbery Pi Print Server

Raspberry Pi Print Servers in 2025

The Raspberry Pi 2B I bought many years ago has lived many lives. It's been a video game console, a media center, a synthesizer, and in its most dutiful incarnation a print server. I am cheap and decided I did not want a newer 64-bit Pi. This one should do fine, right? ... Right? Well not without headaches. This is an adaptation of a haxor.no article but updated to reflect changes present in the Bookworm and Trixie releases of Debian/Armbian/PiOS.

MicroSD Card

The card selected must be 8GB or higher and from a quality brand. That's all I'll say. Do your own research on why this is true. Knockoff SD cards are known to fail. You get what you pay for, basically.

Initial Setup

After flashing the SD card with a fresh Pi OS, the package configuration blue screen will appear.

Keyboard Layout

Setting the Keyboard layout correctly is more important than you might think, else you'll have a lot of trouble typing the " character later on.

Username

Don't use the default username of "pi" like we did in the old days. Newer versions of PiOS isntead force you to create a username of your own. This is a good thing.

Password

You'll have a chance to type in a password and confirm that you didn't mess it up. Put this in a password manager like KeePass.

WiFi

The first login is complete, and the next obvious step is to set up WiFi. Every WiFi documentation article out there is wrong since the release of Bookworm. The correct tool to use is nmtui. Run it and begin setup

Radio

This is where you turn on the WiFi antenna. In my case, The 2B did not come with an antenna of its own and I use a tiny USB 2.4GHz WiFi thingy. That's what it's officially called, yes. If you don't see this option, it means your version of PiOS is too old. Trash it and start over. I wasted a lot of time after an apt upgrade to an older install which didn't have the radio option for some reason. If this happens to you, don't waste any more time; just trash the OS and start fresh.

Hostname

For my print server I like to set the name to printypi to let myself know this is the Pi meant for printing. It will save a little bit of time later on too.

Activate Connection

I chose the WiFi SSID from a scanned list. This is pretty easy! The first time connecting, it will take a second and then prompt for the password like you'd expect. if all goes well, you're online.

Enable SSH

Run sudo raspi-config to set up SSH.

  • Interface Options
  • SSH
  • Yes

Reboot To Confirm

After running sudo reboot the cloud-init-network.service should show all your connections and at the end of all the text report My IP address is 192.168.x.xxx.

Log in again and you should see <username>@printypi:~$

Switch to The Big Computer

The rest of the guide will be done from SSH.

Confirm the hostname works

Ensure you're on the same WiFi SSID and then try this:

ping printypi.local

Press Ctrl+C when you've seen a few packets send successfully.

Send over your SSH Key

Set up the Pi with your public SSH key. This isn't just about avoiding trying in your password. Ansible will need this.

ssh-copy-id <username>@printypi.local

Setting Up Ansible

Most other guides will drag you through a lot more things to type in...but not this one! We're going to automate the rest of set-up with Redhat Ansible. This will be awesome especially because if you find any mistakes or necessary changes that this guide doesn't cover after I publish it, updating the playbook will automatically remove unnecessary bits and add necessary bits cleanly.

Upstall Ansible Controller

Version mismatches may cause the next steps to fail. You can check with ansible --version if you've already got it. Version 2.14 or lower isn't high enough for Trixie. To install/upgrade ansible to the newest version:

pip install --user ansible

Edit the inventory.yml file

Change the ansible_user field to use the pi user name

Run The Playbook

To convert your Pi into a print server just run the following which will install and configure cups

ansible-playbook -i inventory.yml printypi.yml
#
# Configuration file for the CUPS scheduler. See "man cupsd.conf" for a
# complete description of this file.
#
# Log general information in error_log - change "warn" to "debug"
# for troubleshooting...
LogLevel warn
PageLogFormat
# Specifies the maximum size of the log files before they are rotated. The value "0" disables log rotation.
MaxLogSize 0
# Default error policy for printers
ErrorPolicy retry-job
# Only listen for connections from the local machine.
Listen localhost:631
Listen /run/cups/cups.sock
# Show shared printers on the local network.
Browsing On
BrowseLocalProtocols dnssd
DefaultShared Yes
# Default authentication type, when authentication is required...
DefaultAuthType Basic
# Web interface setting...
WebInterface Yes
# Timeout after cupsd exits if idle (applied only if cupsd runs on-demand - with -l)
IdleExitTimeout 60
# Restrict access to the server...
<Location />
Order allow,deny
Allow @LOCAL
</Location>
# Restrict access to the admin pages...
<Location /admin>
AuthType Default
Require user @SYSTEM
Order allow,deny
</Location>
# Restrict access to configuration files...
<Location /admin/conf>
AuthType Default
Require user @SYSTEM
Order allow,deny
</Location>
# Restrict access to log files...
<Location /admin/log>
AuthType Default
Require user @SYSTEM
Order allow,deny
</Location>
# Set the default printer/job policies...
<Policy default>
# Job/subscription privacy...
JobPrivateAccess default
JobPrivateValues default
SubscriptionPrivateAccess default
SubscriptionPrivateValues default
# Job-related operations must be done by the owner or an administrator...
<Limit Create-Job Print-Job Print-URI Validate-Job>
Order deny,allow
</Limit>
<Limit Send-Document Send-URI Hold-Job Release-Job Restart-Job Purge-Jobs Set-Job-Attributes Create-Job-Subscription Renew-Subscription Cancel-Subscription Get-Notifications Reprocess-Job Cancel-Current-Job Suspend-Current-Job Resume-Job Cancel-My-Jobs Close-Job CUPS-Move-Job>
Require user @OWNER @SYSTEM
Order deny,allow
</Limit>
<Limit CUPS-Get-Document>
AuthType Default
Require user @OWNER @SYSTEM
Order deny,allow
</Limit>
# All administration operations require an administrator to authenticate...
<Limit CUPS-Add-Modify-Printer CUPS-Delete-Printer CUPS-Add-Modify-Class CUPS-Delete-Class CUPS-Set-Default CUPS-Get-Devices>
AuthType Default
Require user @SYSTEM
Order deny,allow
</Limit>
# All printer operations require a printer operator to authenticate...
<Limit Pause-Printer Resume-Printer Enable-Printer Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After Cancel-Jobs CUPS-Accept-Jobs CUPS-Reject-Jobs>
AuthType Default
Require user @SYSTEM
Order deny,allow
</Limit>
# Only the owner or an administrator can cancel or authenticate a job...
<Limit Cancel-Job>
Require user @OWNER @SYSTEM
Order deny,allow
</Limit>
<Limit CUPS-Authenticate-Job>
AuthType Default
Require user @OWNER @SYSTEM
Order deny,allow
</Limit>
<Limit All>
Order deny,allow
</Limit>
</Policy>
# Set the authenticated printer/job policies...
<Policy authenticated>
# Job/subscription privacy...
JobPrivateAccess default
JobPrivateValues default
SubscriptionPrivateAccess default
SubscriptionPrivateValues default
# Job-related operations must be done by the owner or an administrator...
<Limit Create-Job Print-Job Print-URI Validate-Job>
AuthType Default
Order deny,allow
</Limit>
<Limit Send-Document Send-URI Hold-Job Release-Job Restart-Job Purge-Jobs Set-Job-Attributes Create-Job-Subscription Renew-Subscription Cancel-Subscription Get-Notifications Reprocess-Job Cancel-Current-Job Suspend-Current-Job Resume-Job Cancel-My-Jobs Close-Job CUPS-Move-Job CUPS-Get-Document>
AuthType Default
Require user @OWNER @SYSTEM
Order deny,allow
</Limit>
# All administration operations require an administrator to authenticate...
<Limit CUPS-Add-Modify-Printer CUPS-Delete-Printer CUPS-Add-Modify-Class CUPS-Delete-Class CUPS-Set-Default>
AuthType Default
Require user @SYSTEM
Order deny,allow
</Limit>
# All printer operations require a printer operator to authenticate...
<Limit Pause-Printer Resume-Printer Enable-Printer Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After Cancel-Jobs CUPS-Accept-Jobs CUPS-Reject-Jobs>
AuthType Default
Require user @SYSTEM
Order deny,allow
</Limit>
# Only the owner or an administrator can cancel or authenticate a job...
<Limit Cancel-Job CUPS-Authenticate-Job>
AuthType Default
Require user @OWNER @SYSTEM
Order deny,allow
</Limit>
<Limit All>
Order deny,allow
</Limit>
</Policy>
# Set the kerberized printer/job policies...
<Policy kerberos>
# Job/subscription privacy...
JobPrivateAccess default
JobPrivateValues default
SubscriptionPrivateAccess default
SubscriptionPrivateValues default
# Job-related operations must be done by the owner or an administrator...
<Limit Create-Job Print-Job Print-URI Validate-Job>
AuthType Negotiate
Order deny,allow
</Limit>
<Limit Send-Document Send-URI Hold-Job Release-Job Restart-Job Purge-Jobs Set-Job-Attributes Create-Job-Subscription Renew-Subscription Cancel-Subscription Get-Notifications Reprocess-Job Cancel-Current-Job Suspend-Current-Job Resume-Job Cancel-My-Jobs Close-Job CUPS-Move-Job CUPS-Get-Document>
AuthType Negotiate
Require user @OWNER @SYSTEM
Order deny,allow
</Limit>
# All administration operations require an administrator to authenticate...
<Limit CUPS-Add-Modify-Printer CUPS-Delete-Printer CUPS-Add-Modify-Class CUPS-Delete-Class CUPS-Set-Default>
AuthType Default
Require user @SYSTEM
Order deny,allow
</Limit>
# All printer operations require a printer operator to authenticate...
<Limit Pause-Printer Resume-Printer Enable-Printer Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After Cancel-Jobs CUPS-Accept-Jobs CUPS-Reject-Jobs>
AuthType Default
Require user @SYSTEM
Order deny,allow
</Limit>
# Only the owner or an administrator can cancel or authenticate a job...
<Limit Cancel-Job CUPS-Authenticate-Job>
AuthType Negotiate
Require user @OWNER @SYSTEM
Order deny,allow
</Limit>
<Limit All>
Order deny,allow
</Limit>
</Policy>
all:
hosts:
printypi:
ansible_host: printypi.local
ansible_user: <youruser>
ansible_python_interpreter: /usr/bin/python3
---
- name: Configure Raspberry Pi Print Server
hosts: printypi
become: yes
tasks:
# Packages
- name: Update apt cache
ansible.builtin.apt:
update_cache: yes
cache_valid_time: 3600
- name: Install packages
ansible.builtin.apt:
name: "{{item}}"
state: present
loop:
# Networking
- avahi-daemon
- samba
# Printing
# WARNING CUPS 2.4.10 DOES NOT ALLOW PRINTER SHARING
- cups=2.4.1
- printer-driver-brlaser
# - cups-driver-gutenprint
# Editing
- vim
# Start Services
- name: Start Avahi for Airprint
ansible.builtin.service:
name: avahi-daemon
state: started
enabled: yes
- name: Start Samba for Windows Share
ansible.builtin.service:
name: samba
state: started
enabled: yes
# Configure Services
- name: Ensure CUPS is disabled before configuration
ansible.builtin.service:
name: cups
state: stopped
enabled: no
- name: Add CUPS printing configuration to smb.conf
blockinfile:
path: /etc/samba/smb.conf
block: |
# CUPS printing.
[printers]
comment = All Printers
browseable = no
path = /var/spool/samba
printable = yes
guest ok = yes
read only = yes
create mask = 0700
[print$]
comment = Printer Drivers
path = /var/lib/samba/printers
browseable = yes
read only = no
guest ok = no
state: present
create: yes
backup: yes
insertafter: EOF
marker: "# {mark} CUPS printing configuration"
# Permissions
- name: Ensure user is in lpadmin group
ansible.builtin.user:
name: "{{ ansible_user }}"
groups: lpadmin
append: yes
# Print Server Settings
- name: Edit the CUPS config file
ansible.builtin.template:
src: templates/cupsd.conf
dest: /etc/cups/cupsd.conf
group: lpadmin
mode: "0644"
- name: Ensure CUPS is running
ansible.builtin.service:
name: cups
state: started
enabled: yes
- name: Enable remote CUPS access
command: cupsctl --remote-any
become: yes
# Restart Services
- name: Restart Samba
ansible.builtin.service:
name: smbd
state: restarted
enabled: yes
- name: Restart CUPS
ansible.builtin.service:
name: cups
state: restarted
enabled: yes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment